MDL-16780 Merging from MOODLE_19_STABLE

This commit is contained in:
nicolasconnault 2008-10-03 07:13:16 +00:00
parent 18a9406799
commit 1e074660da
14 changed files with 1970 additions and 76 deletions

View File

@ -10,7 +10,7 @@
*/
require_once('../config.php');
require_once('lib.php');
require_once($CFG->libdir.'/json/JSON.php');
require_once($CFG->libdir.'/pear/HTML/AJAX/JSON.php');
require_js(array('yui_yahoo', 'yui_dom', 'yui_utilities', 'yui_connection'));
require_js('group/clientlib.js');
@ -58,8 +58,7 @@ switch ($action) {
$roles[]=$shortroledata;
}
}
$json = new Services_JSON();
echo $json->encode($roles);
echo json_encode($roles);
die; // Client side JavaScript takes it from here.
case 'deletegroup':
@ -205,11 +204,11 @@ if ($sel_groupid) {
echo '<option value="'.$member->id.'">'.fullname($member, true).'</option>';
$atleastonemember = true;
}
echo '</optgroup>';
echo '</optgroup>';
}
}
}
}
if (!$atleastonemember) {
// Print an empty option to avoid the XHTML error of having an empty select element
echo '<option>&nbsp;</option>';

357
lib/pear/HTML/AJAX/Action.php Executable file
View File

@ -0,0 +1,357 @@
<?php
/**
* OO AJAX Implementation for PHP, contains HTML_AJAX_Action
*
* SVN Rev: $Id$
*
* @category HTML
* @package AJAX
* @author Elizabeth Smith <auroraeosrose@gmail.com>
* @copyright 2005-2008 Elizabeth Smith
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://htmlajax.org/HTML_AJAX/Using%20haSerializer
*/
/**
* Require the response class and json serializer
*/
require_once 'HTML/AJAX/Response.php';
require_once 'HTML/AJAX/Serializer/JSON.php';
/**
* Helper class to eliminate the need to write javascript functions to deal with data
*
* This class creates information that can be properly serialized and used by
* the haaction serializer which eliminates the need for php users to write
* javascript for dealing with the information returned by an ajax method -
* instead the javascript is basically created for them
*
* @category HTML
* @package AJAX
* @author Elizabeth Smith <auroraeosrose@gmail.com>
* @copyright 2005-2008 Elizabeth Smith
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://htmlajax.org/HTML_AJAX/Using%20haSerializer
*/
class HTML_AJAX_Action extends HTML_AJAX_Response
{
/**
* Content type for the HAA response
*
* goofy but unique content type to tell the javascript which deserializer to use
* overrides HTML_AJAX_Response
*
* @var string
* @access public
*/
var $contentType = 'application/html_ajax_action';
/**
* An array holding all the actions for the class
*
* these have numeric keys and each new action is added on the end, remember
* these are executed in the order added
*
* @var array
* @access private
*/
var $_actions = array();
/**
* Prepends data to the attribute identified by id
*
* The data will be added to the beginning of the attribute identified by the id
* sent, id must be unique
*
* $response->prependAttr('myid', 'class', 'red');
* $response->prependAttr('myid', array('class' => 'red', 'innerHTML' => 'this is an error'));
*
* @param string $id id for a specific item on the page <div id="myid"></div>
* @param string|array $attribute either an array of attribute/data pairs or a string attribute name
* @param mixed $data should be NULL if attribute is an array, otherwise data you wish to set the attribute to
*
* @return void
* @access public
*/
function prependAttr($id, $attribute, $data = null)
{
if (!is_null($data)) {
$attribute = array($attribute => $data);
}
$this->_actions[] = array(
'action' => 'prepend',
'id' => $id,
'attributes' => $attribute,
'data' => $data,
);
return;
}
/**
* Appends data to the attribute identified by id
*
* The data will be added to the end of the attribute identified by the id
* sent, id must be unique
*
* $response->appendAttr('myid', 'class', 'red');
* $response->appendAttr('myid', array('class' => 'red', 'innerHTML' => 'this is an error'));
*
* @param string $id id for a specific item on the page <div id="myid"></div>
* @param string|array $attribute either an array of attribute/data pairs or a string attribute name
* @param mixed $data should be NULL if attribute is an array, otherwise data you wish to set the attribute to
*
* @return void
* @access public
*/
function appendAttr($id, $attribute, $data = null)
{
if (!is_null($data)) {
$attribute = array($attribute => $data);
}
$this->_actions[] = array(
'action' => 'append',
'id' => $id,
'attributes' => $attribute,
);
return;
}
/**
* Assigns data to the attribute identified by id overwriting any previous values
*
* The data will be assigned to the attribute identified by the id
* sent, id must be unique
*
* $response->assignAttr('myid', 'class', 'red');
* $response->assignAttr('myid', array('class' => 'red', 'innerHTML' => 'this is an error'));
*
* @param string $id id for a specific item on the page <div id="myid"></div>
* @param string|array $attribute either an array of attribute/data pairs or a string attribute name
* @param mixed $data should be NULL if attribute is an array, otherwise data you wish to set the attribute to
*
* @return void
* @access public
*/
function assignAttr($id, $attribute, $data = null)
{
if (!is_null($data)) {
$attribute = array($attribute => $data);
}
$this->_actions[] = array(
'action' => 'assign',
'id' => $id,
'attributes' => $attribute,
);
return;
}
/**
* Deletes or assigns a value of an empty string to an attribute
*
* You may send either a single attribute or an array of attributes to clear
*
* $response->clearAttr('myid', 'class');
* $response->clearAttr('myid', array('class', 'innerHTML'));
*
* @param string $id id for a specific item on the page <div id="myid"></div>
* @param string|array $attribute either an array of attribute/data pairs or a string attribute name
*
* @return void
* @access public
*/
function clearAttr($id, $attribute)
{
if (!is_array($attribute)) {
$attribute = array($attribute);
}
$this->_actions[] = array(
'action' => 'clear',
'id' => $id,
'attributes' => $attribute,
);
return;
}
/**
* create a dom node via javascript
*
* higher level dom manipulation - creates a new node to insert into the dom
* You can control where the new node is inserted with two things, the insertion
* type and the id/ The type should be append, prepend, insertBefore, or insertAfter
*
* The id is a sibling node - like a div in the same div you want to add more to
* If you choose to append or prepend a node it will be placed at the beginning
* or end of the node with the id you send. If you choose insertBefore or
* InsertAfter it will be put right before or right after the node you specified.
* You can send an array of attributes to apply to the new node as well,
* so you don't have to create it and then assign Attributes.
*
* <code>
* $response->createNode('myid', 'div');
* $response->createNode('submit', 'input',
* array('id' => 'key',
* 'name' => 'key',
* 'type' => 'hidden',
* 'value' => $id),
* 'insertBefore');
* <code>
*
* @param string $id id for a specific item on the page <div id="myid"></div>
* @param string $tag html node to create
* @param array $attributes array of attribute -> data to fill the node with
* @param string $type append|prepend|insertBefore|insertAfter default is append
*
* @return void
* @access public
*/
function createNode($id, $tag, $attributes, $type = 'append')
{
$types = array('append', 'prepend', 'insertBefore', 'insertAfter');
if (!in_array($type, $types)) {
$type = 'append';
}
settype($attributes, 'array');
$this->_actions[] = array(
'action' => 'create',
'id' => $id,
'tag' => $tag,
'attributes' => $attributes,
'type' => $type,
);
return;
}
/**
* Replace a dom node via javascript
*
* higher level dom manipulation - replaces one node with another
* This can be used to replace a div with a form for inline editing
* use innerHtml attribute to change inside text
*
* $response->replaceNode('myid', 'div', array('innerHTML' => 'loading complete'));
* $response->replaceNode('mydiv', 'form', array('innerHTML' => $form));
*
* @param string $id id for a specific item on the page <div id="myid"></div>
* @param string $tag html node to create
* @param array $attributes array of attribute -> data to fill the node with
*
* @return void
* @access public
*/
function replaceNode($id, $tag, $attributes)
{
settype($attributes, 'array');
$this->_actions[] = array(
'action' => 'replace',
'id' => $id,
'tag' => $tag,
'attributes' => $attributes,
);
return;
}
/**
* Delete a dom node via javascript
*
* $response->removeNode('myid');
* $response->removeNode(array('mydiv', 'myform'));
*
* @param string $id id for a specific item on the page <div id="myid"></div>
*
* @return void
* @access public
*/
function removeNode($id)
{
$this->_actions[] = array(
'action' => 'remove',
'id' => $id,
);
return;
}
/**
* Send a string to a javascript eval
*
* This will send the data right to the eval javascript function, it will NOT
* allow you to dynamically add a javascript function for use later on because
* it is constrined by the eval function
*
* @param string $data string to pass to the alert javascript function
*
* @return void
* @access public
*/
function insertScript($data)
{
$this->_actions[] = array(
'action' => 'script',
'data' => $data,
);
return;
}
/**
* Send a string to a javascript alert
*
* This will send the data right to the alert javascript function
*
* @param string $data string to pass to the alert javascript function
*
* @return void
* @access public
*/
function insertAlert($data)
{
$this->_actions[] = array(
'action' => 'alert',
'data' => $data,
);
return;
}
/**
* Returns the serialized content of the response class
*
* we actually use the json serializer underneath, so we send the actions array
* to the json serializer and return the data
*
* @return string serialized response content
* @access public
*/
function getPayload()
{
$serializer = new HTML_AJAX_Serializer_JSON();
return $serializer->serialize($this->_actions);
}
/**
* Adds all the actions from one response object to another, feature request
* #6635 at pear.php.net
*
* @param object &$instance referenced HTML_AJAX_Action object
*
* @return array
* @access public
*/
function combineActions(&$instance)
{
$this->_actions = array_merge($this->_actions, $instance->retrieveActions());
}
/**
* to follow proper property access we need a way to retrieve the private
* actions array
*
* @return array
* @access public
*/
function retrieveActions()
{
return $this->_actions;
}
}
?>

144
lib/pear/HTML/AJAX/Debug.php Executable file
View File

@ -0,0 +1,144 @@
<?php
/**
* AJAX Debugging implementation
*
* SVN Rev: $Id$
*/
/**
* Newline to use
*/
define ("HTML_AJAX_NEWLINE", "\n");
// {{{ class HTML_AJAX_Debug
/**
* AJAX Debugging implementation
*
* @category HTML
* @package AJAX
* @author David Coallier <davidc@php.net>
* @copyright 2005 David Coallier
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
*/
class HTML_AJAX_Debug {
// {{{ properties
/**
* This is the error message.
*
* @access private
*/
var $errorMsg;
/**
* The line where the error occured.
*
* @access private
*/
var $errorLine;
/**
* The error code.
*
* @access private
*/
var $errorCode;
/**
* The file where the error occured.
*
* @access private
*/
var $errorFile;
/**
* Time the error occured
*
* @access private
*/
var $_timeOccured;
/**
* The whole error itself
*
* @access private
* @see errorMsg
* @see errorLine
* @see errorFile
* @see errorCode
*/
var $error;
/**
* The file to save the error to.
*
* @access private
* @default ajaxErrLog.xml
*/
var $file = 'ajaxErrLog.xml';
// }}}
// {{{ constructor
/**
* The constructor.
*
* @param string $errorMsg The error message.
* @param string $errLine The line where error occured.
* @param string $errCode The error Code.
* @param string $errFile The file where error occured.
*/
function HTML_AJAX_Debug($errMsg, $errLine, $errCode, $errFile)
{
$this->errorMsg = $errMsg;
$this->errorLine = $errLine;
$this->errorCode = $errCode;
$this->errorFile = $errFile;
$this->_timeOccured = date("Y-m-d H:i:s", time());
$this->xmlError();
}
// }}}
// {{{ xmlError
/**
* This functions formats the error to xml format then we can save it.
*
* @access protected
* @return $this->error the main error.
*/
function xmlError()
{
$error = " <when>{$this->_timeOccured}</when>" . HTML_AJAX_NEWLINE;
$error .= " <msg>{$this->errorMsg}</msg>" . HTML_AJAX_NEWLINE;
$error .= " <code>{$this->errorCode}</code>" . HTML_AJAX_NEWLINE;
$error .= " <line>{$this->errorLine}</line>" . HTML_AJAX_NEWLINE;
$error .= " <file>{$this->errorFile}</file>" . HTML_AJAX_NEWLINE . HTML_AJAX_NEWLINE;
return $this->error = $error;
}
// }}}
// {{{ sessionError
/**
* This function pushes the array $_SESSION['html_ajax_debug']['time'][]
* with the values inside of $this->error
*
* @access public
*/
function sessionError()
{
$_SESSION['html_ajax_debug']['time'][] = $this->error;
}
// }}}
// {{{ _saveError
/**
* This function saves the error to a file
* appending to this file.
*
* @access private.
*/
function _saveError()
{
if ($handle = fopen($this->file, 'a')) {
fwrite($handle, $this->error);
}
}
// }}}
}
// }}}
?>

186
lib/pear/HTML/AJAX/Helper.php Executable file
View File

@ -0,0 +1,186 @@
<?php
/**
* HTML/JavaScript Generation Helper
*
* SVN Rev: $Id$
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn <josh@bluga.net>
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
*/
/**
* HTML/JavaScript Generation Helper
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn <josh@bluga.net>
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://pear.php.net/package/HTML_AJAX
*/
class HTML_AJAX_Helper
{
/**
* URL where an HTML_AJAX_Server instance is serving up clients and taking ajax requests
*/
var $serverUrl = 'server.php';
/**
* JS libraries to include
*
* @var array
*/
var $jsLibraries = array('Util','Main','Request','HttpClient','Dispatcher','Behavior','Loading','JSON','iframe');
/**
* Remote class stubs to include
*/
var $stubs = array();
/**
* Combine jsLibraries into a single require and remove duplicates
*/
var $combineJsIncludes = false;
/**
* Include all needed libraries, stubs, and set defaultServer
*
* @return string
*/
function setupAJAX()
{
$libs = array(0=>array());
$combinedLibs = array();
$this->jsLibraries = array_unique($this->jsLibraries);
foreach($this->jsLibraries as $library) {
if (is_array($library)) {
$library = array_unique($library);
$combinedLibs = array_merge($combinedLibs,$library);
$libs[] = implode(',',$library);
}
else {
$libs[0][] = $library;
$combinedLibs[] = $library;
}
}
$libs[0] = implode(',',$libs[0]);
$sep = '?';
if (strstr($this->serverUrl,'?')) {
$sep = '&';
}
$ret = '';
if ($this->combineJsIncludes == true) {
$list = implode(',',$combinedLibs);
$ret .= "<script type='text/javascript' src='{$this->serverUrl}{$sep}client={$list}'></script>\n";
}
else {
foreach($libs as $list) {
$ret .= "<script type='text/javascript' src='{$this->serverUrl}{$sep}client={$list}'></script>\n";
}
}
if (count($this->stubs) > 0) {
$stubs = implode(',',$this->stubs);
$ret .= "<script type='text/javascript' src='{$this->serverUrl}{$sep}stub={$stubs}'></script>\n";
}
$ret .= $this->encloseInScript('HTML_AJAX.defaultServerUrl = '.$this->escape($this->serverUrl));
return $ret;
}
/**
* Create a custom Loading message
*
* @param string $body HTML body of the loading div
* @param string $class CSS class of the div
* @param string $style style tag of the loading div
*/
function loadingMessage($body, $class = 'HTML_AJAX_Loading',
$style = 'position: absolute; top: 0; right: 0; background-color: red; width: 80px; padding: 4px; display: none')
{
return "<div id='HTML_AJAX_LOADING' class='{$class}' style=\"{$style}\">{$body}</div>\n";
}
/**
* Update the contents of an element using ajax
*
* @param string $id id of the element to update
* @param string|array $update Either a url to update with or a array like array('class','method')
* @param string $type replace or append
* @param boolean $enclose
*/
function updateElement($id, $update, $type, $enclose = false) {
if (is_array($update)) {
$updateStr = "";
$comma = '';
foreach($update as $item) {
$updateStr .= $comma.$this->escape($item);
$comma = ',';
}
}
else {
$updateStr = $this->escape($update);
}
$ret = "HTML_AJAX.{$type}(".$this->escape($id).",{$updateStr});\n";
if ($enclose) {
$ret = $this->encloseInScript($ret);
}
return $ret;
}
/**
* Escape a string and add quotes allowing it to be a javascript paramater
*
* @param string $input
* @return string
* @todo do something here besides a quick hack
*/
function escape($input) {
return "'".addslashes($input)."'";
}
/**
* Enclose a string in a script block
*
* @param string $input
* @return string
*/
function encloseInScript($input) {
return '<script type="text/javascript">'.$input."</script>\n";
}
/**
* Generate a JSON String
*
* @param string $input
* @return string
*/
function jsonEncode($input) {
require_once 'HTML/AJAX/Serializer/JSON.php';
$s = new HTML_AJAX_Serializer_JSON();
return $s->serialize($input);
}
/**
* Check the request headers to see if this is an AJAX request
*
* @return boolean
*/
function isAJAX() {
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
return true;
}
return false;
}
}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

111
lib/json/JSON.php → lib/pear/HTML/AJAX/JSON.php Normal file → Executable file
View File

@ -1,5 +1,17 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* This is an embedded version of HTML_AJAX_JSON since it has yet to have
* a PEAR release it has been renamed to HTML_AJAX_JSON so no problems
* will be caused by an eventual release
* Feel free to report bugs against it to HTML_AJAX
*
* SVN Rev: $Id$
*/
/**
* Needed for compat functions
*/
require_once 'HTML/AJAX.php';
/**
* Converts to and from JSON format.
@ -46,48 +58,47 @@
* DAMAGE.
*
* @category
* @package Services_JSON
* @package HTML_AJAX_JSON
* @author Michal Migurski <mike-json@teczno.com>
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
* @copyright 2005 Michal Migurski
* @version CVS: $Id$
* @license http://www.opensource.org/licenses/bsd-license.php
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
*/
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
* Marker constant for HTML_AJAX_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_SLICE', 1);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
* Marker constant for HTML_AJAX_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_STR', 2);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
* Marker constant for HTML_AJAX_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_ARR', 3);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
* Marker constant for HTML_AJAX_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_OBJ', 4);
/**
* Marker constant for Services_JSON::decode(), used to flag stack state
* Marker constant for HTML_AJAX_JSON::decode(), used to flag stack state
*/
define('SERVICES_JSON_IN_CMT', 5);
/**
* Behavior switch for Services_JSON::decode()
* Behavior switch for HTML_AJAX_JSON::decode()
*/
define('SERVICES_JSON_LOOSE_TYPE', 16);
/**
* Behavior switch for Services_JSON::decode()
* Behavior switch for HTML_AJAX_JSON::decode()
*/
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
@ -97,8 +108,8 @@ define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
* Brief example of use:
*
* <code>
* // create a new instance of Services_JSON
* $json = new Services_JSON();
* // create a new instance of HTML_AJAX_JSON
* $json = new HTML_AJAX_JSON();
*
* // convert a complexe value to JSON notation, and send it to the browser
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
@ -112,7 +123,7 @@ define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
* $value = $json->decode($input);
* </code>
*/
class Services_JSON
class HTML_AJAX_JSON
{
/**
* constructs a new JSON instance
@ -130,7 +141,7 @@ class Services_JSON
* bubble up with an error, so all return values
* from encode() should be checked with isError()
*/
function Services_JSON($use = 0)
function HTML_AJAX_JSON($use = 0)
{
$this->use = $use;
}
@ -149,9 +160,8 @@ class Services_JSON
function utf162utf8($utf16)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
if(function_exists('mb_convert_encoding'))
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
@ -193,9 +203,8 @@ class Services_JSON
function utf82utf16($utf8)
{
// oh please oh please oh please oh please oh please
if(function_exists('mb_convert_encoding')) {
if(function_exists('mb_convert_encoding'))
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
}
switch(strlen($utf8)) {
case 1:
@ -227,7 +236,7 @@ class Services_JSON
* encodes an arbitrary variable into JSON format
*
* @param mixed $var any number, boolean, string, array, or object to be encoded.
* see argument 1 to Services_JSON() above for array-parsing behavior.
* see argument 1 to HTML_AJAX_JSON() above for array-parsing behavior.
* if var is a strng, note that encode() always expects it
* to be in ASCII or UTF-8 format!
*
@ -380,11 +389,9 @@ class Services_JSON
array_keys($var),
array_values($var));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
foreach($properties as $property)
if(HTML_AJAX_JSON::isError($property))
return $property;
}
}
return '{' . join(',', $properties) . '}';
}
@ -392,11 +399,9 @@ class Services_JSON
// treat it like a regular array
$elements = array_map(array($this, 'encode'), $var);
foreach($elements as $element) {
if(Services_JSON::isError($element)) {
foreach($elements as $element)
if(HTML_AJAX_JSON::isError($element))
return $element;
}
}
return '[' . join(',', $elements) . ']';
@ -407,18 +412,16 @@ class Services_JSON
array_keys($vars),
array_values($vars));
foreach($properties as $property) {
if(Services_JSON::isError($property)) {
foreach($properties as $property)
if(HTML_AJAX_JSON::isError($property))
return $property;
}
}
return '{' . join(',', $properties) . '}';
default:
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
? 'null'
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
: new HTML_AJAX_JSON_Error(gettype($var)." can not be encoded as JSON string");
}
}
@ -435,9 +438,8 @@ class Services_JSON
{
$encoded_value = $this->encode($value);
if(Services_JSON::isError($encoded_value)) {
if(HTML_AJAX_JSON::isError($encoded_value))
return $encoded_value;
}
return $this->encode(strval($name)) . ':' . $encoded_value;
}
@ -476,7 +478,7 @@ class Services_JSON
*
* @return mixed number, boolean, string, array, or object
* corresponding to given JSON input string.
* See argument 1 to Services_JSON() above for object-output behavior.
* See argument 1 to HTML_AJAX_JSON() above for object-output behavior.
* Note that decode() always returns strings
* in ASCII or UTF-8 format!
* @access public
@ -496,8 +498,6 @@ class Services_JSON
return null;
default:
$m = array();
if (is_numeric($str)) {
// Lookie-loo, it's a number
@ -665,8 +665,6 @@ class Services_JSON
// out the property name and set an
// element in an associative array,
// for now
$parts = array();
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
// "name":value pair
$key = $this->decode($parts[1]);
@ -698,10 +696,9 @@ class Services_JSON
} elseif (($chrs{$c} == $top['delim']) &&
($top['what'] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
(($chrs{$c - 1} != '\\') ||
($chrs{$c - 1} == '\\' && $chrs{$c - 2} == '\\'))) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
@ -765,7 +762,7 @@ class Services_JSON
*/
function isError($data, $code = null)
{
if (class_exists('pear')) {
if (HTML_AJAX_class_exists('pear', false)) {
return PEAR::isError($data, $code);
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
is_subclass_of($data, 'services_json_error'))) {
@ -776,11 +773,11 @@ class Services_JSON
}
}
if (class_exists('PEAR_Error')) {
if (HTML_AJAX_class_exists('pear_error', false)) {
class Services_JSON_Error extends PEAR_Error
class HTML_AJAX_JSON_Error extends PEAR_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
function HTML_AJAX_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
@ -792,9 +789,9 @@ if (class_exists('PEAR_Error')) {
/**
* @todo Ultimately, this class shall be descended from PEAR_Error
*/
class Services_JSON_Error
class HTML_AJAX_JSON_Error
{
function Services_JSON_Error($message = 'unknown error', $code = null,
function HTML_AJAX_JSON_Error($message = 'unknown error', $code = null,
$mode = null, $options = null, $userinfo = null)
{
@ -802,5 +799,21 @@ if (class_exists('PEAR_Error')) {
}
}
// Future-friendly json_encode
if( !function_exists('json_encode') ) {
function json_encode($data) {
$json = new HTML_AJAX_JSON();
return( $json->encode($data) );
}
}
// Future-friendly json_decode
if( !function_exists('json_decode') ) {
function json_decode($data) {
$json = new HTML_AJAX_JSON();
return( $json->decode($data) );
}
}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

78
lib/pear/HTML/AJAX/Response.php Executable file
View File

@ -0,0 +1,78 @@
<?php
/**
* OO AJAX Implementation for PHP, contains HTML_AJAX_Response
*
* SVN Rev: $Id$
*
* @category HTML
* @package AJAX
* @author Elizabeth Smith <auroraeosrose@gmail.com>
* @copyright 2005-2006 Elizabeth Smith
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
*/
/**
* Require the main AJAX library
*/
require_once 'HTML/AJAX.php';
/**
* Simple base class for a response object to use as an ajax callback
*
* This is the base response class, more interesting response classes can be
* built off of this, simply give it a unique content type and override the
* getPayload method or fill the payload property with your extended classes's
* serialized content
*
* @version $Id$
*/
class HTML_AJAX_Response
{
/**
* The base response class uses plain text so use that content type
*
* @var string
* @access public
*/
var $contentType = 'text/plain';
/**
* Assign a string to this variable to use the bare response class
*
* @var string
* @access public
*/
var $payload = '';
/**
* Returns the appropriate content type
*
* This normally simply returns the contentType property but can be overridden
* by an extending class if the content-type is variable
*
* @return string appropriate content type
* @access public
*/
function getContentType()
{
return $this->contentType;
}
/**
* Returns the serialized content of the response class
*
* You can either fill the payload elsewhere in an extending class and leave
* this method alone, or you can override it if you have a different type
* of payload that needs special treatment
*
* @return string serialized response content
* @access public
*/
function getPayload()
{
return $this->payload;
}
}
?>

View File

@ -0,0 +1,20 @@
<?php
require_once 'HTML/AJAX/Serializer/JSON.php';
// $Id
/**
* Error Serializer, for now just uses JSON
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn <josh@bluga.net>
* @copyright 2005 Joshua Eichorn
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: 0.5.6
* @link http://pear.php.net/package/HTML_AJAX
*/
class HTML_AJAX_Serializer_Error extends HTML_AJAX_Serializer_JSON
{
}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

View File

@ -0,0 +1,96 @@
<?php
require_once 'HTML/AJAX/JSON.php';
// $Id$
/**
* JSON Serializer
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn <josh@bluga.net>
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://pear.php.net/package/PackageName
*/
// {{{ class HTMLA_AJAX_Serialize_JSON
class HTML_AJAX_Serializer_JSON
{
// {{{ variables-properties
/**
* JSON instance
* @var HTML_AJAX_JSON
* @access private
*/
var $_json;
/**
* use json php extension http://www.aurore.net/projects/php-json/
* @access private
*/
var $_jsonext;
/**
* use loose typing to decode js objects into php associative arrays
* @access public
*/
var $loose_type;
// }}}
// {{{ constructor
function HTML_AJAX_Serializer_JSON($use_loose_type = true)
{
$this->loose_type = (bool) $use_loose_type;
$this->_jsonext = $this->_detect();
if(!$this->_jsonext) {
$use_loose_type = ($this->loose_type) ? SERVICES_JSON_LOOSE_TYPE : 0;
$this->_json = new HTML_AJAX_JSON($use_loose_type);
}
}
// }}}
// {{{ serialize
/**
* This function serializes and input passed to it.
*
* @access public
* @param string $input The input to serialize.
* @return string $input The serialized input.
*/
function serialize($input)
{
if($this->_jsonext) {
return json_encode($input);
} else {
return $this->_json->encode($input);
}
}
// }}}
// {{{ unserialize
/**
* this function unserializes the input passed to it.
*
* @access public
* @param string $input The input to unserialize
* @return string $input The unserialized input.
*/
function unserialize($input)
{
if($this->_jsonext) {
return json_decode($input, $this->loose_type);
} else {
return $this->_json->decode($input);
}
}
// }}}
// {{{ _detect
/**
* detects the loaded extension
*/
function _detect()
{
return extension_loaded('json');
}
// }}}
}
// }}}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

View File

@ -0,0 +1,28 @@
<?php
// $Id$
/**
* Null Serializer
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn <josh@bluga.net>
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://pear.php.net/package/PackageName
*/
class HTML_AJAX_Serializer_Null
{
function serialize($input)
{
return $input;
}
function unserialize($input)
{
return $input;
}
}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

View File

@ -0,0 +1,88 @@
<?php
// $Id$
/**
* PHP Serializer
*
* @category HTML
* @package AJAX
* @author Arpad Ray <arpad@php.net>
* @copyright 2005 Arpad Ray
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://pear.php.net/package/HTML_AJAX
*/
class HTML_AJAX_Serializer_PHP
{
function serialize($input)
{
return serialize($input);
}
/**
* Unserializes the given string
*
* Triggers an error if a class is found which is not
* in the provided array of allowed class names.
*
* @param string $input
* the serialized string to process
* @param array $allowedClasses
* an array of class names to check objects against
* before instantion
* @return mixed
* the unserialized variable on success, or false on
* failure. If this method fails it will also trigger
* a warning.
*/
function unserialize($input, $allowedClasses)
{
if (version_compare(PHP_VERSION, '4.3.10', '<')
|| (substr(PHP_VERSION, 0, 1) == '5' && version_compare(PHP_VERSION, '5.0.3', '<'))) {
trigger_error('Unsafe version of PHP for native unserialization');
return false;
}
$classes = $this->_getSerializedClassNames($input);
if ($classes === false) {
trigger_error('Invalidly serialized string');
return false;
}
$diff = array_diff($classes, $allowedClasses);
if (!empty($diff)) {
trigger_error('Class(es) not allowed to be serialized');
return false;
}
return unserialize($input);
}
/**
* Extract class names from serialized string
*
* Adapted from code by Harry Fuecks
*
* @param string $string
* the serialized string to process
* @return mixed
* an array of class names found, or false if the input
* is invalidly formed
*/
function _getSerializedClassNames($string) {
// Strip any string representations (which might contain object syntax)
while (($pos = strpos($string, 's:')) !== false) {
$pos2 = strpos($string, ':', $pos + 2);
if ($pos2 === false) {
// invalidly serialized string
return false;
}
$end = $pos + 2 + substr($string, $pos + 2, $pos2) + 1;
$string = substr($string, 0, $pos) . substr($string, $end);
}
// Pull out the class names
preg_match_all('/O:[0-9]+:"(.*)"/U', $string, $matches);
// Make sure names are unique (same object serialized twice)
return array_unique($matches[1]);
}
}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

View File

@ -0,0 +1,67 @@
<?php
// $Id$
// {{{ http_build_query
/**
* Replacement for http_build_query()
*
* @link http://php.net/function.http-build-query
* @author vlad_mustafin@ukr.net
* @author Arpad Ray <arpad@php.net>
*/
if (!function_exists('http_build_query')) {
function http_build_query($formdata, $numeric_prefix = null, $key = null)
{
$res = array();
foreach ((array)$formdata as $k => $v) {
if (is_resource($v)) {
return null;
}
$tmp_key = urlencode(is_int($k) ? $numeric_prefix . $k : $k);
if (!is_null($key)) {
$tmp_key = $key . '[' . $tmp_key . ']';
}
$res[] = (is_scalar($v))
? $tmp_key . '=' . urlencode($v)
: http_build_query($v, null , $tmp_key);
}
$separator = ini_get('arg_separator.output');
if (strlen($separator) == 0) {
$separator = '&';
}
return implode($separator, $res);
}
}
// }}}
// {{{ class HTML_AJAX_Serialize_Urlencoded
/**
* URL Encoding Serializer
*
* @category HTML
* @package AJAX
* @author Arpad Ray <arpad@php.net>
* @author David Coallier <davidc@php.net>
* @copyright 2005 Arpad Ray
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://pear.php.net/package/HTML_AJAX
*/
class HTML_AJAX_Serializer_Urlencoded
{
// {{{ serialize
function serialize($input)
{
return http_build_query(array('_HTML_AJAX' => $input));
}
// }}}
// {{{ unserialize
function unserialize($input)
{
parse_str($input, $ret);
return (isset($ret['_HTML_AJAX']) ? $ret['_HTML_AJAX'] : $ret);
}
// }}}
}
// }}}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

View File

@ -0,0 +1,88 @@
<?php
// $Id$
/**
* XML Serializer - does NOT need a js serializer, use responseXML property in XmlHttpRequest
*
* @category HTML
* @package AJAX
* @author Elizabeth Smith <auroraeosrose@gmail.com>
* @copyright 2005-2006 Elizabeth Smith
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: 0.5.6
* @link http://pear.php.net/package/PackageName
*/
class HTML_AJAX_Serializer_XML
{
/**
* Serializes a domdocument into an xml string
*
* Uses dom or domxml to dump a string from a DomDocument instance
* remember dom is always the default and this will die horribly without
* a domdocument instance
*
* @access public
* @param object $input instanceof DomDocument
* @return string xml string of DomDocument
*/
function serialize($input)
{
if(empty($input))
{
return $input;
}
// we check for the dom extension
elseif (extension_loaded('Dom'))
{
return $input->saveXml();
}
// then will check for domxml
elseif (extension_loaded('Domxml'))
{
return $input->dump_mem();
}
// will throw an error
else {
$error = new HTML_AJAX_Serializer_Error();
$this->serializerNewType = 'Error';
return $error->serialize(array('errStr'=>"Missing PHP Dom extension direct XML won't work"));
}
}
/**
* Unserializes the xml string sent from the document
*
* Uses dom or domxml to pump a string into a DomDocument instance
* remember dom is always the default and this will die horribly without
* one or the other, and will throw warnings if you have bad xml
*
* @access public
* @param string $input The input to serialize.
* @return object instanceofDomDocument
*/
function unserialize($input)
{
if(empty($input))
{
return $input;
}
// we check for the dom extension
elseif (extension_loaded('Dom'))
{
$doc = new DOMDocument();
$doc->loadXML($input);
return $doc;
}
// then we check for the domxml extensions
elseif (extension_loaded('Domxml'))
{
return domxml_open_mem($input);
}
// we give up and just return the xml directly
else
{
return $input;
}
}
}
?>

725
lib/pear/HTML/AJAX/Server.php Executable file
View File

@ -0,0 +1,725 @@
<?php
/**
* OO AJAX Implementation for PHP
*
* SVN Rev: $Id$
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn <josh@bluga.net>
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: @package_version@
*/
/**
* Require the main AJAX library
*/
require_once 'HTML/AJAX.php';
/**
* Class for creating an external AJAX server
*
* Can be used in 2 different modes, registerClass mode where you create an instance of the server and add the classes that will be registered
* and then run handle request
*
* Or you can extend it and add init{className} methods for each class you want to export
*
* Client js generation is exposed through 2 _GET params client and stub
* Setting the _GET param client to `all` will give you all the js classes needed
* Setting the _GET param stub to `all` will give you stubs of all registered classes, you can also set it too just 1 class
*
* @category HTML
* @package AJAX
* @author Joshua Eichorn <josh@bluga.net>
* @copyright 2005 Joshua Eichorn
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version Release: @package_version@
* @link http://pear.php.net/package/PackageName
*/
class HTML_AJAX_Server
{
/**
* Client options array if set to true the code looks at _GET
* @var bool|array
*/
var $options = true;
/**
* HTML_AJAX instance
* @var HTML_AJAX
*/
var $ajax;
/**
* Set to true if your extending the server to add init{className methods}
* @var boolean
* @access public
*/
var $initMethods = false;
/**
* Location on filesystem of client javascript library
* @var false|string if false the default pear data dir location is used
*/
var $clientJsLocation = false;
/**
* An array of options that tell the server howto Cache output
*
* The rules are functions that make etag hash used to see if the client needs to download updated content
* If you extend this class you can make your own rule function the naming convention is _cacheRule{RuleName}
*
* <code>
* array(
* 'httpCacheClient' => true, // send 304 headers for responses to ?client=* requests
* 'ClientCacheRule' => 'File', // create a hash from file names and modified times, options: file|content
* 'ClientCacheExpects'=> 'files', // what type of content to send to the hash function, options: files|classes|content
* 'httpCacheStub' => true, // send 304 headers for responses to ?stub=* requests
* 'StubCacheRule' => 'Api', // create a hash from the exposed api, options: api|content
* 'StubCacheExpects'=> 'classes', // what type of content to send to the hash function, options: files|classes|content
* )
* </code>
*
* @var array
* @access public
*/
var $cacheOptions = array(
'httpCacheClient' => true,
'ClientCacheRule' => 'file',
'ClientCacheExpects' => 'files',
'httpCacheStub' => true,
'StubCacheRule' => 'api',
'StubCacheExpects' => 'classes',
);
/**
* Compression Options
*
* <code>
* array(
* 'enabled' => false, // enable compression
* 'type' => 'gzip' // the type of compression to do, options: gzip
* )
* </code>
*
* @var array
* @access public
*/
var $compression = array(
'enabled' => false,
'type' => 'gzip'
);
/**
* Javascript library names and there path
*
* the return of $this->clientJsLocation(), is prepended before running readfile on them
*
* @access public
* @var array
*/
var $javascriptLibraries = array(
'all' => 'HTML_AJAX.js',
'html_ajax' => 'HTML_AJAX.js',
'html_ajax_lite'=> 'HTML_AJAX_lite.js',
'json' => 'serializer/JSON.js',
'request' => 'Request.js',
'main' => array('Compat.js','Main.js','clientPool.js'),
'httpclient' => 'HttpClient.js',
'dispatcher' => 'Dispatcher.js',
'util' => 'util.js',
'loading' => 'Loading.js',
'phpserializer' => 'serializer/phpSerializer.js',
'urlserializer' => 'serializer/UrlSerializer.js',
'haserializer' => 'serializer/haSerializer.js',
'clientpool' => 'clientPool.js',
'iframe' => 'IframeXHR.js',
'alias' => 'Alias.js',
'queues' => 'Queue.js',
'behavior' => array('behavior/behavior.js','behavior/cssQuery-p.js'),
// rules to help you use a minimal library set
'standard' => array('Compat.js','clientPool.js','util.js','Main.js','HttpClient.js','Request.js','serializer/JSON.js',
'Loading.js','serializer/UrlSerializer.js','Alias.js','behavior/behavior.js','behavior/cssQuery-p.js'),
'jsonrpc' => array('Compat.js','util.js','Main.js','clientPool.js','HttpClient.js','Request.js','serializer/JSON.js'),
'proxyobjects' => array('Compat.js','util.js','Main.js','clientPool.js','Request.js','serializer/JSON.js','Dispatcher.js'),
// BC rules
'priorityqueue' => 'Queue.js',
'orderedqueue' => 'Queue.js',
);
/**
* Custom paths to use for javascript libraries, if not set {@link clientJsLocation} is used to find the system path
*
* @access public
* @var array
* @see registerJsLibrary
*/
var $javascriptLibraryPaths = array();
/**
* Array of className => init methods to call, generated from constructor from initClassName methods
*
* @access protected
*/
var $_initLookup = array();
/**
* Constructor creates the HTML_AJAX instance
*
* @param string $serverUrl (Optional) the url the client should be making a request too
*/
function HTML_AJAX_Server($serverUrl = false)
{
$this->ajax = new HTML_AJAX();
// parameters for HTML::AJAX
$parameters = array('stub', 'client');
// keep in the query string all the parameters that don't belong to AJAX
// we remove all string like "parameter=something&". Final '&' can also
// be '&amp;' (to be sure) and is optional. '=something' is optional too.
$querystring = '';
if (isset($_SERVER['QUERY_STRING'])) {
$querystring = preg_replace('/(' . join('|', $parameters) . ')(?:=[^&]*(?:&(?:amp;)?|$))?/', '', $this->ajax->_getServer('QUERY_STRING'));
}
// call the server with this query string
if ($serverUrl === false) {
$serverUrl = htmlentities($this->ajax->_getServer('PHP_SELF'));
}
if (substr($serverUrl,-1) != '?') {
$serverUrl .= '?';
}
$this->ajax->serverUrl = $serverUrl . $querystring;
$methods = get_class_methods($this);
foreach($methods as $method) {
if (preg_match('/^init([a-zA-Z0-9_]+)$/',$method,$match)) {
$this->_initLookup[strtolower($match[1])] = $method;
}
}
}
/**
* Handle a client request, either generating a client or having HTML_AJAX handle the request
*
* @return boolean true if request was handled, false otherwise
*/
function handleRequest()
{
if ($this->options == true) {
$this->_loadOptions();
}
//basically a hook for iframe but allows processing of data earlier
$this->ajax->populatePayload();
if (!isset($_GET['c']) && (count($this->options['client']) > 0 || count($this->options['stub']) > 0) ) {
$this->generateClient();
return true;
} else {
if (!empty($_GET['c'])) {
$this->_init($this->_cleanIdentifier($this->ajax->_getVar('c')));
}
return $this->ajax->handleRequest();
}
}
/**
* Register method passthrough to HTML_AJAX
*
* @see HTML_AJAX::registerClass for docs
*/
function registerClass(&$instance, $exportedName = false, $exportedMethods = false)
{
$this->ajax->registerClass($instance,$exportedName,$exportedMethods);
}
/**
* Change default serialization - important for exporting classes
*
* I wanted this for the xml serializer :)
*/
function setSerializer($type)
{
$this->ajax->serializer = $type;
$this->ajax->unserializer = $type;
}
/**
* Register a new js client library
*
* @param string $libraryName name you'll reference the library as
* @param string|array $fileName actual filename with no path, for example customLib.js
* @param string|false $path Optional, if not set the result from jsClientLocation is used
*/
function registerJSLibrary($libraryName,$fileName,$path = false) {
$libraryName = strtolower($libraryName);
$this->javascriptLibraries[$libraryName] = $fileName;
if ($path !== false) {
$this->javascriptLibraryPaths[$libraryName] = $path;
}
}
/**
* Register init methods from an external class
*
* @param object $instance an external class with initClassName methods
*/
function registerInitObject(&$instance) {
$instance->server =& $this;
$methods = get_class_methods($instance);
foreach($methods as $method) {
if (preg_match('/^init([a-zA-Z0-9_]+)$/',$method,$match)) {
$this->_initLookup[strtolower($match[1])] = array(&$instance,$method);
}
}
}
/**
* Register a callback to be exported to the client
*
* This function uses the PHP callback pseudo-type
*
*/
function registerPhpCallback($callback)
{
if (!is_callable($callback)) {
// invalid callback
return false;
}
if (is_array($callback) && is_object($callback[0])) {
// object method
$this->registerClass($callback[0], strtolower(get_class($callback[0])), array($callback[1]));
return true;
}
// static callback
$this->ajax->registerPhpCallback($callback);
}
/**
* Generate client js
*
* @todo this is going to need tests to cover all the options
*/
function generateClient()
{
$headers = array();
ob_start();
// create a list list of js files were going to need to output
// index is the full file and so is the value, this keeps duplicates out of $fileList
$fileList = array();
if(!is_array($this->options['client'])) {
$this->options['client'] = array();
}
foreach($this->options['client'] as $library) {
if (isset($this->javascriptLibraries[$library])) {
$lib = (array)$this->javascriptLibraries[$library];
foreach($lib as $file) {
if (isset($this->javascriptLibraryPaths[$library])) {
$fileList[$this->javascriptLibraryPaths[$library].$file] = $this->javascriptLibraryPaths[$library].$file;
}
else {
$fileList[$this->clientJsLocation().$file] = $this->clientJsLocation().$file;
}
}
}
}
// do needed class init if were running an init server
if(!is_array($this->options['stub'])) {
$this->options['stub'] = array();
}
$classList = $this->options['stub'];
if ($this->initMethods) {
if (isset($this->options['stub'][0]) && $this->options['stub'][0] === 'all') {
$this->_initAll();
} else {
foreach($this->options['stub'] as $stub) {
$this->_init($stub);
}
}
}
if (isset($this->options['stub'][0]) && $this->options['stub'][0] === 'all') {
$classList = array_keys($this->ajax->_exportedInstances);
}
// if were doing stub and client we have to wait for both ETags before we can compare with the client
$combinedOutput = false;
if ($classList != false && count($classList) > 0 && count($fileList) > 0) {
$combinedOutput = true;
}
if ($classList != false && count($classList) > 0) {
// were setup enough to make a stubETag if the input it wants is a class list
if ($this->cacheOptions['httpCacheStub'] &&
$this->cacheOptions['StubCacheExpects'] == 'classes')
{
$stubETag = $this->_callCacheRule('Stub',$classList);
}
// if were not in combined output compare etags, if method returns true were done
if (!$combinedOutput && isset($stubETag)) {
if ($this->_compareEtags($stubETag)) {
ob_end_clean();
return;
}
}
// output the stubs for all the classes in our list
foreach($classList as $class) {
echo $this->ajax->generateClassStub($class);
}
// if were cacheing and the rule expects content make a tag and check it, if the check is true were done
if ($this->cacheOptions['httpCacheStub'] &&
$this->cacheOptions['StubCacheExpects'] == 'content')
{
$stubETag = $this->_callCacheRule('Stub',ob_get_contents());
}
// if were not in combined output compare etags, if method returns true were done
if (!$combinedOutput && isset($stubETag)) {
if ($this->_compareEtags($stubETag)) {
ob_end_clean();
return;
}
}
}
if (count($fileList) > 0) {
// if were caching and need a file list build our jsETag
if ($this->cacheOptions['httpCacheClient'] &&
$this->cacheOptions['ClientCacheExpects'] === 'files')
{
$jsETag = $this->_callCacheRule('Client',$fileList);
}
// if were not in combined output compare etags, if method returns true were done
if (!$combinedOutput && isset($jsETag)) {
if ($this->_compareEtags($jsETag)) {
ob_end_clean();
return;
}
}
// output the needed client js files
foreach($fileList as $file) {
$this->_readFile($file);
}
// if were caching and need content build the etag
if ($this->cacheOptions['httpCacheClient'] &&
$this->cacheOptions['ClientCacheExpects'] === 'content')
{
$jsETag = $this->_callCacheRule('Client',ob_get_contents());
}
// if were not in combined output compare etags, if method returns true were done
if (!$combinedOutput && isset($jsETag)) {
if ($this->_compareEtags($jsETag)) {
ob_end_clean();
return;
}
}
// were in combined output, merge the 2 ETags and compare
else if (isset($jsETag) && isset($stubETag)) {
if ($this->_compareEtags(md5($stubETag.$jsETag))) {
ob_end_clean();
return;
}
}
}
// were outputting content, add our length header and send the output
$length = ob_get_length();
$output = ob_get_contents();
ob_end_clean();
if ($this->ajax->packJavaScript) {
$output = $this->ajax->packJavaScript($output);
$length = strlen($output);
}
if ($this->compression['enabled'] && $this->compression['type'] == 'gzip' && strpos($_SERVER["HTTP_ACCEPT_ENCODING"], "gzip") !== false) {
$output = gzencode($output,9);
$length = strlen($output);
$headers['Content-Encoding'] = 'gzip';
}
if ($length > 0 && $this->ajax->_sendContentLength()) {
$headers['Content-Length'] = $length;
}
$headers['Content-Type'] = 'text/javascript; charset=utf-8';
$this->ajax->_sendHeaders($headers);
echo($output);
}
/**
* Run readfile on input with basic error checking
*
* @param string $file file to read
* @access private
* @todo is addslashes enough encoding for js?
*/
function _readFile($file)
{
if (file_exists($file)) {
readfile($file);
} else {
$file = addslashes($file);
echo "alert('Unable to find javascript file: $file');";
}
}
/**
* Get the location of the client js
* To override the default pear datadir location set $this->clientJsLocation
*
* @return string
*/
function clientJsLocation()
{
if (!$this->clientJsLocation) {
$path = '@data-dir@'.DIRECTORY_SEPARATOR.'HTML_AJAX'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR;
if(strpos($path, '@'.'data-dir@') === 0)
{
$path = realpath(dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'js').DIRECTORY_SEPARATOR;
}
return $path;
} else {
return $this->clientJsLocation;
}
}
/**
* Set the location of the client js
*
* @access public
* @param string $location Location
* @return void
*/
function setClientJsLocation($location)
{
$this->clientJsLocation = $location;
}
/**
* Set the path to a Javascript libraries
*
* @access public
* @param string $library Library name
* @param string $path Path
* @return void
*/
function setJavascriptLibraryPath($library, $path)
{
$this->javascriptLibraryPaths[$library] = $path;
}
/**
* Set the path to more than one Javascript libraries at once
*
* @access public
* @param array $paths Paths
* @return void
*/
function setJavascriptLibraryPaths($paths)
{
if (is_array($paths)) {
$this->javascriptLibraryPaths = array_merge($this->javascriptLibraryPaths, $paths);
}
}
/**
* Load options from _GET
*
* @access private
*/
function _loadOptions()
{
$this->options = array('client'=>array(),'stub'=>array());
if (isset($_GET['client'])) {
$clients = explode(',',$this->ajax->_getVar('client'));
$client = array();
foreach($clients as $val) {
$cleanVal = $this->_cleanIdentifier($val);
if (!empty($cleanVal)) {
$client[] = strtolower($cleanVal);
}
}
if (count($client) > 0) {
$this->options['client'] = $client;
}
}
if (isset($_GET['stub'])) {
$stubs = explode(',',$this->ajax->_getVar('stub'));
$stub = array();
foreach($stubs as $val) {
$cleanVal = $this->_cleanIdentifier($val);
if (!empty($cleanVal)) {
$stub[] = strtolower($cleanVal);
}
}
if (count($stub) > 0) {
$this->options['stub'] = $stub;
}
}
}
/**
* Clean an identifier like a class name making it safe to use
*
* @param string $input
* @return string
* @access private
*/
function _cleanIdentifier($input) {
return trim(preg_replace('/[^A-Za-z_0-9]/','',$input));
}
/**
* Run every init method on the class
*
* @access private
*/
function _initAll()
{
if ($this->initMethods) {
foreach($this->_initLookup as $class => $method) {
$this->_init($class);
}
}
}
/**
* Init one class
*
* @param string $className
* @access private
*/
function _init($className)
{
$className = strtolower($className);
if ($this->initMethods) {
if (isset($this->_initLookup[$className])) {
$method =& $this->_initLookup[$className];
if (is_array($method)) {
call_user_func($method);
}
else {
$this->$method();
}
} else {
trigger_error("Could find an init method for class: " . $className);
}
}
}
/**
* Generate a hash from a list of files
*
* @param array $files file list
* @return string a hash that can be used as an etag
* @access private
*/
function _cacheRuleFile($files) {
$signature = "";
foreach($files as $file) {
if (file_exists($file)) {
$signature .= $file.filemtime($file);
}
}
return md5($signature);
}
/**
* Generate a hash from the api of registered classes
*
* @param array $classes class list
* @return string a hash that can be used as an etag
* @access private
*/
function _cacheRuleApi($classes) {
$signature = "";
foreach($classes as $class) {
if (isset($this->ajax->_exportedInstances[$class])) {
$signature .= $class.implode(',',$this->ajax->_exportedInstances[$class]['exportedMethods']);
}
}
return md5($signature);
}
/**
* Generate a hash from the raw content
*
* @param array $content
* @return string a hash that can be used as an etag
* @access private
*/
function _cacheRuleContent($content) {
return md5($content);
}
/**
* Send cache control headers
* @access private
*/
function _sendCacheHeaders($etag,$notModified) {
header('Cache-Control: must-revalidate');
header('ETag: '.$etag);
if ($notModified) {
header('HTTP/1.0 304 Not Modified',false,304);
}
}
/**
* Compare eTags
*
* @param string $serverETag server eTag
* @return boolean
* @access private
*/
function _compareEtags($serverETag) {
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
if (strcmp($this->ajax->_getServer('HTTP_IF_NONE_MATCH'),$serverETag) == 0) {
$this->_sendCacheHeaders($serverETag,true);
return true;
}
}
$this->_sendCacheHeaders($serverETag,false);
return false;
}
/**
* Call a cache rule and return its retusn
*
* @param string $rule Stub|Client
* @param mixed $payload
* @return boolean
* @access private
* @todo decide if error checking is needed
*/
function _callCacheRule($rule,$payload) {
$method = '_cacheRule'.$this->cacheOptions[$rule.'CacheRule'];
return call_user_func(array(&$this,$method),$payload);
}
}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>

View File

@ -2,13 +2,13 @@ PEAR Libraries
====================================================================
This directory (lib/pear) contains unmodified copies of some
This directory (lib/pear) contains unmodified copies of some
libraries from the standard PEAR distribution (http://pear.php.net).
We include these in Moodle solely for the convenience of sites that
We include these in Moodle solely for the convenience of sites that
may not have PEAR installed.
If this directory is DELETED from Moodle then Moodle will search
If this directory is DELETED from Moodle then Moodle will search
the standard PHP directories and use the PEAR libraries there instead.
@ -46,7 +46,7 @@ In detail, the libraries added here are:
- http://pear.php.net/package/HTML
- PEAR main class:
- Current version: 1.4.5
- by Stig Bakken, Thomas V.V.Cox, Pierre-Alain Joye,
- by Stig Bakken, Thomas V.V.Cox, Pierre-Alain Joye,
Greg Beaver and Martin Jansen
- License: PHP
- http://pear.php.net/package/PEAR
@ -60,23 +60,28 @@ In detail, the libraries added here are:
- by Hartmut Holzgraefe and Christian Stocker
- License: BSD
- http://pear.php.net/package/HTTP_WebDAV_Server
- PEAR HTML_AJAX:
- Current version: 0.5.6
- by Elizabeth Smith, Arpad Ray, Joshua Eichorn, David Coallier and Laurent Yaish
- License: LGPL
- http://pear.php.net/package/HTML_AJAX/
----------------------------------------------------------------
A NOTE TO DEVELOPERS
================================================================
We must not use these classes directly ever. Instead we must build
We must not use these classes directly ever. Instead we must build
and use wrapper classes to isolate Moodle code from internal PEAR
implementations, allowing us to migrate if needed to other
libraries in the future. For an example of wrapped classes,
see the excel.class.lib file, that includes code to build
implementations, allowing us to migrate if needed to other
libraries in the future. For an example of wrapped classes,
see the excel.class.lib file, that includes code to build
Excel files using the cool library inside PEAR, but using
the old calls used before Moodle 1.6 to maintain compatibility.
Please, don't forget it! Always use wrapper classes/functions!
Ciao,
Ciao,
Eloy Lafuente, 2005-12-17 :-)
@ -88,28 +93,28 @@ A NOTE ON THE PHP LICENSE AND MOODLE
Everything in Moodle in pure GPL. This pear directory is the only
part of the distribution that is not.
There is some question about how PHP-licensed software can be
There is some question about how PHP-licensed software can be
included within a GPL-licensed distribution like Moodle, specifically
the clause that annoyingly says no derivative of the software can
include the name PHP.
the clause that annoyingly says no derivative of the software can
include the name PHP.
We don't intend to rename Moodle to anything of the sort, obviously,
but to help people downstream who could possibly want to do so,
we have sought special permission from the authors of these classes
to allow us an exemption on this point so that we don't need to
We don't intend to rename Moodle to anything of the sort, obviously,
but to help people downstream who could possibly want to do so,
we have sought special permission from the authors of these classes
to allow us an exemption on this point so that we don't need to
change our nice clean GPL license.
Several authors have given Moodle explicit permission to distribute
their PHP-licensed PEAR classes in the Moodle distribution, allowing
Several authors have given Moodle explicit permission to distribute
their PHP-licensed PEAR classes in the Moodle distribution, allowing
anybody using these classes ONLY as part of the Moodle distribution
exemption from clauses of the PHP license that could cause
conflict with the main GNU Public License that Moodle uses.
We are still waiting to hear back from the others but we assume
We are still waiting to hear back from the others but we assume
for now that it will likewise be OK.
If you are at all worried about this situation you can simply delete
this directory from Moodle and it will use your installed PEAR
If you are at all worried about this situation you can simply delete
this directory from Moodle and it will use your installed PEAR
libraries instead.
Cheers,