diff --git a/phpgwapi/inc/xajax.inc.php b/phpgwapi/inc/xajax.inc.php index 997aef17ba..602a049302 100644 --- a/phpgwapi/inc/xajax.inc.php +++ b/phpgwapi/inc/xajax.inc.php @@ -1,398 +1,545 @@ charset = is_object($GLOBALS['egw']->translation) ? $GLOBALS['egw']->translation->charset() : 'UTF-8'; - //error_log("xajaxResponse: charset=$this->charset"); - $this->xml = "charset\"?>"; - $this->xml .= ""; - } - - // addAssign() adds an assign command message to your xml response - // $sTarget is a string containing the id of an HTML element - // $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.) - // $sData is the data you want to set the attribute to - // usage: $objResponse->addAssign("contentDiv","innerHTML","Some Text"); - function addAssign($sTarget,$sAttribute,$sData) - { - $this->xml .= ""; - $this->xml .= "$sTarget"; - $this->xml .= ""; - $this->xml .= ""; - } - - // addAppend() adds an append command message to your xml response - // $sTarget is a string containing the id of an HTML element - // $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.) - // $sData is the data you want to append to the end of the attribute - // usage: $objResponse->addAppend("contentDiv","innerHTML","Some Text"); - function addAppend($sTarget,$sAttribute,$sData) - { - $this->xml .= ""; - $this->xml .= "$sTarget"; - $this->xml .= ""; - $this->xml .= ""; - } - - // addPrepend() adds an prepend command message to your xml response - // $sTarget is a string containing the id of an HTML element - // $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.) - // $sData is the data you want to prepend to the beginning of the attribute - // usage: $objResponse->addPrepend("contentDiv","innerHTML","Some Text"); - function addPrepend($sTarget,$sAttribute,$sData) - { - $this->xml .= ""; - $this->xml .= "$sTarget"; - $this->xml .= ""; - $this->xml .= ""; - } - - // addReplace() adds an replace command message to your xml response - // $sTarget is a string containing the id of an HTML element - // $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.) - // $sSearch is a string to search for - // $sData is a string to replace the search string when found in the attribute - // usage: $objResponse->addReplace("contentDiv","innerHTML","text","text"); - function addReplace($sTarget,$sAttribute,$sSearch,$sData) - { - $this->xml .= ""; - $this->xml .= "$sTarget"; - $this->xml .= ""; - $this->xml .= ""; - $this->xml .= ""; - } - - // addClear() adds an clear command message to your xml response - // $sTarget is a string containing the id of an HTML element - // $sAttribute is the part of the element you wish to clear ("innerHTML", "value", etc.) - // usage: $objResponse->addClear("contentDiv","innerHTML"); - function addClear($sTarget,$sAttribute) - { - $this->xml .= ""; - $this->xml .= "$sTarget"; - $this->xml .= ""; - } - - // addAlert() adds an alert command message to your xml response - // $sMsg is a text to be displayed in the alert box - // usage: $objResponse->addAlert("This is some text"); - function addAlert($sMsg) - { - $this->xml .= ""; - } - - // addScript() adds a jscript command message to your xml response - // $sJS is a string containing javascript code to be executed - // usage: $objResponse->addAlert("var x = prompt('get some text');"); - function addScript($sJS) - { - $this->xml .= ""; - } - - // addRemove() adds a Remove Element command message to your xml response - // $sTarget is a string containing the id of an HTML element to be removed - // from your page - // usage: $objResponse->addRemove("Div2"); - function addRemove($sTarget) - { - $this->xml .= ""; - $this->xml .= "$sTarget"; - $this->xml .= ""; - } - - function addCreate($sParent, $sTag, $sId, $sType="") - { - $this->xml .= ""; - $this->xml .= "$sParent"; - $this->xml .= ""; - if ($sType != "") - $this->xml .= ""; - $this->xml .= ""; - } - - // getXML() returns the xml to be returned from your function to the xajax - // processor on your page - // usage: $objResponse->getXML(); - function getXML() - { - if (strstr($this->xml,"") == false) - $this->xml .= ""; - - return $this->xml; - } -}// end class xajaxResponse - -// Communication Method Defines -if (!defined ('GET')) -{ - define ('GET', 0); -} -if (!defined ('POST')) -{ - define ('POST', 1); + define ('XAJAX_DEFAULT_CHAR_ENCODING', 'utf-8' ); } -// the xajax class generates the xajax javascript for your page including the -// javascript wrappers for the PHP functions that you want to call from your page. -// It also handles processing and executing the command messages in the xml responses -// sent back to your page from your PHP functions. +require_once(dirname(__FILE__)."/xajaxResponse.inc.php"); + +/** + * Communication Method Defines + */ +if (!defined ('XAJAX_GET')) +{ + define ('XAJAX_GET', 0); +} +if (!defined ('XAJAX_POST')) +{ + define ('XAJAX_POST', 1); +} + +/** + * The xajax class generates the xajax javascript for your page including the + * Javascript wrappers for the PHP functions that you want to call from your page. + * It also handles processing and executing the command messages in the XML responses + * sent back to your page from your PHP functions. + * + * @package xajax + */ class xajax { - var $aFunctions; // Array of PHP functions that will be callable through javascript wrappers - var $aFunctionRequestTypes; // Array of RequestTypes to be used with each function (key=function name) - var $sRequestURI; // The URI for making requests to the xajax object - var $bDebug; // Show debug messages true/false - var $sWrapperPrefix; // The prefix to prepend to the javascript wraper function name - var $bStatusMessages; // Show debug messages true/false - var $aObjArray; // Array for parsing complex objects - var $iPos; // Position in $aObjArray + /**#@+ + * @access protected + */ + /** + * @var array Array of PHP functions that will be callable through javascript wrappers + */ + var $aFunctions; + /** + * @var array Array of object callbacks that will allow Javascript to call PHP methods (key=function name) + */ + var $aObjects; + /** + * @var array Array of RequestTypes to be used with each function (key=function name) + */ + var $aFunctionRequestTypes; + /** + * @var array Array of Include Files for any external functions (key=function name) + */ + var $aFunctionIncludeFiles; + /** + * @var string Name of the PHP function to call if no callable function was found + */ + var $sCatchAllFunction; + /** + * @var string Name of the PHP function to call before any other function + */ + var $sPreFunction; + /** + * @var string The URI for making requests to the xajax object + */ + var $sRequestURI; + /** + * @var string The prefix to prepend to the javascript wraper function name + */ + var $sWrapperPrefix; + /** + * @var boolean Show debug messages (default false) + */ + var $bDebug; + /** + * @var boolean Show messages in the client browser's status bar (default false) + */ + var $bStatusMessages; + /** + * @var boolean Allow xajax to exit after processing a request (default true) + */ + var $bExitAllowed; + /** + * @var boolean Use wait cursor in browser (default true) + */ + var $bWaitCursor; + /** + * @var boolean Use an special xajax error handler so the errors are sent to the browser properly (default false) + */ + var $bErrorHandler; + /** + * @var string Specify what, if any, file xajax should log errors to (and more information in a future release) + */ + var $sLogFile; + /** + * @var boolean Clean all output buffers before outputting response (default false) + */ + var $bCleanBuffer; + /** + * @var string String containing the character encoding used + */ + var $sEncoding; + /** + * @var boolean Decode input request args from UTF-8 (default false) + */ + var $bDecodeUTF8Input; + /** + * @var boolean Convert special characters to HTML entities (default false) + */ + var $bOutputEntities; + /** + * @var array Array for parsing complex objects + */ + var $aObjArray; + /** + * @var integer Position in $aObjArray + */ + var $iPos; - // Contructor - // $sRequestURI - defaults to the current page - // $bDebug Mode - defaults to false - // $sWrapperPrefix - defaults to "xajax_"; - // usage: $xajax = new xajax(); - function xajax($sRequestURI="",$sWrapperPrefix="xajax_",$bDebug=false) + /**#@-*/ + + /** + * Constructor. You can set some extra xajax options right away or use + * individual methods later to set options. + * + * @param string defaults to the current browser URI + * @param string defaults to "xajax_"; + * @param string defaults to XAJAX_DEFAULT_CHAR_ENCODING defined above + * @param boolean defaults to false + */ + function xajax($sRequestURI="",$sWrapperPrefix="xajax_",$sEncoding=XAJAX_DEFAULT_CHAR_ENCODING,$bDebug=false) { $this->aFunctions = array(); + $this->aObjects = array(); + $this->aFunctionIncludeFiles = array(); $this->sRequestURI = $sRequestURI; if ($this->sRequestURI == "") - $this->sRequestURI = $this->detectURI(); + $this->sRequestURI = $this->_detectURI(); $this->sWrapperPrefix = $sWrapperPrefix; $this->bDebug = $bDebug; + $this->bStatusMessages = false; + $this->bWaitCursor = true; + $this->bExitAllowed = true; + $this->bErrorHandler = false; + $this->sLogFile = ""; + $this->bCleanBuffer = false; + $this->setCharEncoding($sEncoding); + $this->bDecodeUTF8Input = false; + $this->bOutputEntities = false; } - - // detectURL() returns the current URL based upon the SERVER vars - // used internally - function detectURI() - { - $aUri = array(); - - if (!empty($_SERVER['REQUEST_URI'])) - { - $aUri = parse_url($_SERVER['REQUEST_URI']); - } - - if (empty($aUri['scheme'])) - { - if (!empty($_SERVER['HTTP_SCHEME'])) - { - $aUri['scheme'] = $_SERVER['HTTP_SCHEME']; - } - else - { - $aUri['scheme'] = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http'; - } - - if (!empty($_SERVER['HTTP_HOST'])) - { - if (strpos($_SERVER['HTTP_HOST'], ':') > 0) - { - list($aUri['host'], $aUri['port']) = explode(':', $_SERVER['HTTP_HOST']); - } - else - { - $aUri['host'] = $_SERVER['HTTP_HOST']; - } - } - else if (!empty($_SERVER['SERVER_NAME'])) - { - $aUri['host'] = $_SERVER['SERVER_NAME']; - } - else - { - print "xajax Error: xajax failed to automatically identify your Request URI."; - print "Please set the Request URI explicitly when you instantiate the xajax object."; - exit(); - } - - if (empty($aUri['port']) && !empty($_SERVER['SERVER_PORT'])) - { - $aUri['port'] = $_SERVER['SERVER_PORT']; - } - - if (empty($aUri['path'])) - { - if (!empty($_SERVER['PATH_INFO'])) - { - $path = parse_url($_SERVER['PATH_INFO']); - } - else - { - $path = parse_url($_SERVER['PHP_SELF']); - } - $aUri['path'] = $path['path']; - unset($path); - } - } - - $sUri = $aUri['scheme'] . '://'; - if (!empty($aUri['user'])) - { - $sUri .= $aUri['user']; - if (!empty($aUri['pass'])) - { - $sUri .= ':' . $aUri['pass']; - } - $sUri .= '@'; - } - - $sUri .= $aUri['host']; - - if (!empty($aUri['port']) && (($aUri['scheme'] == 'http' && $aUri['port'] != 80) || ($aUri['scheme'] == 'https' && $aUri['port'] != 443))) - { - $sUri .= ':'.$aUri['port']; - } - // And finally path, without script name - $sUri .= substr($aUri['path'], 0, strrpos($aUri['path'], '/') + 1); - - unset($aUri); - - return $sUri.basename($_SERVER['SCRIPT_NAME']); - } - - // setRequestURI() sets the URI to which requests will be made - // usage: $xajax->setRequestURI("http://xajax.sourceforge.net"); + + /** + * Sets the URI to which requests will be made. + * Usage: $xajax->setRequestURI("http://www.xajaxproject.org"); + * + * @param string the URI (can be absolute or relative) of the PHP script + * that will be accessed when an xajax request occurs + */ function setRequestURI($sRequestURI) { $this->sRequestURI = $sRequestURI; } - - // debugOn() enables debug messages for xajax - // usage: $xajax->debugOn(); - function debugOn() - { - $this->bDebug = true; - } - - // debugOff() disables debug messages for xajax - // usage: $xajax->debugOff(); - function debugOff() - { - $this->bDebug = false; - } - - // statusMessagesOn() enables messages in the statusbar for xajax - // usage: $xajax->statusMessagesOn(); - function statusMessagesOn() - { - $this->bStatusMessages = true; - } - - // statusMessagesOff() disables messages in the statusbar for xajax - // usage: $xajax->statusMessagesOff(); - function statusMessagesOff() - { - $this->bStatusMessages = false; - } - - // setWrapperPrefix() sets the prefix that will be appended to the javascript - // wraper functions. + + /** + * Sets the prefix that will be appended to the Javascript wrapper + * functions (default is "xajax_"). + * + * @param string + */ + // function setWrapperPrefix($sPrefix) { $this->sWrapperPrefix = $sPrefix; } - //Dpericated. Use registerFunction(); - function addFunction($sFunction,$sRequestType=POST) + /** + * Enables debug messages for xajax. + * */ + function debugOn() { - trigger_error("xajax: the addFunction() method has been renamed registerFunction().
Please use ->registerFunction('$sFunction'".($sRequestType==GET?",GET":"")."); instead.",E_USER_WARNING); - $this->registerFunction($sFunction,$sRequestType); + $this->bDebug = true; } - // registerFunction() registers a PHP function to be callable through xajax - // $sFunction is a string containing the function name - // $sRequestType is the RequestType (GET/POST) that should be used - // for this function. Defaults to POST. - // usage: $xajax->registerFunction("myfunction",POST); - function registerFunction($sFunction,$sRequestType=POST) + /** + * Disables debug messages for xajax (default behavior). + */ + function debugOff() { - $this->aFunctions[] = $sFunction; - $this->aFunctionRequestTypes[$sFunction] = $sRequestType; + $this->bDebug = false; + } + + /** + * Enables messages in the browser's status bar for xajax. + */ + function statusMessagesOn() + { + $this->bStatusMessages = true; } - // generates the javascript wrapper for the specified PHP function - // used internally - function wrap($sFunction,$sRequestType=POST) + /** + * Disables messages in the browser's status bar for xajax (default behavior). + */ + function statusMessagesOff() { - $js = "function ".$this->sWrapperPrefix."$sFunction(){xajax.call(\"$sFunction\", arguments, ".$sRequestType.");}\n"; - return $js; + $this->bStatusMessages = false; } - // processRequests() is the main communications engine of xajax - // The engine handles all incoming xajax requests, calls the apporiate PHP functions - // and passes the xml responses back to the javascript response handler - // if your RequestURI is the same as your web page then this function should - // be called before any headers or html has been sent. - // usage: $xajax->processRequests() + /** + * Enables the wait cursor to be displayed in the browser (default behavior). + */ + function waitCursorOn() + { + $this->bWaitCursor = true; + } + + /** + * Disables the wait cursor to be displayed in the browser. + */ + function waitCursorOff() + { + $this->bWaitCursor = false; + } + + /** + * Enables xajax to exit immediately after processing a request and + * sending the response back to the browser (default behavior). + */ + function exitAllowedOn() + { + $this->bExitAllowed = true; + } + + /** + * Disables xajax's default behavior of exiting immediately after + * processing a request and sending the response back to the browser. + */ + function exitAllowedOff() + { + $this->bExitAllowed = false; + } + + /** + * Turns on xajax's error handling system so that PHP errors that occur + * during a request are trapped and pushed to the browser in the form of + * a Javascript alert. + */ + function errorHandlerOn() + { + $this->bErrorHandler = true; + } + + /** + * Turns off xajax's error handling system (default behavior). + */ + function errorHandlerOff() + { + $this->bErrorHandler = false; + } + + /** + * Specifies a log file that will be written to by xajax during a request + * (used only by the error handling system at present). If you don't invoke + * this method, or you pass in "", then no log file will be written to. + * Usage: $xajax->setLogFile("/xajax_logs/errors.log"); + */ + function setLogFile($sFilename) + { + $this->sLogFile = $sFilename; + } + + /** + * Causes xajax to clean out all output buffers before outputting a + * response (default behavior). + */ + function cleanBufferOn() + { + $this->bCleanBuffer = true; + } + /** + * Turns off xajax's output buffer cleaning. + */ + function cleanBufferOff() + { + $this->bCleanBuffer = false; + } + + /** + * Sets the character encoding for the HTTP output based on + * $sEncoding, which is a string containing the character + * encoding to use. You don't need to use this method normally, since the + * character encoding for the response gets set automatically based on the + * XAJAX_DEFAULT_CHAR_ENCODING constant. + * Usage: $xajax->setCharEncoding("utf-8"); + * + * @param string the encoding type to use (utf-8, iso-8859-1, etc.) + */ + function setCharEncoding($sEncoding) + { + $this->sEncoding = $sEncoding; + } + + /** + * Causes xajax to decode the input request args from UTF-8 to the current + * encoding if possible. Either the iconv or mb_string extension must be + * present for optimal functionality. + */ + function decodeUTF8InputOn() + { + $this->bDecodeUTF8Input = true; + } + + /** + * Turns off decoding the input request args from UTF-8 (default behavior). + */ + function decodeUTF8InputOff() + { + $this->bDecodeUTF8Input = false; + } + + /** + * Tells the response object to convert special characters to HTML entities + * automatically (only works if the mb_string extension is available). + */ + function outputEntitiesOn() + { + $this->bOutputEntities = true; + } + + /** + * Tells the response object to output special characters intact. (default + * behavior). + */ + function outputEntitiesOff() + { + $this->bOutputEntities = false; + } + + /** + * Registers a PHP function or method to be callable through xajax in your + * Javascript. If you want to register a function, pass in the name of that + * function. If you want to register a static class method, pass in an + * array like so: + * array("myFunctionName", "myClass", "myMethod") + * For an object instance method, use an object variable for the second + * array element (and in PHP 4 make sure you put an & before the variable + * to pass the object by reference). Note: the function name is what you + * call via Javascript, so it can be anything as long as it doesn't + * conflict with any other registered function name. + * + * Usage: $xajax->registerFunction("myFunction"); + * or: $xajax->registerFunction(array("myFunctionName", &$myObject, "myMethod")); + * + * @param mixed contains the function name or an object callback array + * @param mixed request type (XAJAX_GET/XAJAX_POST) that should be used + * for this function. Defaults to XAJAX_POST. + */ + function registerFunction($mFunction,$sRequestType=XAJAX_POST) + { + if (is_array($mFunction)) { + $this->aFunctions[$mFunction[0]] = 1; + $this->aFunctionRequestTypes[$mFunction[0]] = $sRequestType; + $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1); + } + else { + $this->aFunctions[$mFunction] = 1; + $this->aFunctionRequestTypes[$mFunction] = $sRequestType; + } + } + + /** + * Registers a PHP function to be callable through xajax which is located + * in some other file. If the function is requested the external file will + * be included to define the function before the function is called. + * + * Usage: $xajax->registerExternalFunction("myFunction","myFunction.inc.php",XAJAX_POST); + * + * @param string contains the function name or an object callback array + * ({@link xajax::registerFunction() see registerFunction} for + * more info on object callback arrays) + * @param string contains the path and filename of the include file + * @param mixed the RequestType (XAJAX_GET/XAJAX_POST) that should be used + * for this function. Defaults to XAJAX_POST. + */ + function registerExternalFunction($mFunction,$sIncludeFile,$sRequestType=XAJAX_POST) + { + $this->registerFunction($mFunction, $sRequestType); + + if (is_array($mFunction)) { + $this->aFunctionIncludeFiles[$mFunction[0]] = $sIncludeFile; + } + else { + $this->aFunctionIncludeFiles[$mFunction] = $sIncludeFile; + } + } + + /** + * Registers a PHP function to be called when xajax cannot find the + * function being called via Javascript. Because this is technically + * impossible when using "wrapped" functions, the catch-all feature is + * only useful when you're directly using the xajax.call() Javascript + * method. Use the catch-all feature when you want more dynamic ability to + * intercept unknown calls and handle them in a custom way. + * + * Usage: $xajax->registerCatchAllFunction("myCatchAllFunction"); + * + * @param string contains the function name or an object callback array + * ({@link xajax::registerFunction() see registerFunction} for + * more info on object callback arrays) + */ + function registerCatchAllFunction($mFunction) + { + if (is_array($mFunction)) { + $this->sCatchAllFunction = $mFunction[0]; + $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1); + } + else { + $this->sCatchAllFunction = $mFunction; + } + } + + /** + * Registers a PHP function to be called before xajax calls the requested + * function. xajax will automatically add the request function's response + * to the pre-function's response to create a single response. Another + * feature is the ability to return not just a response, but an array with + * the first element being false (a boolean) and the second being the + * response. In this case, the pre-function's response will be returned to + * the browser without xajax calling the requested function. + * + * Usage: $xajax->registerPreFunction("myPreFunction"); + * + * @param string contains the function name or an object callback array + * ({@link xajax::registerFunction() see registerFunction} for + * more info on object callback arrays) + */ + function registerPreFunction($mFunction) + { + if (is_array($mFunction)) { + $this->sPreFunction = $mFunction[0]; + $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1); + } + else { + $this->sPreFunction = $mFunction; + } + } + + /** + * Returns true if xajax can process the request, false if otherwise. + * You can use this to determine if xajax needs to process the request or + * not. + * + * @return boolean + */ + function canProcessRequests() + { + if ($this->getRequestMode() != -1) return true; + return false; + } + + /** + * Returns the current request mode (XAJAX_GET or XAJAX_POST), or -1 if + * there is none. + * + * @return mixed + */ + function getRequestMode() + { + if (!empty($_GET["xajax"])) + return XAJAX_GET; + + if (!empty($_POST["xajax"])) + return XAJAX_POST; + + return -1; + } + + /** + * This is the main communications engine of xajax. The engine handles all + * incoming xajax requests, calls the apporiate PHP functions (or + * class/object methods) and passes the XML responses back to the + * Javascript response handler. If your RequestURI is the same as your Web + * page then this function should be called before any headers or HTML has + * been sent. + */ function processRequests() { - if (!empty($_GET['xajaxjs'])) - { - header("Content-type: text/javascript"); - print $this->generateJavascript(); - exit(); - return; - } $requestMode = -1; $sFunctionName = ""; + $bFoundFunction = true; + $bFunctionIsCatchAll = false; + $sFunctionNameForSpecial = ""; $aArgs = array(); + $sPreResponse = ""; + $bEndRequest = false; $sResponse = ""; - if (!empty($_GET["xajax"])) - $requestMode = GET; - - if (!empty($_POST["xajax"])) - $requestMode = POST; - - if ($requestMode == -1) - return; + $requestMode = $this->getRequestMode(); + if ($requestMode == -1) return; - if ($requestMode == POST) + if ($requestMode == XAJAX_POST) { $sFunctionName = $_POST["xajax"]; @@ -405,7 +552,6 @@ class xajax header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header ("Cache-Control: no-cache, must-revalidate"); header ("Pragma: no-cache"); - header("Content-type: text/xml"); $sFunctionName = $_GET["xajax"]; @@ -413,45 +559,471 @@ class xajax $aArgs = $_GET["xajaxargs"]; } - if (!in_array($sFunctionName, $this->aFunctions)) - { - $objResponse = new xajaxResponse(); - $objResponse->addAlert("Unknown Function $sFunctionName."); - $sResponse = $objResponse->getXML(); + // Use xajax error handler if necessary + if ($this->bErrorHandler) { + $GLOBALS['xajaxErrorHandlerText'] = ""; + set_error_handler("xajaxErrorHandler"); } - else if ($this->aFunctionRequestTypes[$sFunctionName] != $requestMode) - { - $objResponse = new xajaxResponse(); - $objResponse->addAlert("Incorrect Request Type."); - $sResponse = $objResponse->getXML(); + + if ($this->sPreFunction) { + if (!$this->_isFunctionCallable($this->sPreFunction)) { + $bFoundFunction = false; + $objResponse = new xajaxResponse(); + $objResponse->addAlert("Unknown Pre-Function ". $this->sPreFunction); + $sResponse = $objResponse->getXML(); + } } - else + //include any external dependencies associated with this function name + if (array_key_exists($sFunctionName,$this->aFunctionIncludeFiles)) + { + ob_start(); + include_once($this->aFunctionIncludeFiles[$sFunctionName]); + ob_end_clean(); + } + + if ($bFoundFunction) { + $sFunctionNameForSpecial = $sFunctionName; + if (!array_key_exists($sFunctionName, $this->aFunctions)) + { + if ($this->sCatchAllFunction) { + $sFunctionName = $this->sCatchAllFunction; + $bFunctionIsCatchAll = true; + } + else { + $bFoundFunction = false; + $objResponse = new xajaxResponse(); + $objResponse->addAlert("Unknown Function $sFunctionName."); + $sResponse = $objResponse->getXML(); + } + } + else if ($this->aFunctionRequestTypes[$sFunctionName] != $requestMode) + { + $bFoundFunction = false; + $objResponse = new xajaxResponse(); + $objResponse->addAlert("Incorrect Request Type."); + $sResponse = $objResponse->getXML(); + } + } + + if ($bFoundFunction) { for ($i = 0; $i < sizeof($aArgs); $i++) { + // If magic quotes is on, then we need to strip the slashes from the args + if (get_magic_quotes_gpc() == 1 && is_string($aArgs[$i])) { + + $aArgs[$i] = stripslashes($aArgs[$i]); + } if (stristr($aArgs[$i],"") != false) { - $aArgs[$i] = $this->xmlToArray("xjxobj",$aArgs[$i]); + $aArgs[$i] = $this->_xmlToArray("xjxobj",$aArgs[$i]); } else if (stristr($aArgs[$i],"") != false) { - $aArgs[$i] = $this->xmlToArray("xjxquery",$aArgs[$i]); + $aArgs[$i] = $this->_xmlToArray("xjxquery",$aArgs[$i]); + } + else if ($this->bDecodeUTF8Input) + { + $aArgs[$i] = $this->_decodeUTF8Data($aArgs[$i]); + } + } + + if ($this->sPreFunction) { + $mPreResponse = $this->_callFunction($this->sPreFunction, array($sFunctionNameForSpecial, $aArgs)); + if (is_array($mPreResponse) && $mPreResponse[0] === false) { + $bEndRequest = true; + $sPreResponse = $mPreResponse[1]; + } + else { + $sPreResponse = $mPreResponse; + } + if (is_a($sPreResponse, "xajaxResponse")) { + $sPreResponse = $sPreResponse->getXML(); + } + if ($bEndRequest) $sResponse = $sPreResponse; + } + + if (!$bEndRequest) { + if (!$this->_isFunctionCallable($sFunctionName)) { + $objResponse = new xajaxResponse(); + $objResponse->addAlert("The Registered Function $sFunctionName Could Not Be Found."); + $sResponse = $objResponse->getXML(); + } + else { + if ($bFunctionIsCatchAll) { + $aArgs = array($sFunctionNameForSpecial, $aArgs); + } + $sResponse = $this->_callFunction($sFunctionName, $aArgs); + } + if (is_a($sResponse, "xajaxResponse")) { + $sResponse = $sResponse->getXML(); + } + if (!is_string($sResponse) || strpos($sResponse, "") === FALSE) { + $objResponse = new xajaxResponse(); + $objResponse->addAlert("No XML Response Was Returned By Function $sFunctionName."); + $sResponse = $objResponse->getXML(); + } + else if ($sPreResponse != "") { + $sNewResponse = new xajaxResponse($this->sEncoding, $this->bOutputEntities); + $sNewResponse->loadXML($sPreResponse); + $sNewResponse->loadXML($sResponse); + $sResponse = $sNewResponse->getXML(); } } - $sResponse = call_user_func_array($sFunctionName, $aArgs); } - header("Content-type: text/xml; charset=$this->charset"); + $sContentHeader = "Content-type: text/xml;"; + if ($this->sEncoding && strlen(trim($this->sEncoding)) > 0) + $sContentHeader .= " charset=".$this->sEncoding; + header($sContentHeader); + if ($this->bErrorHandler && !empty( $GLOBALS['xajaxErrorHandlerText'] )) { + $sErrorResponse = new xajaxResponse(); + $sErrorResponse->addAlert("** PHP Error Messages: **" . $GLOBALS['xajaxErrorHandlerText']); + if ($this->sLogFile) { + $fH = @fopen($this->sLogFile, "a"); + if (!$fH) { + $sErrorResponse->addAlert("** Logging Error **\n\nxajax was unable to write to the error log file:\n" . $this->sLogFile); + } + else { + fwrite($fH, "** xajax Error Log - " . strftime("%b %e %Y %I:%M:%S %p") . " **" . $GLOBALS['xajaxErrorHandlerText'] . "\n\n\n"); + fclose($fH); + } + } + + $sErrorResponse->loadXML($sResponse); + $sResponse = $sErrorResponse->getXML(); + + } + if ($this->bCleanBuffer) while (@ob_end_clean()); print $sResponse; + if ($this->bErrorHandler) restore_error_handler(); - exit(); + if ($this->bExitAllowed) + exit(); + } + + /** + * Prints the xajax Javascript header and wrapper code into your page by + * printing the output of the getJavascript() method. It should only be + * called between the
 
tags in your HTML page. + * Remember, if you only want to obtain the result of this function, use + * {@link xajax::getJavascript()} instead. + * + * Usage: + * + * + * ... + * < ?php $xajax->printJavascript(); ? > + * + * + * @param string the relative address of the folder where xajax has been + * installed. For instance, if your PHP file is + * "http://www.myserver.com/myfolder/mypage.php" + * and xajax was installed in + * "http://www.myserver.com/anotherfolder", then $sJsURI + * should be set to "../anotherfolder". Defaults to assuming + * xajax is in the same folder as your PHP file. + * @param string the relative folder/file pair of the xajax Javascript + * engine located within the xajax installation folder. + * Defaults to xajax_js/xajax.js. + */ + function printJavascript($sJsURI="", $sJsFile=NULL) + { + print $this->getJavascript($sJsURI, $sJsFile); } - // xmlToArray() takes a string containing xajax xjxobj xml or xjxquery xml - // and builds an array representation of it to pass as an argument to - // the php function being called. Returns an array. - // used internally - function xmlToArray($rootTag, $sXml) + /** + * Returns the xajax Javascript code that should be added to your HTML page + * between the tags. + * + * Usage: + * + * < ?php $xajaxJSHead = $xajax->getJavascript(); ? > + * + * ... + * < ?php echo $xajaxJSHead; ? > + * + * + * @param string the relative address of the folder where xajax has been + * installed. For instance, if your PHP file is + * "http://www.myserver.com/myfolder/mypage.php" + * and xajax was installed in + * "http://www.myserver.com/anotherfolder", then $sJsURI + * should be set to "../anotherfolder". Defaults to assuming + * xajax is in the same folder as your PHP file. + * @param string the relative folder/file pair of the xajax Javascript + * engine located within the xajax installation folder. + * Defaults to xajax_js/xajax.js. + * @return string + */ + function getJavascript($sJsURI="", $sJsFile=NULL) + { + $html = $this->getJavascriptConfig(); + $html .= $this->getJavascriptInclude($sJsURI, $sJsFile); + + return $html; + } + + /** + * Returns a string containing inline Javascript that sets up the xajax + * runtime (typically called internally by xajax from get/printJavascript). + * + * @return string + */ + function getJavascriptConfig() + { + $html = "\t\n"; + return $html; + } + + /** + * Returns a string containing a Javascript include of the xajax.js file + * along with a check to see if the file loaded after six seconds + * (typically called internally by xajax from get/printJavascript). + * + * @param string the relative address of the folder where xajax has been + * installed. For instance, if your PHP file is + * "http://www.myserver.com/myfolder/mypage.php" + * and xajax was installed in + * "http://www.myserver.com/anotherfolder", then $sJsURI + * should be set to "../anotherfolder". Defaults to assuming + * xajax is in the same folder as your PHP file. + * @param string the relative folder/file pair of the xajax Javascript + * engine located within the xajax installation folder. + * Defaults to xajax_js/xajax.js. + * @return string + */ + function getJavascriptInclude($sJsURI="", $sJsFile=NULL) + { + if ($sJsFile == NULL) $sJsFile = "xajax_js/xajax.js"; + + if ($sJsURI != "" && substr($sJsURI, -1) != "/") $sJsURI .= "/"; + + $html = "\t\n"; + $html .= "\t\n"; + return $html; + } + + /** + * This method can be used to create a new xajax.js file out of the + * xajax_uncompressed.js file (which will only happen if xajax.js doesn't + * already exist on the filesystem). + * + * @param string an optional argument containing the full server file path + * of xajax.js. + */ + function autoCompressJavascript($sJsFullFilename=NULL) + { + $sJsFile = "xajax_js/xajax.js"; + + if ($sJsFullFilename) { + $realJsFile = $sJsFullFilename; + } + else { + $realPath = realpath(dirname(__FILE__)); + $realJsFile = $realPath . "/". $sJsFile; + } + + // Create a compressed file if necessary + if (!file_exists($realJsFile)) { + $srcFile = str_replace(".js", "_uncompressed.js", $realJsFile); + if (!file_exists($srcFile)) { + trigger_error("The xajax uncompressed Javascript file could not be found in the " . dirname($realJsFile) . " folder. Error ", E_USER_ERROR); + } + require(dirname(__FILE__)."/xajaxCompress.php"); + $javaScript = implode('', file($srcFile)); + $compressedScript = xajaxCompressJavascript($javaScript); + $fH = @fopen($realJsFile, "w"); + if (!$fH) { + trigger_error("The xajax compressed javascript file could not be written in the " . dirname($realJsFile) . " folder. Error ", E_USER_ERROR); + } + else { + fwrite($fH, $compressedScript); + fclose($fH); + } + } + } + + /** + * Returns the current URL based upon the SERVER vars. + * + * @access private + * @return string + */ + function _detectURI() { + $aURL = array(); + + // Try to get the request URL + if (!empty($_SERVER['REQUEST_URI'])) { + $aURL = parse_url($_SERVER['REQUEST_URI']); + } + + // Fill in the empty values + if (empty($aURL['scheme'])) { + if (!empty($_SERVER['HTTP_SCHEME'])) { + $aURL['scheme'] = $_SERVER['HTTP_SCHEME']; + } else { + $aURL['scheme'] = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http'; + } + } + + if (empty($aURL['host'])) { + if (!empty($_SERVER['HTTP_HOST'])) { + if (strpos($_SERVER['HTTP_HOST'], ':') > 0) { + list($aURL['host'], $aURL['port']) = explode(':', $_SERVER['HTTP_HOST']); + } else { + $aURL['host'] = $_SERVER['HTTP_HOST']; + } + } else if (!empty($_SERVER['SERVER_NAME'])) { + $aURL['host'] = $_SERVER['SERVER_NAME']; + } else { + print "xajax Error: xajax failed to automatically identify your Request URI."; + print "Please set the Request URI explicitly when you instantiate the xajax object."; + exit(); + } + } + + if (empty($aURL['port']) && !empty($_SERVER['SERVER_PORT'])) { + $aURL['port'] = $_SERVER['SERVER_PORT']; + } + + if (empty($aURL['path'])) { + if (!empty($_SERVER['PATH_INFO'])) { + $sPath = parse_url($_SERVER['PATH_INFO']); + } else { + $sPath = parse_url($_SERVER['PHP_SELF']); + } + $aURL['path'] = $sPath['path']; + unset($sPath); + } + + if (!empty($aURL['query'])) { + $aURL['query'] = '?'.$aURL['query']; + } + + // Build the URL: Start with scheme, user and pass + $sURL = $aURL['scheme'].'://'; + if (!empty($aURL['user'])) { + $sURL.= $aURL['user']; + if (!empty($aURL['pass'])) { + $sURL.= ':'.$aURL['pass']; + } + $sURL.= '@'; + } + + // Add the host + $sURL.= $aURL['host']; + + // Add the port if needed + if (!empty($aURL['port']) && (($aURL['scheme'] == 'http' && $aURL['port'] != 80) || ($aURL['scheme'] == 'https' && $aURL['port'] != 443))) { + $sURL.= ':'.$aURL['port']; + } + + // Add the path and the query string + $sURL.= $aURL['path'].@$aURL['query']; + + // Clean up + unset($aURL); + return $sURL; + } + + /** + * Returns true if the function name is associated with an object callback, + * false if not. + * + * @param string the name of the function + * @access private + * @return boolean + */ + function _isObjectCallback($sFunction) + { + if (array_key_exists($sFunction, $this->aObjects)) return true; + return false; + } + + /** + * Returns true if the function or object callback can be called, false if + * not. + * + * @param string the name of the function + * @access private + * @return boolean + */ + function _isFunctionCallable($sFunction) + { + if ($this->_isObjectCallback($sFunction)) { + if (is_object($this->aObjects[$sFunction][0])) { + return method_exists($this->aObjects[$sFunction][0], $this->aObjects[$sFunction][1]); + } + else { + return is_callable($this->aObjects[$sFunction]); + } + } + else { + return function_exists($sFunction); + } + } + + /** + * Calls the function, class method, or object method with the supplied + * arguments. + * + * @param string the name of the function + * @param array arguments to pass to the function + * @access private + * @return mixed the output of the called function or method + */ + function _callFunction($sFunction, $aArgs) + { + if ($this->_isObjectCallback($sFunction)) { + $mReturn = call_user_func_array($this->aObjects[$sFunction], $aArgs); + } + else { + $mReturn = call_user_func_array($sFunction, $aArgs); + } + return $mReturn; + } + + /** + * Generates the Javascript wrapper for the specified PHP function. + * + * @param string the name of the function + * @param mixed the request type + * @access private + * @return string + */ + function _wrap($sFunction,$sRequestType=XAJAX_POST) + { + $js = "function ".$this->sWrapperPrefix."$sFunction(){return xajax.call(\"$sFunction\", arguments, ".$sRequestType.");}\n"; + return $js; + } + + /** + * Takes a string containing xajax xjxobj XML or xjxquery XML and builds an + * array representation of it to pass as an argument to the PHP function + * being called. + * + * @param string the root tag of the XML + * @param string XML to convert + * @access private + * @return array + */ + function _xmlToArray($rootTag, $sXml) { $aArray = array(); $sXml = str_replace("<$rootTag>","<$rootTag>|~|",$sXml); @@ -468,15 +1040,20 @@ class xajax $this->aObjArray = explode("|~|",$sXml); $this->iPos = 0; - $aArray = $this->parseObjXml($rootTag); - + $aArray = $this->_parseObjXml($rootTag); + return $aArray; } - // parseObjXml() is a recursive function that generates an array from the - // contents of $this->aObjArray. Returns an array. - // used internally - function parseObjXml($rootTag) + /** + * A recursive function that generates an array from the contents of + * $this->aObjArray. + * + * @param string the root tag of the XML + * @access private + * @return array + */ + function _parseObjXml($rootTag) { $aArray = array(); @@ -509,18 +1086,23 @@ class xajax { if(stristr($this->aObjArray[$this->iPos],"")) { - $value = $this->parseObjXml("xjxobj"); + $value = $this->_parseObjXml("xjxobj"); $this->iPos++; } else { $value .= $this->aObjArray[$this->iPos]; + if ($this->bDecodeUTF8Input) + { + $value = $this->_decodeUTF8Data($value); + } } $this->iPos++; } } $this->iPos++; } + $aArray[$key]=$value; } } @@ -540,551 +1122,118 @@ class xajax $sQuery .= $this->aObjArray[$this->iPos]; $this->iPos++; } + parse_str($sQuery, $aArray); + if ($this->bDecodeUTF8Input) + { + foreach($aArray as $key => $value) + { + $aArray[$key] = $this->_decodeUTF8Data($value); + } + } + // If magic quotes is on, then we need to strip the slashes from the + // array values because of the parse_str pass which adds slashes + if (get_magic_quotes_gpc() == 1) { + $newArray = array(); + foreach ($aArray as $sKey => $sValue) { + if (is_string($sValue)) + $newArray[$sKey] = stripslashes($sValue); + else + $newArray[$sKey] = $sValue; + } + $aArray = $newArray; + } } return $aArray; } - // Depricated. Use printJavascript(); - function javascript($sJsURI="") + /** + * Decodes string data from UTF-8 to the current xajax encoding. + * + * @param string data to convert + * @access private + * @return string converted data + */ + function _decodeUTF8Data($sData) { - trigger_error("xajax: the javascript() method has been renamed printJavascript().
Please use ->printJavascript(".($sJsURI==""?"":"'$sJsURI'")."); instead.",E_USER_WARNING); - $this->printJavascript($sJsURI); - } - - // printJavascript() prints the xajax javascript code into your page - // it should only be called between the tags - // usage: - // - // ... - // printJavascript(); - function printJavascript($sJsURI="") - { - print $this->getJavascript($sJsURI); - } - - // getJavascript() returns the xajax javascript code that should be added to - // your page between the tags - // usage: - // - // ... - // getJavascript(); - function getJavascript($sJsURI="") - { - if ($sJsURI == "") - $sJsURI = $this->sRequestURI; - - $separator=strpos($sJsURI,'?')==false?'?':'&'; - - $html = "\n"; - $html .= "\t\n"; - - return $html; - } - - // compressJavascript() compresses the javascript code for more efficient delivery - // used internally - // $sJS is a string containing the javascript code to compress - function compressJavascript($sJS) - { - //remove windows cariage returns - $sJS = str_replace("\r","",$sJS); - - //array to store replaced literal strings - $literal_strings = array(); - - //explode the string into lines - $lines = explode("\n",$sJS); - //loop through all the lines, building a new string at the same time as removing literal strings - $clean = ""; - $inComment = false; - $literal = ""; - $inQuote = false; - $escaped = false; - $quoteChar = ""; - - for($i=0;$ibDecodeUTF8Input) { - $line = $lines[$i]; - $inNormalComment = false; - - //loop through line's characters and take out any literal strings, replace them with ___i___ where i is the index of this string - for($j=0;$jsEncoding == "ISO-8859-1") + { + $sFuncToUse = "utf8_decode"; + } + else + { + trigger_error("The incoming xajax data could not be converted from UTF-8", E_USER_NOTICE); + } + + if ($sFuncToUse) + { + if (is_string($sValue)) { - //is this character a quote or a comment - if(($c=="\"" || $c=="'") && !$inComment && !$inNormalComment) + if ($sFuncToUse == "iconv") { - $inQuote = true; - $inComment = false; - $escaped = false; - $quoteChar = $c; - $literal = $c; + $sValue = iconv("UTF-8", $this->sEncoding.'//TRANSLIT', $sValue); } - else if($d=="/*" && !$inNormalComment) + else if ($sFuncToUse == "mb_convert_encoding") { - $inQuote = false; - $inComment = true; - $escaped = false; - $quoteChar = $d; - $literal = $d; - $j++; - } - else if($d=="//") //ignore string markers that are found inside comments - { - $inNormalComment = true; - $clean .= $c; + $sValue = mb_convert_encoding($sValue, $this->sEncoding, "UTF-8"); } else { - $clean .= $c; + $sValue = utf8_decode($sValue); } } - else //allready in a string so find end quote - { - if($c == $quoteChar && !$escaped && !$inComment) - { - $inQuote = false; - $literal .= $c; - - //subsitute in a marker for the string - $clean .= "___" . count($literal_strings) . "___"; - - //push the string onto our array - array_push($literal_strings,$literal); - - } - else if($inComment && $d=="*/") - { - $inComment = false; - $literal .= $d; - - //subsitute in a marker for the string - $clean .= "___" . count($literal_strings) . "___"; - - //push the string onto our array - array_push($literal_strings,$literal); - - $j++; - } - else if($c == "\\" && !$escaped) - $escaped = true; - else - $escaped = false; - - $literal .= $c; - } } - if($inComment) $literal .= "\n"; - $clean .= "\n"; } - //explode the clean string into lines again - $lines = explode("\n",$clean); - - //now process each line at a time - for($i=0;$ibDebug){ $js .= "var xajaxDebug=".($this->bDebug?"true":"false").";\n"; } - ob_start(); - ?> - function Xajax() - { - bDebug){ ?>this.DebugMessage = function(text){if (xajaxDebug) alert("Xajax Debug:\n " + text)} - - this.workId = 'xajaxWork'+ new Date().getTime(); - this.depth = 0; - - //Get the XMLHttpRequest Object - this.getRequestObject = function() - { - bDebug){ ?>this.DebugMessage("Initializing Request Object.."); - var req; - try - { - req=new ActiveXObject("Msxml2.XMLHTTP"); - } - catch (e) - { - try - { - req=new ActiveXObject("Microsoft.XMLHTTP"); - } - catch (e2) - { - req=null; - } - } - if(!req && typeof XMLHttpRequest != "undefined") - req = new XMLHttpRequest(); - - bDebug){ ?>if (!req) this.DebugMessage("Request Object Instantiation failed."); - - return req; - } - - // xajax.$() is shorthand for document.getElementById() - this.$ = function(sId) - { - return document.getElementById(sId); - } - - // xajax.getFormValues() builds a query string XML message from the elements of a form object - this.getFormValues = function(frm) - { - var objForm; - if (typeof(frm) == "string") - objForm = this.$(frm); - else - objForm = frm; - var sXml = ""; - if (objForm && objForm.tagName == 'FORM') - { - var formElements = objForm.elements; - for( var i=0; i < formElements.length; i++) - { - if ((formElements[i].type == 'radio' || formElements[i].type == 'checkbox') && formElements[i].checked == false) - continue; - var name = formElements[i].name; - if (name) - { - if (sXml != '') - sXml += '&'; - sXml += name+"="+encodeURIComponent(formElements[i].value); - } - } - } - - sXml +=""; - - return sXml; - } - - // Generates an XML message that xajax can understand from a javascript object - this.objectToXML = function(obj) - { - var sXml = ""; - for (i in obj) - { - try - { - if (i == 'constructor') - continue; - if (obj[i] && typeof(obj[i]) == 'function') - continue; - - var key = i; - var value = obj[i]; - if (value && typeof(value)=="object" && - (value.constructor == Array - ) && this.depth <= 50) - { - this.depth++; - value = this.objectToXML(value); - this.depth--; - } - - sXml += ""+key+""+value+""; - - } - catch(e) - { - bDebug){ ?>this.DebugMessage(e); - } - } - sXml += ""; - - return sXml; - } - - // Sends a XMLHttpRequest to call the specified PHP function on the server - this.call = function(sFunction, aArgs, sRequestType) - { - var i,r,postData; - if (document.body) - document.body.style.cursor = 'wait'; - bStatusMessages == true){?>window.status = 'Sending Request...'; - bDebug){ ?>this.DebugMessage("Starting xajax..."); - var xajaxRequestType = sRequestType; - var uri = xajaxRequestUri; - var value; - switch(xajaxRequestType) - { - case :{ - var uriGet = uri.indexOf("?")==-1?"?xajax="+encodeURIComponent(sFunction):"&xajax="+encodeURIComponent(sFunction); - for (i = 0; i:{ - postData = "xajax="+encodeURIComponent(sFunction); - postData += "&xajaxr="+new Date().getTime(); - for (i = 0; i ?"GET":"POST", uri, true); - if (xajaxRequestType == ) - { - try - { - r.setRequestHeader("Method", "POST " + uri + " HTTP/1.1"); - r.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - } - catch(e) - { - alert("Your browser does not appear to support asynchronous requests using POST."); - return false; - } - } - r.onreadystatechange = function() - { - if (r.readyState != 4) - return; - - if (r.status==200) - { - bDebug){ ?>xajax.DebugMessage("Received:\n" + r.responseText); - var data = r.responseXML; - if (data) - xajax.processResponse(data); - } - } - bDebug){ ?>this.DebugMessage("Calling "+sFunction +" uri="+uri+" (post:"+ postData +")"); - r.send(postData); - bStatusMessages == true){?>window.status = 'Waiting for data...'; - bDebug){ ?>this.DebugMessage(sFunction + " waiting.."); - delete r; - return true; - } - - // Tests if the new Data is the same as the extant data - this.willChange = function(element, attribute, newData) - { - var oldData; - if (attribute == "innerHTML") - { - tmpXajax = this.$(this.workId); - if (tmpXajax == null) - { - tmpXajax = document.createElement("div"); - tmpXajax.setAttribute('id',this.workId); - tmpXajax.style.display = "none"; - tmpXajax.style.visibility = "hidden"; - document.body.appendChild(tmpXajax); - } - tmpXajax.innerHTML = newData; - newData = tmpXajax.innerHTML; - } - eval("oldData=document.getElementById('"+element+"')."+attribute); - if (newData != oldData) - return true; - - return false; - } - - //Process XML xajaxResponses returned from the request - this.processResponse = function(xml) - { - bStatusMessages == true){?> window.status = 'Recieving data...'; - var tmpXajax = null; - xml = xml.documentElement; - for (i=0; i -1) - { - x = v.indexOf(search)+search.length+1; - v2 += v.substr(0,x).replace(search,data); - v = v.substr(x,v.length-x); - } - if (this.willChange(element,attribute,v2)) - eval('document.getElementById("'+element+'").'+attribute+'=v2;'); - } - if (action=="clear") - eval("document.getElementById('"+element+"')."+attribute+"='';"); - if (action=="remove") - { - objElement = this.$(element); - if (objElement.parentNode && objElement.parentNode.removeChild) - { - objElement.parentNode.removeChild(objElement); - } - } - if (action=="create") - { - var objParent = this.$(element); - objElement = document.createElement(attribute); - objElement.setAttribute('id',data); - if (type && type != '') - objElement.setAttribute('type',type); - objParent.appendChild(objElement); - if (objParent.tagName == "FORM") - { - - } - } - } - } - document.body.style.cursor = 'default'; - bStatusMessages == true){?> window.status = 'Done'; - } - } - - var xajax = new Xajax(); - aFunctions as $sFunction) - $js .= $this->wrap($sFunction,$this->aFunctionRequestTypes[$sFunction]); - - if ($this->bDebug == false) - $js = $this->compressJavascript($js); - - print $js; - } }// end class xajax -?> + +/** + * This function is registered with PHP's set_error_handler() function if + * the xajax error handling system is turned on. + */ +function xajaxErrorHandler($errno, $errstr, $errfile, $errline) +{ + $errorReporting = error_reporting(); + if (($errno & $errorReporting) == 0) return; + + if ($errno == E_NOTICE) { + $errTypeStr = "NOTICE"; + } + else if ($errno == E_WARNING) { + $errTypeStr = "WARNING"; + } + else if ($errno == E_USER_NOTICE) { + $errTypeStr = "USER NOTICE"; + } + else if ($errno == E_USER_WARNING) { + $errTypeStr = "USER WARNING"; + } + else if ($errno == E_USER_ERROR) { + $errTypeStr = "USER FATAL ERROR"; + } + else if ($errno == E_STRICT) { + return; + } + else { + $errTypeStr = "UNKNOWN: $errno"; + } + $GLOBALS['xajaxErrorHandlerText'] .= "\n----\n[$errTypeStr] $errstr\nerror in line $errline of file $errfile"; +} + +?> \ No newline at end of file diff --git a/phpgwapi/inc/xajaxResponse.inc.php b/phpgwapi/inc/xajaxResponse.inc.php new file mode 100644 index 0000000000..1c0aeb6022 --- /dev/null +++ b/phpgwapi/inc/xajaxResponse.inc.php @@ -0,0 +1,580 @@ + + *
  • Assign - sets the specified attribute of an element in your page
  • + *
  • Append - appends data to the end of the specified attribute of an + * element in your page
  • + *
  • Prepend - prepends data to the beginning of the specified attribute of + * an element in your page
  • + *
  • Replace - searches for and replaces data in the specified attribute of + * an element in your page
  • + *
  • Script - runs the supplied JavaScript code
  • + *
  • Alert - shows an alert box with the supplied message text
  • + * + * + * Note: elements are identified by their HTML id, so if you don't see + * your browser HTML display changing from the request, make sure you're using + * the right id names in your response. + * + * @package xajax + */ +class xajaxResponse +{ + /**#@+ + * @access protected + */ + /** + * @var string internal XML storage + */ + var $xml; + /** + * @var string the encoding type to use + */ + var $sEncoding; + /** + * @var boolean if special characters in the XML should be converted to + * entities + */ + var $bOutputEntities; + + /**#@-*/ + + /** + * The constructor's main job is to set the character encoding for the + * response. + * + * Note: to change the character encoding for all of the + * responses, set the XAJAX_DEFAULT_ENCODING constant before you + * instantiate xajax. + * + * @param string contains the character encoding string to use + * @param boolean lets you set if you want special characters in the output + * converted to HTML entities + * + */ + function xajaxResponse($sEncoding=XAJAX_DEFAULT_CHAR_ENCODING, $bOutputEntities=false) + { + $this->setCharEncoding($sEncoding); + $this->bOutputEntities = $bOutputEntities; + } + + /** + * Sets the character encoding for the response based on $sEncoding, which + * is a string containing the character encoding to use. You don't need to + * use this method normally, since the character encoding for the response + * gets set automatically based on the XAJAX_DEFAULT_CHAR_ENCODING + * constant. + * + * @param string + */ + function setCharEncoding($sEncoding) + { + $this->sEncoding = $sEncoding; + } + + /** + * Tells the response object to convert special characters to HTML entities + * automatically (only works if the mb_string extension is available). + */ + function outputEntitiesOn() + { + $this->bOutputEntities = true; + } + + /** + * Tells the response object to output special characters intact. (default + * behavior) + */ + function outputEntitiesOff() + { + $this->bOutputEntities = false; + } + + /** + * Adds a confirm commands command message to the XML response. + * + * Usage: $objResponse->addConfirmCommands(1, "Do you want to preview the new data?"); + * + * @param integer the number of commands to skip if the user presses + * Cancel in the browsers's confirm dialog + * @param string the message to show in the browser's confirm dialog + */ + function addConfirmCommands($iCmdNumber, $sMessage) + { + $this->xml .= $this->_cmdXML(array("n"=>"cc","t"=>$iCmdNumber),$sMessage); + } + + /** + * Adds an assign command message to the XML response. + * + * Usage: $objResponse->addAssign("contentDiv", "innerHTML", "Some Text"); + * + * @param string contains the id of an HTML element + * @param string the part of the element you wish to modify ("innerHTML", + * "value", etc.) + * @param string the data you want to set the attribute to + */ + function addAssign($sTarget,$sAttribute,$sData) + { + $this->xml .= $this->_cmdXML(array("n"=>"as","t"=>$sTarget,"p"=>$sAttribute),$sData); + } + + /** + * Adds an append command message to the XML response. + * + * Usage: $objResponse->addAppend("contentDiv", "innerHTML", "Some New Text"); + * + * @param string contains the id of an HTML element + * @param string the part of the element you wish to modify ("innerHTML", + * "value", etc.) + * @param string the data you want to append to the end of the attribute + */ + function addAppend($sTarget,$sAttribute,$sData) + { + $this->xml .= $this->_cmdXML(array("n"=>"ap","t"=>$sTarget,"p"=>$sAttribute),$sData); + } + + /** + * Adds an prepend command message to the XML response. + * + * Usage: $objResponse->addPrepend("contentDiv", "innerHTML", "Some Starting Text"); + * + * @param string contains the id of an HTML element + * @param string the part of the element you wish to modify ("innerHTML", + * "value", etc.) + * @param string the data you want to prepend to the beginning of the + * attribute + */ + function addPrepend($sTarget,$sAttribute,$sData) + { + $this->xml .= $this->_cmdXML(array("n"=>"pp","t"=>$sTarget,"p"=>$sAttribute),$sData); + } + + /** + * Adds a replace command message to the XML response. + * + * Usage: $objResponse->addReplace("contentDiv", "innerHTML", "text", "text"); + * + * @param string contains the id of an HTML element + * @param string the part of the element you wish to modify ("innerHTML", + * "value", etc.) + * @param string the string to search for + * @param string the string to replace the search string when found in the + * attribute + */ + function addReplace($sTarget,$sAttribute,$sSearch,$sData) + { + $sDta = ""; + $this->xml .= $this->_cmdXML(array("n"=>"rp","t"=>$sTarget,"p"=>$sAttribute),$sDta); + } + + /** + * Adds a clear command message to the XML response. + * + * Usage: $objResponse->addClear("contentDiv", "innerHTML"); + * + * @param string contains the id of an HTML element + * @param string the part of the element you wish to clear ("innerHTML", + * "value", etc.) + */ + function addClear($sTarget,$sAttribute) + { + $this->addAssign($sTarget,$sAttribute,''); + } + + /** + * Adds an alert command message to the XML response. + * + * Usage: $objResponse->addAlert("This is important information"); + * + * @param string the text to be displayed in the Javascript alert box + */ + function addAlert($sMsg) + { + $this->xml .= $this->_cmdXML(array("n"=>"al"),$sMsg); + } + + /** + * Uses the addScript() method to add a Javascript redirect to another URL. + * + * Usage: $objResponse->addRedirect("http://www.xajaxproject.org"); + * + * @param string the URL to redirect the client browser to + */ + function addRedirect($sURL) + { + //we need to parse the query part so that the values are rawurlencode()'ed + //can't just use parse_url() cos we could be dealing with a relative URL which + // parse_url() can't deal with. + $queryStart = strpos($sURL, '?', strrpos($sURL, '/')); + if ($queryStart !== FALSE) + { + $queryStart++; + $queryEnd = strpos($sURL, '#', $queryStart); + if ($queryEnd === FALSE) + $queryEnd = strlen($sURL); + $queryPart = substr($sURL, $queryStart, $queryEnd-$queryStart); + parse_str($queryPart, $queryParts); + $newQueryPart = ""; + foreach($queryParts as $key => $value) + { + $newQueryPart .= rawurlencode($key).'='.rawurlencode($value).ini_get('arg_separator.output'); + } + $sURL = str_replace($queryPart, $newQueryPart, $sURL); + } + $this->addScript('window.location = "'.$sURL.'";'); + } + + /** + * Adds a Javascript command message to the XML response. + * + * Usage: $objResponse->addScript("var x = prompt('get some text');"); + * + * @param string contains Javascript code to be executed + */ + function addScript($sJS) + { + $this->xml .= $this->_cmdXML(array("n"=>"js"),$sJS); + } + + /** + * Adds a Javascript function call command message to the XML response. + * + * Usage: $objResponse->addScriptCall("myJSFunction", "arg 1", "arg 2", 12345); + * + * @param string $sFunc the name of a Javascript function + * @param mixed $args,... optional arguments to pass to the Javascript function + */ + function addScriptCall() { + $arguments = func_get_args(); + $sFunc = array_shift($arguments); + $sData = $this->_buildObjXml($arguments); + $this->xml .= $this->_cmdXML(array("n"=>"jc","t"=>$sFunc),$sData); + } + + /** + * Adds a remove element command message to the XML response. + * + * Usage: $objResponse->addRemove("Div2"); + * + * @param string contains the id of an HTML element to be removed + */ + function addRemove($sTarget) + { + $this->xml .= $this->_cmdXML(array("n"=>"rm","t"=>$sTarget),''); + } + + /** + * Adds a create element command message to the XML response. + * + * Usage: $objResponse->addCreate("parentDiv", "h3", "myid"); + * + * @param string contains the id of an HTML element to to which the new + * element will be appended. + * @param string the tag to be added + * @param string the id to be assigned to the new element + * @param string deprecated, use the addCreateInput() method instead + */ + function addCreate($sParent, $sTag, $sId, $sType="") + { + if ($sType) + { + trigger_error("The \$sType parameter of addCreate has been deprecated. Use the addCreateInput() method instead.", E_USER_WARNING); + return; + } + $this->xml .= $this->_cmdXML(array("n"=>"ce","t"=>$sParent,"p"=>$sId),$sTag); + } + + /** + * Adds a insert element command message to the XML response. + * + * Usage: $objResponse->addInsert("childDiv", "h3", "myid"); + * + * @param string contains the id of the child before which the new element + * will be inserted + * @param string the tag to be added + * @param string the id to be assigned to the new element + */ + function addInsert($sBefore, $sTag, $sId) + { + $this->xml .= $this->_cmdXML(array("n"=>"ie","t"=>$sBefore,"p"=>$sId),$sTag); + } + + /** + * Adds a insert element command message to the XML response. + * + * Usage: $objResponse->addInsertAfter("childDiv", "h3", "myid"); + * + * @param string contains the id of the child after which the new element + * will be inserted + * @param string the tag to be added + * @param string the id to be assigned to the new element + */ + function addInsertAfter($sAfter, $sTag, $sId) + { + $this->xml .= $this->_cmdXML(array("n"=>"ia","t"=>$sAfter,"p"=>$sId),$sTag); + } + + /** + * Adds a create input command message to the XML response. + * + * Usage: $objResponse->addCreateInput("form1", "text", "username", "input1"); + * + * @param string contains the id of an HTML element to which the new input + * will be appended + * @param string the type of input to be created (text, radio, checkbox, + * etc.) + * @param string the name to be assigned to the new input and the variable + * name when it is submitted + * @param string the id to be assigned to the new input + */ + function addCreateInput($sParent, $sType, $sName, $sId) + { + $this->xml .= $this->_cmdXML(array("n"=>"ci","t"=>$sParent,"p"=>$sId,"c"=>$sType),$sName); + } + + /** + * Adds an insert input command message to the XML response. + * + * Usage: $objResponse->addInsertInput("input5", "text", "username", "input1"); + * + * @param string contains the id of the child before which the new element + * will be inserted + * @param string the type of input to be created (text, radio, checkbox, + * etc.) + * @param string the name to be assigned to the new input and the variable + * name when it is submitted + * @param string the id to be assigned to the new input + */ + function addInsertInput($sBefore, $sType, $sName, $sId) + { + $this->xml .= $this->_cmdXML(array("n"=>"ii","t"=>$sBefore,"p"=>$sId,"c"=>$sType),$sName); + } + + /** + * Adds an insert input command message to the XML response. + * + * Usage: $objResponse->addInsertInputAfter("input7", "text", "email", "input2"); + * + * @param string contains the id of the child after which the new element + * will be inserted + * @param string the type of input to be created (text, radio, checkbox, + * etc.) + * @param string the name to be assigned to the new input and the variable + * name when it is submitted + * @param string the id to be assigned to the new input + */ + function addInsertInputAfter($sAfter, $sType, $sName, $sId) + { + $this->xml .= $this->_cmdXML(array("n"=>"iia","t"=>$sAfter,"p"=>$sId,"c"=>$sType),$sName); + } + + /** + * Adds an event command message to the XML response. + * + * Usage: $objResponse->addEvent("contentDiv", "onclick", "alert(\'Hello World\');"); + * + * @param string contains the id of an HTML element + * @param string the event you wish to set ("onclick", "onmouseover", etc.) + * @param string the Javascript string you want the event to invoke + */ + function addEvent($sTarget,$sEvent,$sScript) + { + $this->xml .= $this->_cmdXML(array("n"=>"ev","t"=>$sTarget,"p"=>$sEvent),$sScript); + } + + /** + * Adds a handler command message to the XML response. + * + * Usage: $objResponse->addHandler("contentDiv", "onclick", "content_click"); + * + * @param string contains the id of an HTML element + * @param string the event you wish to set ("onclick", "onmouseover", etc.) + * @param string the name of a Javascript function that will handle the + * event. Multiple handlers can be added for the same event + */ + function addHandler($sTarget,$sEvent,$sHandler) + { + $this->xml .= $this->_cmdXML(array("n"=>"ah","t"=>$sTarget,"p"=>$sEvent),$sHandler); + } + + /** + * Adds a remove handler command message to the XML response. + * + * Usage: $objResponse->addRemoveHandler("contentDiv", "onclick", "content_click"); + * + * @param string contains the id of an HTML element + * @param string the event you wish to remove ("onclick", "onmouseover", + * etc.) + * @param string the name of a Javascript handler function that you want to + * remove + */ + function addRemoveHandler($sTarget,$sEvent,$sHandler) + { + $this->xml .= $this->_cmdXML(array("n"=>"rh","t"=>$sTarget,"p"=>$sEvent),$sHandler); + } + + /** + * Adds an include script command message to the XML response. + * + * Usage: $objResponse->addIncludeScript("functions.js"); + * + * @param string URL of the Javascript file to include + */ + function addIncludeScript($sFileName) + { + $this->xml .= $this->_cmdXML(array("n"=>"in"),$sFileName); + } + + /** + * Returns the XML to be returned from your function to the xajax processor + * on your page. Since xajax 0.2, you can also return an xajaxResponse + * object from your function directly, and xajax will automatically request + * the XML using this method call. + * + * Usage: return $objResponse->getXML(); + * + * @return string response XML data + */ + function getXML() + { + $sXML = "sEncoding && strlen(trim($this->sEncoding)) > 0) + $sXML .= " encoding=\"".$this->sEncoding."\""; + $sXML .= " ?".">" . $this->xml . ""; + + return $sXML; + } + + /** + * Adds the commands of the provided response XML output to this response + * object + * + * Usage: + * $r1 = $objResponse1->getXML(); + * $objResponse2->loadXML($r1); + * return $objResponse2->getXML(); + * + * @param string the response XML (returned from a getXML() method) to add + * to the end of this response object + */ + function loadXML($mXML) + { + if (is_a($mXML, "xajaxResponse")) { + $mXML = $mXML->getXML(); + } + $sNewXML = ""; + $iStartPos = strpos($mXML, "") + 5; + $sNewXML = substr($mXML, $iStartPos); + $iEndPos = strpos($sNewXML, ""); + $sNewXML = substr($sNewXML, 0, $iEndPos); + $this->xml .= $sNewXML; + } + + /** + * Generates XML from command data + * + * @access private + * @param array associative array of attributes + * @param string data + * @return string XML command + */ + function _cmdXML($aAttributes, $sData) + { + if ($this->bOutputEntities) { + if (function_exists('mb_convert_encoding')) { + $sData = call_user_func_array('mb_convert_encoding', array(&$sData, 'HTML-ENTITIES', $this->sEncoding)); + } + else { + trigger_error("The xajax XML response output could not be converted to HTML entities because the mb_convert_encoding function is not available", E_USER_NOTICE); + } + } + $xml = " $sValue) + $xml .= " $sAttribute=\"$sValue\""; + if ($sData !== null && !stristr($sData,'"; + else if ($sData !== null) + $xml .= ">$sData"; + else + $xml .= ">"; + + return $xml; + } + + /** + * Recursively serializes a data structure in XML so it can be sent to + * the client. It could be thought of as the opposite of + * {@link xajax::_parseObjXml()}. + * + * @access private + * @param mixed data structure to serialize to XML + * @return string serialized XML + */ + function _buildObjXml($var) { + if (gettype($var) == "object") $var = get_object_vars($var); + if (!is_array($var)) { + return ""; + } + else { + $data = ""; + foreach ($var as $key => $value) { + $data .= ""; + $data .= "" . htmlspecialchars($key) . ""; + $data .= "" . $this->_buildObjXml($value) . ""; + $data .= ""; + } + $data .= ""; + return $data; + } + } + +}// end class xajaxResponse +?>