Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

merge in changes from SVN, should be everything up to r616

git-svn-id: http://svn.php.net/repository/pear/packages/HTML_AJAX/trunk@259271 c90b9560-bf6c-de11-be94-00142212c4b1
  • Loading branch information...
commit ad5d83fce061f0e482e4d8ab0e22bbe466f2a0a2 1 parent b446984
Joshua Eichorn authored
527 AJAX.php
View
@@ -1,5 +1,18 @@
<?php
-// $Id$
+/**
+ * OO AJAX Implementation for PHP
+ *
+ * @category HTML
+ * @package AJAX
+ * @author Joshua Eichorn <josh@bluga.net>
+ * @author Arpad Ray <arpad@php.net>
+ * @author David Coallier <davidc@php.net>
+ * @author Elizabeth Smith <auroraeosrose@gmail.com>
+ * @copyright 2005-2008 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/HTML_AJAX
+ */
/**
* This is a quick hack, loading serializers as needed doesn't work in php5
@@ -14,24 +27,28 @@
/**
* OO AJAX Implementation for PHP
*
- * @category HTML
- * @package AJAX
- * @author Joshua Eichorn <josh@bluga.net>
- * @author Arpad Ray <arpad@php.net>
- * @author David Coallier <davidc@php.net>
- * @author Elizabeth Smith <auroraeosrose@gmail.com>
- * @copyright 2005 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith
- * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
- * @version Release: @package_version@
- * @link http://pear.php.net/package/HTML_AJAX
+ * @category HTML
+ * @package AJAX
+ * @author Joshua Eichorn <josh@bluga.net>
+ * @author Arpad Ray <arpad@php.net>
+ * @author David Coallier <davidc@php.net>
+ * @author Elizabeth Smith <auroraeosrose@gmail.com>
+ * @copyright 2005-2008 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/HTML_AJAX
*/
-class HTML_AJAX {
+class HTML_AJAX
+{
/**
* An array holding the instances were exporting
*
* key is the exported name
*
- * row format is array('className'=>'','exportedName'=>'','instance'=>'','exportedMethods=>'')
+ * row format is
+ * <code>
+ * array('className'=>'','exportedName'=>'','instance'=>'','exportedMethods=>'')
+ * </code>
*
* @var object
* @access private
@@ -46,7 +63,9 @@ class HTML_AJAX {
var $serverUrl = false;
/**
- * What encoding your going to use for serializing data from php being sent to javascript
+ * What encoding your going to use for serializing data
+ * from php being sent to javascript.
+ *
* @var string JSON|PHP|Null
*/
var $serializer = 'JSON';
@@ -101,7 +120,10 @@ class HTML_AJAX {
var $debugSession = false;
/**
- * If the Content-Length header should be sent, if your using a gzip handler on an output buffer, or run into any compatability problems, try disabling this.
+ * Boolean telling if the Content-Length header should be sent.
+ *
+ * If your using a gzip handler on an output buffer, or run into
+ * any compatability problems, try disabling this.
*
* @access public
* @var boolean
@@ -109,9 +131,13 @@ class HTML_AJAX {
var $sendContentLength = true;
/**
- * Make Generated code compatible with php4 by lowercasing all class/method names before exporting to JavaScript
- * If you have code that works on php4 but not on php5 then setting this flag can fix the problem.
- * The recommended solution is too specify the class and method names when registering the class letting you have function case in php4 as well
+ * Make Generated code compatible with php4 by lowercasing all
+ * class/method names before exporting to JavaScript.
+ *
+ * If you have code that works on php4 but not on php5 then setting
+ * this flag can fix the problem. The recommended solution is too
+ * specify the class and method names when registering the class
+ * letting you have function case in php4 as well
*
* @access public
* @var boolean
@@ -160,14 +186,24 @@ class HTML_AJAX {
var $_validCallbacks = array();
/**
+ * Interceptor instance
+ */
+ var $_interceptor = false;
+
+ /**
* Set a class to handle requests
*
- * @param object $instance
- * @param mixed $exportedName Name used for the javascript class, if false the name of the php class is used
- * @param mixed $exportedMethods If false all functions without a _ prefix are exported, if an array only the methods listed in the array are exported
- * @return void
+ * @param object &$instance An instance to export
+ * @param mixed $exportedName Name used for the javascript class,
+ * if false the name of the php class is used
+ * @param mixed $exportedMethods If false all functions without a _ prefix
+ * are exported, if an array only the methods
+ * listed in the array are exported
+ *
+ * @return void
*/
- function registerClass(&$instance, $exportedName = false, $exportedMethods = false)
+ function registerClass(&$instance, $exportedName = false,
+ $exportedMethods = false)
{
$className = strtolower(get_class($instance));
@@ -183,23 +219,26 @@ function registerClass(&$instance, $exportedName = false, $exportedMethods = fal
}
- $index = strtolower($exportedName);
- $this->_exportedInstances[$index] = array();
- $this->_exportedInstances[$index]['className'] = $className;
- $this->_exportedInstances[$index]['exportedName'] = $exportedName;
- $this->_exportedInstances[$index]['instance'] =& $instance;
+ $index = strtolower($exportedName);
+ $this->_exportedInstances[$index] = array();
+ $this->_exportedInstances[$index]['className'] = $className;
+ $this->_exportedInstances[$index]['exportedName'] = $exportedName;
+ $this->_exportedInstances[$index]['instance'] =& $instance;
$this->_exportedInstances[$index]['exportedMethods'] = $exportedMethods;
}
/**
* Get a list of methods in a class to export
*
- * This function uses get_class_methods to get a list of callable methods, so if you're on PHP5 extending this class with a class you want to export should export its
- * protected methods, while normally only its public methods would be exported. All methods starting with _ are removed from the export list.
+ * This function uses get_class_methods to get a list of callable methods,
+ * so if you're on PHP5 extending this class with a class you want to export
+ * should export its protected methods, while normally only its public methods
+ * would be exported. All methods starting with _ are removed from the export list.
* This covers PHP4 style private by naming as well as magic methods in either PHP4 or PHP5
*
- * @param string $className
- * @return array all methods of the class that are public
+ * @param string $className Name of the class
+ *
+ * @return array all methods of the class that are public
* @access private
*/
function _getMethodsToExport($className)
@@ -207,10 +246,9 @@ function _getMethodsToExport($className)
$funcs = get_class_methods($className);
foreach ($funcs as $key => $func) {
- if (strtolower($func) === $className || substr($func,0,1) === '_') {
+ if (strtolower($func) === $className || substr($func, 0, 1) === '_') {
unset($funcs[$key]);
- }
- else if ($this->php4CompatCase) {
+ } else if ($this->php4CompatCase) {
$funcs[$key] = strtolower($func);
}
}
@@ -236,8 +274,10 @@ function generateJavaScriptClient()
/**
* Return the stub for a class
*
- * @param string $name name of the class to generated the stub for, note that this is the exported name not the php class name
- * @return string javascript proxy stub code for a single class
+ * @param string $name name of the class to generated the stub for,
+ * note that this is the exported name not the php class name
+ *
+ * @return string javascript proxy stub code for a single class
*/
function generateClassStub($name)
{
@@ -245,7 +285,7 @@ function generateClassStub($name)
return '';
}
- $client = "// Client stub for the {$this->_exportedInstances[$name]['exportedName']} PHP Class\n";
+ $client = "// Client stub for the {$this->_exportedInstances[$name]['exportedName']} PHP Class\n";
$client .= "function {$this->_exportedInstances[$name]['exportedName']}(callback) {\n";
$client .= "\tmode = 'sync';\n";
$client .= "\tif (callback) { mode = 'async'; }\n";
@@ -258,10 +298,10 @@ function generateClassStub($name)
$client .= "{$this->_exportedInstances[$name]['exportedName']}.prototype = {\n";
$client .= "\tSync: function() { this.dispatcher.Sync(); }, \n";
$client .= "\tAsync: function(callback) { this.dispatcher.Async(callback); },\n";
- foreach($this->_exportedInstances[$name]['exportedMethods'] as $method) {
+ foreach ($this->_exportedInstances[$name]['exportedMethods'] as $method) {
$client .= $this->_generateMethodStub($method);
}
- $client = substr($client,0,(strlen($client)-2))."\n";
+ $client = substr($client, 0, (strlen($client)-2))."\n";
$client .= "}\n\n";
if ($this->packJavaScript) {
@@ -273,35 +313,37 @@ function generateClassStub($name)
/**
* Returns a methods stub
*
+ * @param string $method the method name
*
- * @param string the method name
* @return string the js code
* @access private
*/
function _generateMethodStub($method)
{
- $stub = "\t{$method}: function() { return this.dispatcher.doCall('{$method}',arguments); },\n";
+ $stub = "\t{$method}: function() { return ".
+ "this.dispatcher.doCall('{$method}',arguments); },\n";
return $stub;
}
/**
* Populates the current payload
*
- *
- * @param string the method name
* @return string the js code
* @access private
*/
function populatePayload()
{
- if(isset($_REQUEST['Iframe_XHR'])) {
+ if (isset($_REQUEST['Iframe_XHR'])) {
$this->_iframe = $_REQUEST['Iframe_XHR_id'];
- if (isset($_REQUEST['Iframe_XHR_headers']) && is_array($_REQUEST['Iframe_XHR_headers'])) {
+ if (isset($_REQUEST['Iframe_XHR_headers']) &&
+ is_array($_REQUEST['Iframe_XHR_headers'])) {
foreach ($_REQUEST['Iframe_XHR_headers'] as $header) {
- $array = explode(':', $header);
+
+ $array = explode(':', $header);
$array[0] = strip_tags(strtoupper(str_replace('-', '_', $array[0])));
- //only content-length and content-type can go in without an http_ prefix - security
- if(strpos($array[0], 'HTTP_') !== 0
+ //only content-length and content-type can go in without an
+ //http_ prefix - security
+ if (strpos($array[0], 'HTTP_') !== 0
&& strcmp('CONTENT_TYPE', $array[0])
&& strcmp('CONTENT_LENGTH', $array[0])) {
$array[0] = 'HTTP_' . $array[0];
@@ -309,7 +351,9 @@ function populatePayload()
$_SERVER[$array[0]] = strip_tags($array[1]);
}
}
- $this->_payload = (isset($_REQUEST['Iframe_XHR_data']) ? $_REQUEST['Iframe_XHR_data'] : '');
+ $this->_payload = (isset($_REQUEST['Iframe_XHR_data'])
+ ? $_REQUEST['Iframe_XHR_data'] : '');
+
if (isset($_REQUEST['Iframe_XHR_method'])) {
$_GET['m'] = $_REQUEST['Iframe_XHR_method'];
}
@@ -322,11 +366,10 @@ function populatePayload()
/**
* Handle a ajax request if needed
*
- * The current check is if GET variables c (class) and m (method) are set, more options may be available in the future
+ * The current check is if GET variables c (class) and m (method) are set,
+ * more options may be available in the future
*
- * @todo is it worth it to figure out howto use just 1 instance if the type is the same for serialize and unserialize
- *
- * @return boolean true if an ajax call was handled, false otherwise
+ * @return boolean true if an ajax call was handled, false otherwise
*/
function handleRequest()
{
@@ -344,16 +387,18 @@ function handleRequest()
}
}
- $class = strtolower($this->_getVar('c'));
- $method = $this->_getVar('m');
+ $class = strtolower($this->_getVar('c'));
+ $method = $this->_getVar('m');
$phpCallback = $this->_getVar('cb');
+
if (!empty($class) && !empty($method)) {
if (!isset($this->_exportedInstances[$class])) {
// handle error
trigger_error('Unknown class: '. $class);
}
- if (!in_array($method,$this->_exportedInstances[$class]['exportedMethods'])) {
+ if (!in_array(($this->php4CompatCase ? strtolower($method) : $method),
+ $this->_exportedInstances[$class]['exportedMethods'])) {
// handle error
trigger_error('Unknown method: ' . $method);
}
@@ -378,7 +423,8 @@ function handleRequest()
// auto-detect serializer to use from content-type
$type = $this->unserializer;
- $key = array_search($this->_getClientPayloadContentType(),$this->contentTypeMap);
+ $key = array_search($this->_getClientPayloadContentType(),
+ $this->contentTypeMap);
if ($key) {
$type = $key;
}
@@ -388,6 +434,10 @@ function handleRequest()
if (!is_array($args)) {
$args = array($args);
}
+
+ if ($this->_interceptor !== false) {
+ $args = $this->_processInterceptor($class, $method, $phpCallback, $args);
+ }
if (empty($phpCallback)) {
$ret = call_user_func_array(array(&$this->_exportedInstances[$class]['instance'], $method), $args);
@@ -411,11 +461,13 @@ function _getClientPayloadContentType()
//OPERA IS STUPID FIX
if (isset($_SERVER['HTTP_X_CONTENT_TYPE'])) {
$type = $this->_getServer('HTTP_X_CONTENT_TYPE');
- $pos = strpos($type, ';');
+ $pos = strpos($type, ';');
+
return strtolower($pos ? substr($type, 0, $pos) : $type);
} else if (isset($_SERVER['CONTENT_TYPE'])) {
$type = $this->_getServer('CONTENT_TYPE');
- $pos = strpos($type, ';');
+ $pos = strpos($type, ';');
+
return strtolower($pos ? substr($type, 0, $pos) : $type);
}
return 'text/plain';
@@ -428,72 +480,85 @@ function _getClientPayloadContentType()
* Iframe Detection: if this has been detected as an iframe response, it has to
* be wrapped in different code and headers changed (quite a mess)
*
- * @param mixed content to serialize and send
- * @access private
+ * @param mixed $response content to serialize and send
+ *
+ * @access private
+ * @return void
*/
function _sendResponse($response)
{
- if(is_object($response) && is_a($response, 'HTML_AJAX_Response')) {
- $output = $response->getPayload();
+ if (is_object($response) && is_a($response, 'HTML_AJAX_Response')) {
+ $output = $response->getPayload();
$content = $response->getContentType();
- } else if(is_a($response, 'PEAR_Error')) {
+
+ } elseif (is_a($response, 'PEAR_Error')) {
$serializer = $this->_getSerializer('Error');
- $output = $serializer->serialize(array(
+ $output = $serializer->serialize(array(
'message' => $response->getMessage(),
'userinfo' => $response->getUserInfo(),
'code' => $response->getCode(),
'mode' => $response->getMode()
- )
- );
- $content = $this->contentTypeMap['Error'];
+ ));
+ $content = $this->contentTypeMap['Error'];
+
} else {
$serializer = $this->_getSerializer($this->serializer);
- $output = $serializer->serialize($response);
- if (isset($this->contentTypeMap[$this->serializer])) {
- //remember that IE is stupid and wants a capital T
- $content = $this->contentTypeMap[$this->serializer];
+ $output = $serializer->serialize($response);
+
+ $serializerType = $this->serializer;
+ // let a serializer change its output type
+ if (isset($serializer->serializerNewType)) {
+ $serializerType = $serializer->serializerNewType;
+ }
+
+ if (isset($this->contentTypeMap[$serializerType])) {
+ $content = $this->contentTypeMap[$serializerType];
}
}
// headers to force things not to be cached:
$headers = array();
//OPERA IS STUPID FIX
- if(isset($_SERVER['HTTP_X_CONTENT_TYPE']))
- {
+ if (isset($_SERVER['HTTP_X_CONTENT_TYPE'])) {
$headers['X-Content-Type'] = $content;
- $content = 'text/plain';
+ $content = 'text/plain';
}
+
if ($this->_sendContentLength()) {
$headers['Content-Length'] = strlen($output);
}
- $headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
- $headers['Last-Modified'] = gmdate( "D, d M Y H:i:s" ) . 'GMT';
+
+ $headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
+ $headers['Last-Modified'] = gmdate("D, d M Y H:i:s").'GMT';
$headers['Cache-Control'] = 'no-cache, must-revalidate';
- $headers['Pragma'] = 'no-cache';
- $headers['Content-Type'] = $content.'; charset=utf-8';
+ $headers['Pragma'] = 'no-cache';
+ $headers['Content-Type'] = $content.'; charset=utf-8';
//intercept to wrap iframe return data
- if($this->_iframe)
- {
- $output = $this->_iframeWrapper($this->_iframe, $output, $headers);
+ if ($this->_iframe) {
+ $output = $this->_iframeWrapper($this->_iframe,
+ $output, $headers);
$headers['Content-Type'] = 'text/html; charset=utf-8';
}
+
$this->_sendHeaders($headers);
echo $output;
}
/**
* Decide if we should send a Content-length header
- * @return bool true if it's ok to send the header, false otherwise
+ *
+ * @return bool true if it's ok to send the header, false otherwise
* @access private
*/
- function _sendContentLength() {
+ function _sendContentLength()
+ {
if (!$this->sendContentLength) {
return false;
}
$ini_tests = array( "output_handler",
"zlib.output_compression",
"zlib.output_handler");
- foreach($ini_tests as $test) {
+ foreach ($ini_tests as $test) {
if (ini_get($test)) {
return false;
}
@@ -504,12 +569,14 @@ function _sendContentLength() {
/**
* Actually send a list of headers
*
- * @param array list of headers to send, default callback for headers
+ * @param array $array list of headers to send
+ *
* @access private
+ * @return void
*/
function _sendHeaders($array)
{
- foreach($array as $header => $value) {
+ foreach ($array as $header => $value) {
header($header . ': ' . $value);
}
}
@@ -517,7 +584,10 @@ function _sendHeaders($array)
/**
* Get an instance of a serializer class
*
+ * @param string $type Last part of the class name
+ *
* @access private
+ * @return HTML_AJAX_Serializer
*/
function _getSerializer($type)
{
@@ -527,9 +597,10 @@ function _getSerializer($type)
$class = 'HTML_AJAX_Serializer_'.$type;
- if ( (version_compare(phpversion(),5,'>') && !class_exists($class,false)) || (version_compare(phpversion(),5,'<') && !class_exists($class)) ) {
+ if ( (version_compare(phpversion(), 5, '>') && !class_exists($class, false))
+ || (version_compare(phpversion(), 5, '<') && !class_exists($class)) ) {
// include the class only if it isn't defined
- require_once "HTML/AJAX/Serializer/{$type}.php";
+ include_once "HTML/AJAX/Serializer/{$type}.php";
}
//handle JSON loose typing option for associative arrays
@@ -565,13 +636,15 @@ function _getClientPayload()
/**
* stub for getting get vars - applies strip_tags
*
+ * @param string $var variable to get
+ *
* @access private
* @return string filtered _GET value
*/
function _getVar($var)
{
if (!isset($_GET[$var])) {
- return NULL;
+ return null;
} else {
return strip_tags($_GET[$var]);
}
@@ -580,13 +653,15 @@ function _getVar($var)
/**
* stub for getting server vars - applies strip_tags
*
+ * @param string $var variable to get
+ *
* @access private
* @return string filtered _GET value
*/
function _getServer($var)
{
if (!isset($_SERVER[$var])) {
- return NULL;
+ return null;
} else {
return strip_tags($_SERVER[$var]);
}
@@ -595,31 +670,42 @@ function _getServer($var)
/**
* Exception handler, passes them to _errorHandler to do the actual work
*
+ * @param Exception $ex Exception to be handled
+ *
* @access private
+ * @return void
*/
function _exceptionHandler($ex)
{
- $this->_errorHandler($ex->getCode(),$ex->getMessage(),$ex->getFile(),$ex->getLine());
+ $this->_errorHandler($ex->getCode(), $ex->getMessage(), $ex->getFile(), $ex->getLine());
}
/**
* Error handler that sends it errors to the client side
*
+ * @param int $errno Error number
+ * @param string $errstr Error string
+ * @param string $errfile Error file
+ * @param string $errline Error line
+ *
* @access private
+ * @return void
*/
function _errorHandler($errno, $errstr, $errfile, $errline)
{
if ($errno & error_reporting()) {
- $e = new stdClass();
+ $e = new stdClass();
$e->errNo = $errno;
$e->errStr = $errstr;
$e->errFile = $errfile;
$e->errLine = $errline;
+
+
$this->serializer = 'Error';
$this->_sendResponse($e);
if ($this->debugEnabled) {
- $this->debug =& new HTML_AJAX_Debug($errstr, $errline, $errno, $errfile);
+ $this->debug = new HTML_AJAX_Debug($errstr, $errline, $errno, $errfile);
if ($this->debugSession) {
$this->debug->sessionError();
}
@@ -632,15 +718,25 @@ function _errorHandler($errno, $errstr, $errfile, $errline)
/**
* Creates html to wrap serialized info for iframe xmlhttprequest fakeout
*
+ * @param string $id iframe instance id
+ * @param string $data data to pass
+ * @param string $headers headers to pass
+ *
* @access private
+ * @return string html page with iframe passing code
*/
function _iframeWrapper($id, $data, $headers = array())
{
- $string = '<html><script type="text/javascript">'."\n".'var Iframe_XHR_headers = new Object();';
- foreach($headers as $label => $value) {
- $string .= 'Iframe_XHR_headers["'.preg_replace("/\r?\n/", "\\n", addslashes($label)).'"] = "'.preg_replace("/\r?\n/", "\\n", addslashes($value))."\";\n";
+ $string = '<html><script type="text/javascript">'."\n".
+ 'var Iframe_XHR_headers = new Object();';
+
+ foreach ($headers as $label => $value) {
+ $string .= 'Iframe_XHR_headers["'.preg_replace("/\r?\n/", "\\n",
+ addslashes($label)).'"] = "'.preg_replace("/\r?\n/", "\\n",
+ addslashes($value))."\";\n";
}
- $string .= 'var Iframe_XHR_data = "' . preg_replace("/\r?\n/", "\\n", addslashes($data)) . '";</script>'
+ $string .= 'var Iframe_XHR_data = "' . preg_replace("/\r?\n/", "\\n",
+ addslashes($data)) . '";</script>'
. '<body onload="parent.HTML_AJAX_IframeXHR_instances[\''.$id.'\']'
. '.isLoaded(Iframe_XHR_headers, Iframe_XHR_data);"></body></html>';
return $string;
@@ -649,8 +745,8 @@ function _iframeWrapper($id, $data, $headers = array())
/**
* Handles a proxied grab request
*
- * @return bool true to end the response, false to continue trying to handle it
- * @access private
+ * @return bool true to end the response, false to continue trying to handle it
+ * @access private
*/
function _iframeGrabProxy()
{
@@ -658,11 +754,12 @@ function _iframeGrabProxy()
trigger_error('Invalid iframe ID');
return false;
}
- $this->_iframe = $_REQUEST['Iframe_XHR_id'];
+ $this->_iframe = $_REQUEST['Iframe_XHR_id'];
$this->_payload = (isset($_REQUEST['Iframe_XHR_data']) ? $_REQUEST['Iframe_XHR_data'] : '');
- $url = urldecode($_GET['px']);
- $url_parts = parse_url($url);
- $urlregex = '#^https?://#i';
+ $url = urldecode($_GET['px']);
+ $url_parts = parse_url($url);
+ $urlregex = '#^https?://#i';
+
if (!preg_match($urlregex, $url) || $url_parts['host'] != $_SERVER['HTTP_HOST']) {
trigger_error('Invalid URL for grab proxy');
return true;
@@ -696,7 +793,7 @@ function _iframeGrabProxy()
'content' => $this->_payload
)
);
- $ret = @file_get_contents($url, false, stream_context_create($opts));
+ $ret = @file_get_contents($url, false, stream_context_create($opts));
if (!empty($ret)) {
$this->_sendResponse($ret);
return true;
@@ -738,15 +835,17 @@ function _iframeGrabProxy()
$fp = fsockopen($_SERVER['HTTP_HOST'], $port, $errno, $errstr, 4);
if ($fp) {
fputs($fp, $request);
- $ret = '';
+
+ $ret = '';
$done_headers = false;
+
while (!feof($fp)) {
$ret .= fgets($fp, 2048);
if ($done_headers || ($contentpos = strpos($ret, "\r\n\r\n")) === false) {
continue;
}
$done_headers = true;
- $ret = substr($ret, $contentpos + 4);
+ $ret = substr($ret, $contentpos + 4);
}
fclose($fp);
$this->_sendResponse($ret);
@@ -760,15 +859,17 @@ function _iframeGrabProxy()
trigger_error('Grab proxy failed: ' . socket_strerror($socket));
return true;
}
- $ret = '';
+
+ $ret = '';
$done_headers = false;
+
while ($out = socket_read($socket, 2048)) {
$ret .= $out;
if ($done_headers || ($contentpos = strpos($ret, "\r\n\r\n")) === false) {
continue;
}
$done_headers = true;
- $ret = substr($ret, $contentpos + 4);
+ $ret = substr($ret, $contentpos + 4);
}
socket_close($socket);
$this->_sendResponse($ret);
@@ -776,12 +877,13 @@ function _iframeGrabProxy()
}
/**
- * Add a class or classes to those allowed to be unserialized
- *
- * @param mixed $classes
- * the class or array of classes to add
- * @access public
- */
+ * Add a class or classes to those allowed to be unserialized
+ *
+ * @param mixed $classes the class or array of classes to add
+ *
+ * @access public
+ * @return void
+ */
function addAllowedClasses($classes)
{
if (!is_array($classes)) {
@@ -795,11 +897,10 @@ function addAllowedClasses($classes)
/**
* Checks that the given callback is callable and allowed to be called
*
- * @param callback $callback
- * the callback to check
- * @return bool
- * true if the callback is valid, false otherwise
- * @access private
+ * @param callback $callback the callback to check
+ *
+ * @return bool true if the callback is valid, false otherwise
+ * @access private
*/
function _validatePhpCallback($callback)
{
@@ -813,9 +914,10 @@ function _validatePhpCallback($callback)
/**
* Register a callback so it may be called from JS
*
- * @param callback $callback
- * the callback to register
- * @access public
+ * @param callback $callback the callback to register
+ *
+ * @access public
+ * @return void
*/
function registerPhpCallback($callback)
{
@@ -824,56 +926,149 @@ function registerPhpCallback($callback)
/**
* Make JavaScript code smaller
- *
+ *
* Currently just strips whitespace and comments, needs to remain fast
+ * Strips comments only if they are not preceeded by code
+ * Strips /*-style comments only if they span over more than one line
+ * Since strings cannot span over multiple lines, it cannot be defeated by a
+ * string containing /*
+ *
+ * @param string $input Javascript to pack
+ *
+ * @access public
+ * @return string packed javascript
*/
- function packJavaScript($input) {
- $stripPregs = array(
- '/^\s+$/',
+ function packJavaScript($input)
+ {
+ $stripPregs = array(
+ '/^\s*$/',
'/^\s*\/\/.*$/'
);
- $blockStart = '/\/\*/';
- $blockEnd = '/\*\//';
-
- $out = '';
-
- $lines = explode("\n",$input);
- $inblock = false;
- foreach($lines as $line) {
- $keep = true;
- if ($inblock) {
- if (preg_match($blockEnd,$line)) {
- $inblock = false;
- $keep = false;
- }
- }
- else if (preg_match($blockStart,$line)) {
- $inblock = true;
- $keep = false;
- if (preg_match($blockEnd,$line)) {
+ $blockStart = '/^\s*\/\/\*/';
+ $blockEnd = '/\*\/\s*(.*)$/';
+ $inlineComment = '/\/\*.*\*\//';
+ $out = '';
+
+ $lines = explode("\n", $input);
+ $inblock = false;
+ foreach ($lines as $line) {
+ $keep = true;
+ if ($inblock) {
+ if (preg_match($blockEnd, $line)) {
$inblock = false;
+ $line = preg_match($blockEnd, '$1', $line);
+ $keep = strlen($line) > 0;
}
- }
-
- if (!$inblock) {
- foreach($stripPregs as $preg) {
- if (preg_match($preg,$line)) {
- $keep = false;
- break;
- }
- }
- }
-
- if ($keep && !$inblock) {
- $out .= trim($line)."\n";
- }
- /* Enable to see what your striping out
- else {
- echo $line."<br>";
- }//*/
- }
+ } elseif (preg_match($inlineComment, $line)) {
+ $keep = true;
+ } elseif (preg_match($blockStart, $line)) {
+ $inblock = true;
+ $keep = false;
+ }
+
+ if (!$inblock) {
+ foreach ($stripPregs as $preg) {
+ if (preg_match($preg, $line)) {
+ $keep = false;
+ break;
+ }
+ }
+ }
+
+ if ($keep && !$inblock) {
+ $out .= trim($line)."\n";
+ }
+ /* Enable to see what your striping out
+ else {
+ echo $line."<br>";
+ }//*/
+ }
+ $out .= "\n";
return $out;
}
+
+ /**
+ * Set an interceptor class
+ *
+ * An interceptor class runs during the process of handling a request,
+ * it allows you to run security checks globally. It also allows you to
+ * rewrite parameters
+ *
+ * You can throw errors and exceptions in your intercptor methods and
+ * they will be passed to javascript
+ *
+ * You can add interceptors are 3 levels
+ * For a particular class/method, this is done by add a method to you class
+ * named ClassName_MethodName($params)
+ * For a particular class, method ClassName($methodName,$params)
+ * Globally, method intercept($className,$methodName,$params)
+ *
+ * Only one match is done, using the most specific interceptor
+ *
+ * All methods have to return $params, if you want to empty all of the
+ * parameters return an empty array
+ *
+ * @param Object $instance an instance of you interceptor class
+ *
+ * @todo handle php callbacks
+ * @access public
+ * @return void
+ */
+ function setInterceptor($instance)
+ {
+ $this->_interceptor = $instance;
+ }
+
+ /**
+ * Attempt to intercept a call
+ *
+ * @param string $className Class Name
+ * @param string $methodName Method Name
+ * @param string $callback Not implemented
+ * @param array $params Array of parameters to pass to the interceptor
+ *
+ * @todo handle php callbacks
+ * @access private
+ * @return array Updated params
+ */
+ function _processInterceptor($className,$methodName,$callback,$params)
+ {
+
+ $m = $className.'_'.$methodName;
+ if (method_exists($this->_interceptor, $m)) {
+ return $this->_interceptor->$m($params);
+ }
+
+ $m = $className;
+ if (method_exists($this->_interceptor, $m)) {
+ return $this->_interceptor->$m($methodName, $params);
+ }
+
+ $m = 'intercept';
+ if (method_exists($this->_interceptor, $m)) {
+ return $this->_interceptor->$m($className, $methodName, $params);
+ }
+
+ return $params;
+ }
+}
+
+/**
+ * PHP 4 compat function for interface/class exists
+ *
+ * @param string $class Class name
+ * @param bool $autoload Should the autoloader be called
+ *
+ * @access public
+ * @return bool
+ */
+function HTML_AJAX_Class_exists($class, $autoload)
+{
+ if (function_exists('interface_exists')) {
+ return class_exists($class, $autoload);
+ } else {
+ return class_exists($class);
+ }
}
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
?>
12 AJAX/Debug.php
View
@@ -1,5 +1,5 @@
<?php
-define ("NEWLINE", "\n");
+define ("HTML_AJAX_NEWLINE", "\n");
// {{{ class HTML_AJAX_Debug
/**
* AJAX Debugging implementation
@@ -101,11 +101,11 @@ function HTML_AJAX_Debug($errMsg, $errLine, $errCode, $errFile)
*/
function xmlError()
{
- $error = " <when>{$this->_timeOccured}</when>" . NEWLINE;
- $error .= " <msg>{$this->errorMsg}</msg>" . NEWLINE;
- $error .= " <code>{$this->errorCode}</code>" . NEWLINE;
- $error .= " <line>{$this->errorLine}</line>" . NEWLINE;
- $error .= " <file>{$this->errorFile}</file>" . NEWLINE . NEWLINE;
+ $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;
}
// }}}
43 AJAX/Helper.php
View
@@ -40,6 +40,11 @@ class HTML_AJAX_Helper
*/
var $stubs = array();
+ /**
+ * Combine jsLibraries into a single require and remove duplicates
+ */
+ var $combineJsIncludes = false;
+
/**
* Include all needed libraries, stubs, and set defaultServer
*
@@ -48,24 +53,41 @@ class HTML_AJAX_Helper
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 = '';
- foreach($libs as $list) {
- $ret .= "<script type='text/javascript' src='{$this->serverUrl}?client={$list}'></script>\n";
- }
+ 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}?stub={$stubs}'></script>\n";
+ $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;
@@ -145,5 +167,18 @@ function jsonEncode($input) {
$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: */
?>
9 AJAX/JSON.php
View
@@ -6,6 +6,11 @@
* Feel free to report bugs against it to HTML_AJAX
*/
+/**
+ * Needed for compat functions
+ */
+require_once 'HTML/AJAX.php';
+
/**
* Converts to and from JSON format.
*
@@ -755,7 +760,7 @@ function decode($str)
*/
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'))) {
@@ -766,7 +771,7 @@ function isError($data, $code = null)
}
}
-if (class_exists('pear_error')) {
+if (HTML_AJAX_class_exists('pear_error', false)) {
class HTML_AJAX_JSON_Error extends PEAR_Error
{
2  AJAX/Serializer/JSON.php
View
@@ -43,7 +43,7 @@ function HTML_AJAX_Serializer_JSON($use_loose_type = true)
$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);
+ $this->_json = new HTML_AJAX_JSON($use_loose_type);
}
}
// }}}
76 AJAX/Server.php
View
@@ -93,6 +93,24 @@ class HTML_AJAX_Server
);
/**
+ * 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
@@ -121,10 +139,10 @@ class HTML_AJAX_Server
'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'),
+ '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',
@@ -155,7 +173,7 @@ class HTML_AJAX_Server
*/
function HTML_AJAX_Server($serverUrl = false)
{
- $this->ajax =& new HTML_AJAX();
+ $this->ajax = new HTML_AJAX();
// parameters for HTML::AJAX
$parameters = array('stub', 'client');
@@ -434,8 +452,15 @@ function generateClient()
$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-Length'] = $length;
}
$headers['Content-Type'] = 'text/javascript; charset=utf-8';
$this->ajax->_sendHeaders($headers);
@@ -480,6 +505,45 @@ function 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
11 examples/form.php
View
@@ -76,5 +76,16 @@
</table>
<input type="submit" name="submit" value="Submit form" />
</form>
+
+ <h3>JavaScript callback function target test</h3>
+ <form action="server.php" method="post" onsubmit="return !HTML_AJAX.formSubmit(this, function(result) { document.getElementById('target').innerHTML = result; }, {className: 'test', methodName:'multiarg'});">
+
+ <table>
+ <tr>
+ <td>Text</td>
+ <td><input type="text" name="test_text" value="example" /></td>
+ </tr>
+ </table>
+ </form>
</body>
</html>
2  examples/guestbook/auto_server.php
View
@@ -21,7 +21,7 @@ class GuestbookServer extends HTML_AJAX_Server {
// init method for the test class, includes needed files an registers it for ajax
function initGuestbook() {
include 'guestbook.class.php';
- $this->registerClass(new Guestbook(),'guestbook',array('newEntry', 'clearGuestbook', 'deleteEntry', 'editEntry')); // specify methods so that we get case in php4
+ $this->registerClass(new Guestbook(),'guestbook',array('newEntry', 'clearGuestbook', 'deleteEntry', 'editEntry', 'updateSelect')); // specify methods so that we get case in php4
}
}
13 examples/guestbook/guestbook.class.php
View
@@ -137,6 +137,19 @@ function editEntry($id) {
return $response;
}
+ function updateSelect($id)
+ {
+ $response = new HTML_AJAX_Action();
+ $attr = array('id' => $id, 'name' => $id);
+ $response->replaceNode($id, 'select', $attr);
+ for ($i=1;$i<=10;$i++)
+ {
+ $attr = array('value' => $i, 'innerHTML' => 'Option ' . $i);
+ $response->createNode($id, 'option', $attr, 'append');
+ }
+ return $response;
+ }
+
function _makeDiv($key, $data, $replace = FALSE) {
$div = '';
if($replace == FALSE)
24 examples/guestbook/index.php
View
@@ -148,6 +148,10 @@ function editentry(id) {
var remoteguestbook = new guestbook();
remoteguestbook.editEntry(id);
}
+function updateselect(id) {
+ var remoteguestbook = new guestbook();
+ remoteguestbook.updateSelect(id);
+}
</script>
<h2>Welcome to the Guestbook</h2>
<div id="guestbookList">
@@ -184,15 +188,15 @@ function editentry(id) {
</fieldset>
</form>
-<h4>Current Guestbook Testing Status</h4>
-<h5>Win32 - XP</h5>
-<ol>
-<li>Firefox 1.5b - all passed</li>
-<li>IE 6 - all passed</li>
-<li>Netscape 8 - IE mode passed, Gecko mode failed (some kind of browser bug I suspect)</li>
-<li>Opera 8.5 - all passed</li>
-<li>IE 5.5 - sessions were messed up but what worked was fine</li>
-<li>IE 5.01 - same as 5.5, messed up sessions but partially worked</li>
-</ol>
+<p>Fill a select item with a list of options - tests the HTML_AJAX_Action::replaceNode and HTML_AJAX_Action::createNode methods</p>
+ <form id="testing" action="index.php" method="post" onsubmit="return false;">
+ <div>
+ <a href="#" onclick="updateselect('replaceme');">Gimme some options</a>
+ <select id="replaceme">
+ <option name="dog" id="dog">Dog</option>
+ </select>
+ </div>
+ </form>
+
</body>
</html>
12 examples/helper_usage.php
View
@@ -18,7 +18,7 @@
// create an instance and set the server url
$ajaxHelper = new HTML_AJAX_Helper();
-$ajaxHelper->serverUrl = 'auto_server.php';
+$ajaxHelper->serverUrl = 'server.php?gzip=true';
$ajaxHelper->jsLibraries[] = 'customLib';
?>
<html>
@@ -42,6 +42,16 @@
// update the element using ajax
echo $ajaxHelper->updateElement('updateTarget',array('test','echo_string','Some text to echo'),'replace',true);
?>
+
+
+<p>Was this page loaded using AJAX: <?php var_dump($ajaxHelper->isAJAX()); ?></p>
+
+Below is the output of HTML_AJAX_Helper::isAJAX() on content loaded from AJAX
+<div id="updateTarget2"></div>
+<?php
+ echo $ajaxHelper->updateElement('updateTarget2','support/isajax.php','replace',true);
+?>
+
</body>
</html>
<?php
8 examples/index.php
View
@@ -1,9 +1,9 @@
<html>
<head>
-<title>HTML_AJAX 0.5.0 Examples</title>
+<title>HTML_AJAX 0.5.3 Examples</title>
</head>
<body>
-<h1>HTML_AJAX 0.5.0 Examples</h1>
+<h1>HTML_AJAX 0.5.3 Examples</h1>
<p>
These are examples showing the basics of using HTML_AJAX
</p>
@@ -58,6 +58,8 @@
<li><a href='server.php?client=util,main'>server.php?client=util,main</a> - server.php generating a javascript file with the main and util libs in it</li>
<li><a href='auto_server.php?stub=test2'>server.php?stub=test2</a> - auto_server.php generating a javascript file a which contains a generated proxy class for the test2 php class</li>
<li><a href='auto_server.php?stub=all'>server.php?stub=all</a> - auto_server.php generating a javascript file which contains proxies for all the php classes registered with it</li>
+<li><a href='server.php?stub=all&gzip=true'>server.php?stub=all&gzip=true</a> - an example with gzip compression enabled (note gzip=true isn't built in, see server.php)<li>
+<li><a href='server.php?stub=all&gzip=true'>server.php?stub=all&gzip=true</a> - another example with gzip compression enabled (note gzip=true isn't built in, see server.php)<li>
</ul>
<p>
@@ -79,6 +81,8 @@
<li><a href='tests/setInnerHTML.php'>setInnerHTML.php</a> - Tests used to verify the operation of HTML_AJAX_Util.setInnerHTML</li>
<li><a href='tests/duplicateJSLib.php'>duplicateJSLib.php</a> - Tests used to verify that HTML_AJAX_Server is removing duplicate JS libraries from client generation correctly</li>
<li><a href='tests/behaviorSpeed.php'>behaviorSpeed.php</a> - Tests used to see how fast the JavaScript behavior code runs.</li>
+<li><a href='tests/helper_combine.php'>helper_combine.php</a> - Tests used to verify helper url javascript include generation.</li>
+<li><a href='interceptors.php'>interceptors.php</a> - Interceptors test</a></li>
</ul>
<p>
3  examples/proxy_usage_server.php
View
@@ -82,7 +82,8 @@ function asyncCall() {
}
function unicodeTest() {
- asyncProxy.echo_data({'suggestion': ['Français', 'caractères']});
+ //asyncProxy.echo_data({'suggestion': ['Français', 'caractères']});
+ asyncProxy.echo_data({"suggestion":["Fran\u00e7ais","caract\u00e8res"]});
}
function unicodeTest2() {
12 examples/review/review.class.php
View
@@ -10,16 +10,24 @@ function Review() {
// data is an array of objects
function newReview($data) {
+ // clean data, its coming from the client
+ $data['name'] = htmlentities($data['name']);
+ $data['review'] = htmlentities($data['review']);
+
$_SESSION['reviews'][] = $data;
$key = count($_SESSION['reviews'])-1;
- return "<div onclick='editReview($key,this)'><div class='name'>$data->name</div><div class='review'>$data->review</div></div>";
+ return "<div onclick='editReview($key,this)'><div class='name'>$data[name]</div><div class='review'>$data[review]</div></div>";
}
function updateReview($key,$data) {
+ // clean data, its coming from the client
+ $data['name'] = htmlentities($data['name']);
+ $data['review'] = htmlentities($data['review']);
+
$_SESSION['reviews'][$key] = $data;
- return array($key,"<div onclick='editReview($key,this)'><div class='name'>$data->name</div><div class='review'>$data->review</div></div>");
+ return array($key,"<div onclick='editReview($key,this)'><div class='name'>$data[name]</div><div class='review'>$data[review]</div></div>");
}
}
?>
7 examples/server.php
View
@@ -28,6 +28,13 @@
$server->registerClass($test);
$server->ajax->packJavaScript = true;
+if (isset($_GET['gzip']) && $_GET['gzip'] == 'true') {
+ $server->compression['enabled'] = true;
+}
+
+// user HTML_AJAX to deliver a custom library
+$server->registerJSLibrary('customLib','customLib.js','./support/');
+
// handle different types of requests possiblities are
// ?client=all - request for all javascript client files
// ?stub=classname - request for proxy stub for given class, can be combined with client but this may hurt caching unless stub=all is used
10 examples/support/test.class.php
View
@@ -46,6 +46,16 @@ function unicode_data() {
$returnData = array('word' => mb_convert_encoding('Français','UTF-8'), 'suggestion' => array(mb_convert_encoding('Français','UTF-8'), mb_convert_encoding('caractères','UTF-8')));
return $returnData;
}
+
+ function test1($in) {
+ return $in;
+ }
+ function test2($in) {
+ return $in;
+ }
+ function test3($in) {
+ return $in;
+ }
}
if (isset($_GET['TEST_CLASS'])) {
11 examples/support/test2.class.php
View
@@ -11,15 +11,8 @@
* @link http://pear.php.net/package/HTML_AJAX
*/
class test2 {
- function echo_string($string) {
- return $string;
- }
- function slow_echo_string($string) {
- sleep(2);
- return $string;
- }
- function error_test($string) {
- trigger_error($string);
+ function test($in) {
+ return $in;
}
}
?>
17 examples/support/xml.class.php
View
@@ -32,7 +32,7 @@ function createHealthy()
$element->appendChild($dom->createTextNode('carrot'));
return $dom;
}
- else
+ elseif (extension_loaded('Domxml'))
{
$dom = domxml_new_doc('1.0');
$element = $dom->create_element('root');
@@ -51,6 +51,9 @@ function createHealthy()
$root->append_child($element);
return $dom;
}
+ else {
+ return 'No Dom Support';
+ }
}
function createJunk()
@@ -74,7 +77,7 @@ function createJunk()
$element->appendChild($dom->createTextNode('pie'));
return $dom;
}
- else
+ else if(extension_loaded('Domxml'))
{
$dom = domxml_new_doc('1.0');
$element = $dom->create_element('root');
@@ -93,6 +96,9 @@ function createJunk()
$root->append_child($element);
return $dom;
}
+ else {
+ return 'No Dom Support';
+ }
}
function writeDoc($dom) {
@@ -101,10 +107,13 @@ function writeDoc($dom) {
// save implementation is broken in dom right now
file_put_contents('test.xml', $dom->saveXML());
}
- else
+ else if(extension_loaded('Domxml'))
{
$doc->dump_file(realpath('test.xml'),false,true);
}
+ else {
+ return 'No Dom Support';
+ }
}
}
-?>
+?>
21 examples/xml_usage.php
View
@@ -67,10 +67,10 @@ function clearTarget() {
}
//create xml document to send back to server
-var xmlhello = '<?xml version="1.0"?><root><tag>Hello</tag></root>';
+var xmlhello = '<' + '?xml version="1.0"?><root><tag>Hello</tag></root>';
xmlhello = new DOMParser().parseFromString(xmlhello, 'text/xml');
-var xmlgoodbye = '<?xml version="1.0"?><root><tag>Goodbye</tag></root>';
+var xmlgoodbye = '<' + '?xml version="1.0"?><root><tag>Goodbye</tag></root>';
xmlgoodbye = new DOMParser().parseFromString(xmlgoodbye, 'text/xml');
</script>
@@ -102,6 +102,21 @@ function asyncSend(xml) {
asyncProxy.writeDoc(xml);
}
</script>
+
+<p>HTML_AJAX XML functionality needs the Dom extensions in PHP5 or the DOMXML extension in PHP4.<br>
+It looks like you have:<br>
+<?php
+if (extension_loaded('Dom')) {
+ echo 'The Dom extension';
+}
+else if (extension_loaded('Domxml')) {
+ echo 'The Domxml extension';
+}
+else {
+ echo 'No XML DOM support, so you can expect these examples to fail';
+}
+?>
+</p>
<ul>
<li><a href="javascript:clearTarget()">Clear Target</a></li>
<li><a href="javascript:syncCall()">Retrieve XmlDom Sync</a></li>
@@ -114,4 +129,4 @@ function asyncSend(xml) {
</div>
</body>
-</html>
+</html>
2  examples/xmlserver.php
View
@@ -6,7 +6,7 @@
$server = new HTML_AJAX_Server();
// register an instance of the class were registering
$xml =& new TestXml();
-$server->registerClass($xml);
+$server->registerClass($xml,'TestXml',array('createHealthy','createJunk','writeDoc'));
$server->setSerializer('XML');
$server->handleRequest();
?>
35 js/Compat.js
View
@@ -98,25 +98,20 @@ if (!Array.pop && !Array.prototype.pop) {
return this.splice(this.length - 1, 1)[0];
}
}
-/*
- From IE7, version 0.9 (alpha) (2005-08-19)
- Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
-*/
-if (!DOMParser.parseFromString && window.ActiveXObject)
-{
-function DOMParser() {/* empty constructor */};
-DOMParser.prototype = {
- parseFromString: function(str, contentType) {
- var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
- xmlDocument.loadXML(str);
- return xmlDocument;
- }
-};
+if (window.ActiveXObject && window['DOMParser'] == 'undefined') {
+ window.DOMParser = new function() {};
+ DOMParser.prototype = {
+ parseFromString: function(str, contentType) {
+ var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
+ xmlDocument.loadXML(str);
+ return xmlDocument;
+ }
+ };
-function XMLSerializer() {/* empty constructor */};
-XMLSerializer.prototype = {
- serializeToString: function(root) {
- return root.xml || root.outerHTML;
- }
-};
+ window.XMLSerializer = new function() {};
+ XMLSerializer.prototype = {
+ serializeToString: function(root) {
+ return root.xml || root.outerHTML;
+ }
+ };
}
828 js/HTML_AJAX.js
View
@@ -99,27 +99,22 @@ if (!Array.pop && !Array.prototype.pop) {
return this.splice(this.length - 1, 1)[0];
}
}
-/*
- From IE7, version 0.9 (alpha) (2005-08-19)
- Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
-*/
-if (!DOMParser.parseFromString && window.ActiveXObject)
-{
-function DOMParser() {/* empty constructor */};
-DOMParser.prototype = {
- parseFromString: function(str, contentType) {
- var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
- xmlDocument.loadXML(str);
- return xmlDocument;
- }
-};
-
-function XMLSerializer() {/* empty constructor */};
-XMLSerializer.prototype = {
- serializeToString: function(root) {
- return root.xml || root.outerHTML;
- }
-};
+if (window.ActiveXObject && window['DOMParser'] == 'undefined') {
+ window.DOMParser = new function() {};
+ DOMParser.prototype = {
+ parseFromString: function(str, contentType) {
+ var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
+ xmlDocument.loadXML(str);
+ return xmlDocument;
+ }
+ };
+
+ window.XMLSerializer = new function() {};
+ XMLSerializer.prototype = {
+ serializeToString: function(root) {
+ return root.xml || root.outerHTML;
+ }
+ };
}
// Main.js
/**
@@ -154,6 +149,7 @@ XMLSerializer.prototype = {
* HTML_AJAX static methods, this is the main proxyless api, it also handles global error and event handling
*/
var HTML_AJAX = {
+ version: '@package_version@',
defaultServerUrl: false,
defaultEncoding: 'JSON',
queues: false,
@@ -263,7 +259,7 @@ var HTML_AJAX = {
},
replace: function(id) {
var callback = function(result) {
- HTML_AJAX_Util.setInnerHTML(document.getElementById(id),result);
+ HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result);
}
if (arguments.length == 2) {
// grab replacement
@@ -280,7 +276,7 @@ var HTML_AJAX = {
},
append: function(id) {
var callback = function(result) {
- HTML_AJAX_Util.setInnerHTML(document.getElementById(id),result,'append');
+ HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result,'append');
}
if (arguments.length == 2) {
// grab replacement
@@ -464,9 +460,27 @@ var HTML_AJAX = {
if (!target) {
target = form;
}
- var action = form.attributes['action'].value;
- var callback = function(result) {
- HTML_AJAX_Util.setInnerHTML(target,result);
+ try
+ {
+ var action = form.attributes['action'].value;
+ }
+ catch(e){}
+ if(action == undefined)
+ {
+ action = form.getAttribute('action');
+ }
+
+ var callback = false;
+ if (HTML_AJAX_Util.getType(target) == 'function') {
+ callback = target;
+ }
+ else {
+ callback = function(result) {
+ // result will be undefined if HA_Action is returned, so skip the replace
+ if (typeof result != 'undefined') {
+ HTML_AJAX_Util.setInnerHTML(target,result);
+ }
+ }
}
var serializer = HTML_AJAX.serializerForEncoding('Null');
@@ -496,8 +510,14 @@ var HTML_AJAX = {
request[i] = options[i];
}
}
- HTML_AJAX.makeRequest(request);
- return true;
+
+ if (request.isAsync == false) {
+ return HTML_AJAX.makeRequest(request);
+ }
+ else {
+ HTML_AJAX.makeRequest(request);
+ return true;
+ }
}, // end formSubmit()
makeFormAJAX: function(form,target,options) {
form = HTML_AJAX_Util.getElement(form);
@@ -715,12 +735,12 @@ HTML_AJAX_Queue_Ordered.prototype = {
}
else {
this.interned[order] = result;
- if (this.interned[this.current]) {
- this.callbacks[this.current](this.interned[this.current]);
- this.current++;
- }
}
- }
+ while (this.interned[this.current]) {
+ this.callbacks[this.current](this.interned[this.current]);
+ this.current++;
+ }
+}
}
// Make a single request at once, canceling and currently outstanding requests when a new one is made
@@ -1746,7 +1766,7 @@ HTML_AJAX_HttpClient.prototype = {
var self = this;
this.xmlhttp.open(this.request.requestType,this.request.completeUrl(),this.request.isAsync);
if (this.request.customHeaders) {
- for (i in this.request.customHeaders) {
+ for (var i in this.request.customHeaders) {
this.xmlhttp.setRequestHeader(i, this.request.customHeaders[i]);
}
}
@@ -1977,7 +1997,7 @@ HTML_AJAX_Request.prototype = {
priority: 0,
// a hash of headers to add to add to this request
- customHeaders: {},
+ customHeaders: {'X-Requested-With': 'XMLHttpRequest', 'X-Ajax-Engine': 'HTML_AJAX/@package_version@'},
// true if this request will be sent using iframes
iframe: false,
@@ -2085,326 +2105,137 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
-Array.prototype.______array = '______array';
-
-var HTML_AJAX_JSON = {
- org: 'http://www.JSON.org',
- copyright: '(c)2005 JSON.org',
- license: 'http://www.crockford.com/JSON/license.html',
-
- stringify: function (arg) {
- var c, i, l, s = '', v;
-
- switch (typeof arg) {
- case 'object':
- if (arg) {
- if (arg.______array == '______array') {
- for (i = 0; i < arg.length; ++i) {
- v = this.stringify(arg[i]);
- if (s) {
- s += ',';
- }
- s += v;
- }
- return '[' + s + ']';
- } else if (typeof arg.toString != 'undefined') {
- for (i in arg) {
- v = arg[i];
- if (typeof v != 'undefined' && typeof v != 'function') {
- v = this.stringify(v);
- if (s) {
- s += ',';
- }
- s += this.stringify(i) + ':' + v;
- }
- }
- return '{' + s + '}';
- }
- }
- return 'null';
- case 'number':
- return isFinite(arg) ? String(arg) : 'null';
- case 'string':
- l = arg.length;
- s = '"';
- for (i = 0; i < l; i += 1) {
- c = arg.charAt(i);
- if (c >= ' ') {
- if (c == '\\' || c == '"') {
- s += '\\';
- }
- s += c;
- } else {
- switch (c) {
- case '\b':
- s += '\\b';
- break;
- case '\f':
- s += '\\f';
- break;
- case '\n':
- s += '\\n';
- break;
- case '\r':
- s += '\\r';
- break;
- case '\t':
- s += '\\t';
- break;
- default:
- c = c.charCodeAt();
- s += '\\u00' + Math.floor(c / 16).toString(16) +
- (c % 16).toString(16);
- }
- }
- }
- return s + '"';
- case 'boolean':
- return String(arg);
- default:
- return 'null';
- }
- },
- parse: function (text) {
- var at = 0;
- var ch = ' ';
-
- function error(m) {
- throw {
- name: 'JSONError',
- message: m,
- at: at - 1,
- text: text
- };
- }
-
- function next() {
- ch = text.charAt(at);
- at += 1;
- return ch;
- }
-
- function white() {
- while (ch) {
- if (ch <= ' ') {
- next();
- } else if (ch == '/') {
- switch (next()) {
- case '/':
- while (next() && ch != '\n' && ch != '\r') {}
- break;
- case '*':
- next();
- for (;;) {
- if (ch) {
- if (ch == '*') {
- if (next() == '/') {
- next();
- break;
- }
- } else {
- next();
- }
- } else {
- error("Unterminated comment");
- }
- }
- break;
- default:
- error("Syntax error");
- }
- } else {
- break;
- }
- }
- }
-
- function string() {
- var i, s = '', t, u;
-
- if (ch == '"') {
-outer: while (next()) {
- if (ch == '"') {
- next();
- return s;
- } else if (ch == '\\') {
- switch (next()) {
- case 'b':
- s += '\b';
- break;
- case 'f':
- s += '\f';
- break;
- case 'n':
- s += '\n';
- break;
- case 'r':
- s += '\r';
- break;
- case 't':
- s += '\t';
- break;
- case 'u':
- u = 0;
- for (i = 0; i < 4; i += 1) {
- t = parseInt(next(), 16);
- if (!isFinite(t)) {
- break outer;
- }
- u = u * 16 + t;
- }
- s += String.fromCharCode(u);
- break;
- default:
- s += ch;
- }
- } else {
- s += ch;
- }
- }
- }
- error("Bad string");
- }
-
- function array() {
- var a = [];
-
- if (ch == '[') {
- next();
- white();
- if (ch == ']') {
- next();
- return a;
- }
- while (ch) {
- a.push(value());
- white();
- if (ch == ']') {
- next();
- return a;
- } else if (ch != ',') {
- break;
- }
- next();
- white();
- }
- }
- error("Bad array");
- }
-
- function object() {
- var k, o = {};
+/*
+ The global object JSON contains two methods.
- if (ch == '{') {
- next();
- white();
- if (ch == '}') {
- next();
- return o;
- }
- while (ch) {
- k = string();
- white();
- if (ch != ':') {
- break;
- }
- next();
- o[k] = value();
- white();
- if (ch == '}') {
- next();
- return o;
- } else if (ch != ',') {
- break;
- }
- next();
- white();
- }
- }
- error("Bad object");
- }
+ JSON.stringify(value) takes a JavaScript value and produces a JSON text.
+ The value must not be cyclical.
- function number() {
- var n = '', v;
- if (ch == '-') {
- n = '-';
- next();
- }
- while (ch >= '0' && ch <= '9') {
- n += ch;
- next();
- }
- if (ch == '.') {
- n += '.';
- while (next() && ch >= '0' && ch <= '9') {
- n += ch;
- }
- }
- if (ch == 'e' || ch == 'E') {
- n += 'e';
- next();
- if (ch == '-' || ch == '+') {
- n += ch;
- next();
- }
- while (ch >= '0' && ch <= '9') {
- n += ch;
- next();
- }
- }
- v = +n;
- if (!isFinite(v)) {
- ////error("Bad number");
- } else {
- return v;
- }
- }
-
- function word() {
- switch (ch) {
- case 't':
- if (next() == 'r' && next() == 'u' && next() == 'e') {
- next();
- return true;
- }
- break;
- case 'f':
- if (next() == 'a' && next() == 'l' && next() == 's' &&
- next() == 'e') {
- next();
- return false;
- }
- break;
- case 'n':