accueil: correction d'un lien (pour Gustavo)
[aidenligne_francais_universite.git] / ajax / xajax.inc.php
1 <?php
2 /**
3 * xajax.inc.php :: Main xajax class and setup file
4 *
5 * xajax version 0.2.4
6 * copyright (c) 2005 by Jared White & J. Max Wilson
7 * http://www.xajaxproject.org
8 *
9 * xajax is an open source PHP class library for easily creating powerful
10 * PHP-driven, web-based Ajax Applications. Using xajax, you can asynchronously
11 * call PHP functions and update the content of your your webpage without
12 * reloading the page.
13 *
14 * xajax is released under the terms of the LGPL license
15 * http://www.gnu.org/copyleft/lesser.html#SEC3
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
21 *
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
26 *
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 *
31 * @package xajax
32 * @version $Id$
33 * @copyright Copyright (c) 2005-2006 by Jared White & J. Max Wilson
34 * @license http://www.gnu.org/copyleft/lesser.html#SEC3 LGPL License
35 */
36
37 /*
38 ----------------------------------------------------------------------------
39 | Online documentation for this class is available on the xajax wiki at: |
40 | http://wiki.xajaxproject.org/Documentation:xajax.inc.php |
41 ----------------------------------------------------------------------------
42 */
43
44 /**
45 * Define XAJAX_DEFAULT_CHAR_ENCODING that is used by both
46 * the xajax and xajaxResponse classes
47 */
48 if (!defined ('XAJAX_DEFAULT_CHAR_ENCODING'))
49 {
50 define ('XAJAX_DEFAULT_CHAR_ENCODING', 'utf-8' );
51 }
52
53 require_once(dirname(__FILE__)."/xajaxResponse.inc.php");
54
55 /**
56 * Communication Method Defines
57 */
58 if (!defined ('XAJAX_GET'))
59 {
60 define ('XAJAX_GET', 0);
61 }
62 if (!defined ('XAJAX_POST'))
63 {
64 define ('XAJAX_POST', 1);
65 }
66
67 /**
68 * The xajax class generates the xajax javascript for your page including the
69 * Javascript wrappers for the PHP functions that you want to call from your page.
70 * It also handles processing and executing the command messages in the XML responses
71 * sent back to your page from your PHP functions.
72 *
73 * @package xajax
74 */
75 class xajax
76 {
77 /**#@+
78 * @access protected
79 */
80 /**
81 * @var array Array of PHP functions that will be callable through javascript wrappers
82 */
83 var $aFunctions;
84 /**
85 * @var array Array of object callbacks that will allow Javascript to call PHP methods (key=function name)
86 */
87 var $aObjects;
88 /**
89 * @var array Array of RequestTypes to be used with each function (key=function name)
90 */
91 var $aFunctionRequestTypes;
92 /**
93 * @var array Array of Include Files for any external functions (key=function name)
94 */
95 var $aFunctionIncludeFiles;
96 /**
97 * @var string Name of the PHP function to call if no callable function was found
98 */
99 var $sCatchAllFunction;
100 /**
101 * @var string Name of the PHP function to call before any other function
102 */
103 var $sPreFunction;
104 /**
105 * @var string The URI for making requests to the xajax object
106 */
107 var $sRequestURI;
108 /**
109 * @var string The prefix to prepend to the javascript wraper function name
110 */
111 var $sWrapperPrefix;
112 /**
113 * @var boolean Show debug messages (default false)
114 */
115 var $bDebug;
116 /**
117 * @var boolean Show messages in the client browser's status bar (default false)
118 */
119 var $bStatusMessages;
120 /**
121 * @var boolean Allow xajax to exit after processing a request (default true)
122 */
123 var $bExitAllowed;
124 /**
125 * @var boolean Use wait cursor in browser (default true)
126 */
127 var $bWaitCursor;
128 /**
129 * @var boolean Use an special xajax error handler so the errors are sent to the browser properly (default false)
130 */
131 var $bErrorHandler;
132 /**
133 * @var string Specify what, if any, file xajax should log errors to (and more information in a future release)
134 */
135 var $sLogFile;
136 /**
137 * @var boolean Clean all output buffers before outputting response (default false)
138 */
139 var $bCleanBuffer;
140 /**
141 * @var string String containing the character encoding used
142 */
143 var $sEncoding;
144 /**
145 * @var boolean Decode input request args from UTF-8 (default false)
146 */
147 var $bDecodeUTF8Input;
148 /**
149 * @var boolean Convert special characters to HTML entities (default false)
150 */
151 var $bOutputEntities;
152 /**
153 * @var array Array for parsing complex objects
154 */
155 var $aObjArray;
156 /**
157 * @var integer Position in $aObjArray
158 */
159 var $iPos;
160
161 /**#@-*/
162
163 /**
164 * Constructor. You can set some extra xajax options right away or use
165 * individual methods later to set options.
166 *
167 * @param string defaults to the current browser URI
168 * @param string defaults to "xajax_";
169 * @param string defaults to XAJAX_DEFAULT_CHAR_ENCODING defined above
170 * @param boolean defaults to false
171 */
172 function xajax($sRequestURI="",$sWrapperPrefix="xajax_",$sEncoding=XAJAX_DEFAULT_CHAR_ENCODING,$bDebug=false)
173 {
174 $this->aFunctions = array();
175 $this->aObjects = array();
176 $this->aFunctionIncludeFiles = array();
177 $this->sRequestURI = $sRequestURI;
178 if ($this->sRequestURI == "")
179 $this->sRequestURI = $this->_detectURI();
180 $this->sWrapperPrefix = $sWrapperPrefix;
181 $this->bDebug = $bDebug;
182 $this->bStatusMessages = false;
183 $this->bWaitCursor = true;
184 $this->bExitAllowed = true;
185 $this->bErrorHandler = false;
186 $this->sLogFile = "";
187 $this->bCleanBuffer = false;
188 $this->setCharEncoding($sEncoding);
189 $this->bDecodeUTF8Input = false;
190 $this->bOutputEntities = false;
191 }
192
193 /**
194 * Sets the URI to which requests will be made.
195 * <i>Usage:</i> <kbd>$xajax->setRequestURI("http://www.xajaxproject.org");</kbd>
196 *
197 * @param string the URI (can be absolute or relative) of the PHP script
198 * that will be accessed when an xajax request occurs
199 */
200 function setRequestURI($sRequestURI)
201 {
202 $this->sRequestURI = $sRequestURI;
203 }
204
205 /**
206 * Sets the prefix that will be appended to the Javascript wrapper
207 * functions (default is "xajax_").
208 *
209 * @param string
210 */
211 //
212 function setWrapperPrefix($sPrefix)
213 {
214 $this->sWrapperPrefix = $sPrefix;
215 }
216
217 /**
218 * Enables debug messages for xajax.
219 * */
220 function debugOn()
221 {
222 $this->bDebug = true;
223 }
224
225 /**
226 * Disables debug messages for xajax (default behavior).
227 */
228 function debugOff()
229 {
230 $this->bDebug = false;
231 }
232
233 /**
234 * Enables messages in the browser's status bar for xajax.
235 */
236 function statusMessagesOn()
237 {
238 $this->bStatusMessages = true;
239 }
240
241 /**
242 * Disables messages in the browser's status bar for xajax (default behavior).
243 */
244 function statusMessagesOff()
245 {
246 $this->bStatusMessages = false;
247 }
248
249 /**
250 * Enables the wait cursor to be displayed in the browser (default behavior).
251 */
252 function waitCursorOn()
253 {
254 $this->bWaitCursor = true;
255 }
256
257 /**
258 * Disables the wait cursor to be displayed in the browser.
259 */
260 function waitCursorOff()
261 {
262 $this->bWaitCursor = false;
263 }
264
265 /**
266 * Enables xajax to exit immediately after processing a request and
267 * sending the response back to the browser (default behavior).
268 */
269 function exitAllowedOn()
270 {
271 $this->bExitAllowed = true;
272 }
273
274 /**
275 * Disables xajax's default behavior of exiting immediately after
276 * processing a request and sending the response back to the browser.
277 */
278 function exitAllowedOff()
279 {
280 $this->bExitAllowed = false;
281 }
282
283 /**
284 * Turns on xajax's error handling system so that PHP errors that occur
285 * during a request are trapped and pushed to the browser in the form of
286 * a Javascript alert.
287 */
288 function errorHandlerOn()
289 {
290 $this->bErrorHandler = true;
291 }
292
293 /**
294 * Turns off xajax's error handling system (default behavior).
295 */
296 function errorHandlerOff()
297 {
298 $this->bErrorHandler = false;
299 }
300
301 /**
302 * Specifies a log file that will be written to by xajax during a request
303 * (used only by the error handling system at present). If you don't invoke
304 * this method, or you pass in "", then no log file will be written to.
305 * <i>Usage:</i> <kbd>$xajax->setLogFile("/xajax_logs/errors.log");</kbd>
306 */
307 function setLogFile($sFilename)
308 {
309 $this->sLogFile = $sFilename;
310 }
311
312 /**
313 * Causes xajax to clean out all output buffers before outputting a
314 * response (default behavior).
315 */
316 function cleanBufferOn()
317 {
318 $this->bCleanBuffer = true;
319 }
320 /**
321 * Turns off xajax's output buffer cleaning.
322 */
323 function cleanBufferOff()
324 {
325 $this->bCleanBuffer = false;
326 }
327
328 /**
329 * Sets the character encoding for the HTTP output based on
330 * <kbd>$sEncoding</kbd>, which is a string containing the character
331 * encoding to use. You don't need to use this method normally, since the
332 * character encoding for the response gets set automatically based on the
333 * <kbd>XAJAX_DEFAULT_CHAR_ENCODING</kbd> constant.
334 * <i>Usage:</i> <kbd>$xajax->setCharEncoding("utf-8");</kbd>
335 *
336 * @param string the encoding type to use (utf-8, iso-8859-1, etc.)
337 */
338 function setCharEncoding($sEncoding)
339 {
340 $this->sEncoding = $sEncoding;
341 }
342
343 /**
344 * Causes xajax to decode the input request args from UTF-8 to the current
345 * encoding if possible. Either the iconv or mb_string extension must be
346 * present for optimal functionality.
347 */
348 function decodeUTF8InputOn()
349 {
350 $this->bDecodeUTF8Input = true;
351 }
352
353 /**
354 * Turns off decoding the input request args from UTF-8 (default behavior).
355 */
356 function decodeUTF8InputOff()
357 {
358 $this->bDecodeUTF8Input = false;
359 }
360
361 /**
362 * Tells the response object to convert special characters to HTML entities
363 * automatically (only works if the mb_string extension is available).
364 */
365 function outputEntitiesOn()
366 {
367 $this->bOutputEntities = true;
368 }
369
370 /**
371 * Tells the response object to output special characters intact. (default
372 * behavior).
373 */
374 function outputEntitiesOff()
375 {
376 $this->bOutputEntities = false;
377 }
378
379 /**
380 * Registers a PHP function or method to be callable through xajax in your
381 * Javascript. If you want to register a function, pass in the name of that
382 * function. If you want to register a static class method, pass in an
383 * array like so:
384 * <kbd>array("myFunctionName", "myClass", "myMethod")</kbd>
385 * For an object instance method, use an object variable for the second
386 * array element (and in PHP 4 make sure you put an & before the variable
387 * to pass the object by reference). Note: the function name is what you
388 * call via Javascript, so it can be anything as long as it doesn't
389 * conflict with any other registered function name.
390 *
391 * <i>Usage:</i> <kbd>$xajax->registerFunction("myFunction");</kbd>
392 * or: <kbd>$xajax->registerFunction(array("myFunctionName", &$myObject, "myMethod"));</kbd>
393 *
394 * @param mixed contains the function name or an object callback array
395 * @param mixed request type (XAJAX_GET/XAJAX_POST) that should be used
396 * for this function. Defaults to XAJAX_POST.
397 */
398 function registerFunction($mFunction,$sRequestType=XAJAX_POST)
399 {
400 if (is_array($mFunction)) {
401 $this->aFunctions[$mFunction[0]] = 1;
402 $this->aFunctionRequestTypes[$mFunction[0]] = $sRequestType;
403 $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
404 }
405 else {
406 $this->aFunctions[$mFunction] = 1;
407 $this->aFunctionRequestTypes[$mFunction] = $sRequestType;
408 }
409 }
410
411 /**
412 * Registers a PHP function to be callable through xajax which is located
413 * in some other file. If the function is requested the external file will
414 * be included to define the function before the function is called.
415 *
416 * <i>Usage:</i> <kbd>$xajax->registerExternalFunction("myFunction","myFunction.inc.php",XAJAX_POST);</kbd>
417 *
418 * @param string contains the function name or an object callback array
419 * ({@link xajax::registerFunction() see registerFunction} for
420 * more info on object callback arrays)
421 * @param string contains the path and filename of the include file
422 * @param mixed the RequestType (XAJAX_GET/XAJAX_POST) that should be used
423 * for this function. Defaults to XAJAX_POST.
424 */
425 function registerExternalFunction($mFunction,$sIncludeFile,$sRequestType=XAJAX_POST)
426 {
427 $this->registerFunction($mFunction, $sRequestType);
428
429 if (is_array($mFunction)) {
430 $this->aFunctionIncludeFiles[$mFunction[0]] = $sIncludeFile;
431 }
432 else {
433 $this->aFunctionIncludeFiles[$mFunction] = $sIncludeFile;
434 }
435 }
436
437 /**
438 * Registers a PHP function to be called when xajax cannot find the
439 * function being called via Javascript. Because this is technically
440 * impossible when using "wrapped" functions, the catch-all feature is
441 * only useful when you're directly using the xajax.call() Javascript
442 * method. Use the catch-all feature when you want more dynamic ability to
443 * intercept unknown calls and handle them in a custom way.
444 *
445 * <i>Usage:</i> <kbd>$xajax->registerCatchAllFunction("myCatchAllFunction");</kbd>
446 *
447 * @param string contains the function name or an object callback array
448 * ({@link xajax::registerFunction() see registerFunction} for
449 * more info on object callback arrays)
450 */
451 function registerCatchAllFunction($mFunction)
452 {
453 if (is_array($mFunction)) {
454 $this->sCatchAllFunction = $mFunction[0];
455 $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
456 }
457 else {
458 $this->sCatchAllFunction = $mFunction;
459 }
460 }
461
462 /**
463 * Registers a PHP function to be called before xajax calls the requested
464 * function. xajax will automatically add the request function's response
465 * to the pre-function's response to create a single response. Another
466 * feature is the ability to return not just a response, but an array with
467 * the first element being false (a boolean) and the second being the
468 * response. In this case, the pre-function's response will be returned to
469 * the browser without xajax calling the requested function.
470 *
471 * <i>Usage:</i> <kbd>$xajax->registerPreFunction("myPreFunction");</kbd>
472 *
473 * @param string contains the function name or an object callback array
474 * ({@link xajax::registerFunction() see registerFunction} for
475 * more info on object callback arrays)
476 */
477 function registerPreFunction($mFunction)
478 {
479 if (is_array($mFunction)) {
480 $this->sPreFunction = $mFunction[0];
481 $this->aObjects[$mFunction[0]] = array_slice($mFunction, 1);
482 }
483 else {
484 $this->sPreFunction = $mFunction;
485 }
486 }
487
488 /**
489 * Returns true if xajax can process the request, false if otherwise.
490 * You can use this to determine if xajax needs to process the request or
491 * not.
492 *
493 * @return boolean
494 */
495 function canProcessRequests()
496 {
497 if ($this->getRequestMode() != -1) return true;
498 return false;
499 }
500
501 /**
502 * Returns the current request mode (XAJAX_GET or XAJAX_POST), or -1 if
503 * there is none.
504 *
505 * @return mixed
506 */
507 function getRequestMode()
508 {
509 if (!empty($_GET["xajax"]))
510 return XAJAX_GET;
511
512 if (!empty($_POST["xajax"]))
513 return XAJAX_POST;
514
515 return -1;
516 }
517
518 /**
519 * This is the main communications engine of xajax. The engine handles all
520 * incoming xajax requests, calls the apporiate PHP functions (or
521 * class/object methods) and passes the XML responses back to the
522 * Javascript response handler. If your RequestURI is the same as your Web
523 * page then this function should be called before any headers or HTML has
524 * been sent.
525 */
526 function processRequests()
527 {
528
529 $requestMode = -1;
530 $sFunctionName = "";
531 $bFoundFunction = true;
532 $bFunctionIsCatchAll = false;
533 $sFunctionNameForSpecial = "";
534 $aArgs = array();
535 $sPreResponse = "";
536 $bEndRequest = false;
537 $sResponse = "";
538
539 $requestMode = $this->getRequestMode();
540 if ($requestMode == -1) return;
541
542 if ($requestMode == XAJAX_POST)
543 {
544 $sFunctionName = $_POST["xajax"];
545
546 if (!empty($_POST["xajaxargs"]))
547 $aArgs = $_POST["xajaxargs"];
548 }
549 else
550 {
551 header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
552 header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
553 header ("Cache-Control: no-cache, must-revalidate");
554 header ("Pragma: no-cache");
555
556 $sFunctionName = $_GET["xajax"];
557
558 if (!empty($_GET["xajaxargs"]))
559 $aArgs = $_GET["xajaxargs"];
560 }
561
562 // Use xajax error handler if necessary
563 if ($this->bErrorHandler) {
564 $GLOBALS['xajaxErrorHandlerText'] = "";
565 set_error_handler("xajaxErrorHandler");
566 }
567
568 if ($this->sPreFunction) {
569 if (!$this->_isFunctionCallable($this->sPreFunction)) {
570 $bFoundFunction = false;
571 $objResponse = new xajaxResponse();
572 $objResponse->addAlert("Unknown Pre-Function ". $this->sPreFunction);
573 $sResponse = $objResponse->getXML();
574 }
575 }
576 //include any external dependencies associated with this function name
577 if (array_key_exists($sFunctionName,$this->aFunctionIncludeFiles))
578 {
579 ob_start();
580 include_once($this->aFunctionIncludeFiles[$sFunctionName]);
581 ob_end_clean();
582 }
583
584 if ($bFoundFunction) {
585 $sFunctionNameForSpecial = $sFunctionName;
586 if (!array_key_exists($sFunctionName, $this->aFunctions))
587 {
588 if ($this->sCatchAllFunction) {
589 $sFunctionName = $this->sCatchAllFunction;
590 $bFunctionIsCatchAll = true;
591 }
592 else {
593 $bFoundFunction = false;
594 $objResponse = new xajaxResponse();
595 $objResponse->addAlert("Unknown Function $sFunctionName.");
596 $sResponse = $objResponse->getXML();
597 }
598 }
599 else if ($this->aFunctionRequestTypes[$sFunctionName] != $requestMode)
600 {
601 $bFoundFunction = false;
602 $objResponse = new xajaxResponse();
603 $objResponse->addAlert("Incorrect Request Type.");
604 $sResponse = $objResponse->getXML();
605 }
606 }
607
608 if ($bFoundFunction)
609 {
610 for ($i = 0; $i < sizeof($aArgs); $i++)
611 {
612 // If magic quotes is on, then we need to strip the slashes from the args
613 if (get_magic_quotes_gpc() == 1 && is_string($aArgs[$i])) {
614
615 $aArgs[$i] = stripslashes($aArgs[$i]);
616 }
617 if (stristr($aArgs[$i],"<xjxobj>") != false)
618 {
619 $aArgs[$i] = $this->_xmlToArray("xjxobj",$aArgs[$i]);
620 }
621 else if (stristr($aArgs[$i],"<xjxquery>") != false)
622 {
623 $aArgs[$i] = $this->_xmlToArray("xjxquery",$aArgs[$i]);
624 }
625 else if ($this->bDecodeUTF8Input)
626 {
627 $aArgs[$i] = $this->_decodeUTF8Data($aArgs[$i]);
628 }
629 }
630
631 if ($this->sPreFunction) {
632 $mPreResponse = $this->_callFunction($this->sPreFunction, array($sFunctionNameForSpecial, $aArgs));
633 if (is_array($mPreResponse) && $mPreResponse[0] === false) {
634 $bEndRequest = true;
635 $sPreResponse = $mPreResponse[1];
636 }
637 else {
638 $sPreResponse = $mPreResponse;
639 }
640 if (is_a($sPreResponse, "xajaxResponse")) {
641 $sPreResponse = $sPreResponse->getXML();
642 }
643 if ($bEndRequest) $sResponse = $sPreResponse;
644 }
645
646 if (!$bEndRequest) {
647 if (!$this->_isFunctionCallable($sFunctionName)) {
648 $objResponse = new xajaxResponse();
649 $objResponse->addAlert("The Registered Function $sFunctionName Could Not Be Found.");
650 $sResponse = $objResponse->getXML();
651 }
652 else {
653 if ($bFunctionIsCatchAll) {
654 $aArgs = array($sFunctionNameForSpecial, $aArgs);
655 }
656 $sResponse = $this->_callFunction($sFunctionName, $aArgs);
657 }
658 if (is_a($sResponse, "xajaxResponse")) {
659 $sResponse = $sResponse->getXML();
660 }
661 if (!is_string($sResponse) || strpos($sResponse, "<xjx>") === FALSE) {
662 $objResponse = new xajaxResponse();
663 $objResponse->addAlert("No XML Response Was Returned By Function $sFunctionName.");
664 $sResponse = $objResponse->getXML();
665 }
666 else if ($sPreResponse != "") {
667 $sNewResponse = new xajaxResponse($this->sEncoding, $this->bOutputEntities);
668 $sNewResponse->loadXML($sPreResponse);
669 $sNewResponse->loadXML($sResponse);
670 $sResponse = $sNewResponse->getXML();
671 }
672 }
673 }
674
675 $sContentHeader = "Content-type: text/xml;";
676 if ($this->sEncoding && strlen(trim($this->sEncoding)) > 0)
677 $sContentHeader .= " charset=".$this->sEncoding;
678 header($sContentHeader);
679 if ($this->bErrorHandler && !empty( $GLOBALS['xajaxErrorHandlerText'] )) {
680 $sErrorResponse = new xajaxResponse();
681 $sErrorResponse->addAlert("** PHP Error Messages: **" . $GLOBALS['xajaxErrorHandlerText']);
682 if ($this->sLogFile) {
683 $fH = @fopen($this->sLogFile, "a");
684 if (!$fH) {
685 $sErrorResponse->addAlert("** Logging Error **\n\nxajax was unable to write to the error log file:\n" . $this->sLogFile);
686 }
687 else {
688 fwrite($fH, "** xajax Error Log - " . strftime("%b %e %Y %I:%M:%S %p") . " **" . $GLOBALS['xajaxErrorHandlerText'] . "\n\n\n");
689 fclose($fH);
690 }
691 }
692
693 $sErrorResponse->loadXML($sResponse);
694 $sResponse = $sErrorResponse->getXML();
695
696 }
697 if ($this->bCleanBuffer) while (@ob_end_clean());
698 print $sResponse;
699 if ($this->bErrorHandler) restore_error_handler();
700
701 if ($this->bExitAllowed)
702 exit();
703 }
704
705 /**
706 * Prints the xajax Javascript header and wrapper code into your page by
707 * printing the output of the getJavascript() method. It should only be
708 * called between the <pre><head> </head></pre> tags in your HTML page.
709 * Remember, if you only want to obtain the result of this function, use
710 * {@link xajax::getJavascript()} instead.
711 *
712 * <i>Usage:</i>
713 * <code>
714 * <head>
715 * ...
716 * < ?php $xajax->printJavascript(); ? >
717 * </code>
718 *
719 * @param string the relative address of the folder where xajax has been
720 * installed. For instance, if your PHP file is
721 * "http://www.myserver.com/myfolder/mypage.php"
722 * and xajax was installed in
723 * "http://www.myserver.com/anotherfolder", then $sJsURI
724 * should be set to "../anotherfolder". Defaults to assuming
725 * xajax is in the same folder as your PHP file.
726 * @param string the relative folder/file pair of the xajax Javascript
727 * engine located within the xajax installation folder.
728 * Defaults to xajax_js/xajax.js.
729 */
730 function printJavascript($sJsURI="", $sJsFile=NULL)
731 {
732 print $this->getJavascript($sJsURI, $sJsFile);
733 }
734
735 /**
736 * Returns the xajax Javascript code that should be added to your HTML page
737 * between the <kbd><head> </head></kbd> tags.
738 *
739 * <i>Usage:</i>
740 * <code>
741 * < ?php $xajaxJSHead = $xajax->getJavascript(); ? >
742 * <head>
743 * ...
744 * < ?php echo $xajaxJSHead; ? >
745 * </code>
746 *
747 * @param string the relative address of the folder where xajax has been
748 * installed. For instance, if your PHP file is
749 * "http://www.myserver.com/myfolder/mypage.php"
750 * and xajax was installed in
751 * "http://www.myserver.com/anotherfolder", then $sJsURI
752 * should be set to "../anotherfolder". Defaults to assuming
753 * xajax is in the same folder as your PHP file.
754 * @param string the relative folder/file pair of the xajax Javascript
755 * engine located within the xajax installation folder.
756 * Defaults to xajax_js/xajax.js.
757 * @return string
758 */
759 function getJavascript($sJsURI="", $sJsFile=NULL)
760 {
761 $html = $this->getJavascriptConfig();
762 $html .= $this->getJavascriptInclude($sJsURI, $sJsFile);
763
764 return $html;
765 }
766
767 /**
768 * Returns a string containing inline Javascript that sets up the xajax
769 * runtime (typically called internally by xajax from get/printJavascript).
770 *
771 * @return string
772 */
773 function getJavascriptConfig()
774 {
775 $html = "\t<script type=\"text/javascript\">\n";
776 $html .= "var xajaxRequestUri=\"".$this->sRequestURI."\";\n";
777 $html .= "var xajaxDebug=".($this->bDebug?"true":"false").";\n";
778 $html .= "var xajaxStatusMessages=".($this->bStatusMessages?"true":"false").";\n";
779 $html .= "var xajaxWaitCursor=".($this->bWaitCursor?"true":"false").";\n";
780 $html .= "var xajaxDefinedGet=".XAJAX_GET.";\n";
781 $html .= "var xajaxDefinedPost=".XAJAX_POST.";\n";
782 $html .= "var xajaxLoaded=false;\n";
783
784 foreach($this->aFunctions as $sFunction => $bExists) {
785 $html .= $this->_wrap($sFunction,$this->aFunctionRequestTypes[$sFunction]);
786 }
787
788 $html .= "\t</script>\n";
789 return $html;
790 }
791
792 /**
793 * Returns a string containing a Javascript include of the xajax.js file
794 * along with a check to see if the file loaded after six seconds
795 * (typically called internally by xajax from get/printJavascript).
796 *
797 * @param string the relative address of the folder where xajax has been
798 * installed. For instance, if your PHP file is
799 * "http://www.myserver.com/myfolder/mypage.php"
800 * and xajax was installed in
801 * "http://www.myserver.com/anotherfolder", then $sJsURI
802 * should be set to "../anotherfolder". Defaults to assuming
803 * xajax is in the same folder as your PHP file.
804 * @param string the relative folder/file pair of the xajax Javascript
805 * engine located within the xajax installation folder.
806 * Defaults to xajax_js/xajax.js.
807 * @return string
808 */
809 function getJavascriptInclude($sJsURI="", $sJsFile=NULL)
810 {
811 if ($sJsFile == NULL) $sJsFile = "xajax_js/xajax.js";
812
813 if ($sJsURI != "" && substr($sJsURI, -1) != "/") $sJsURI .= "/";
814
815 $html = "\t<script type=\"text/javascript\" src=\"" . $sJsURI . $sJsFile . "\"></script>\n";
816 $html .= "\t<script type=\"text/javascript\">\n";
817 $html .= "window.setTimeout(function () { if (!xajaxLoaded) { alert('Error: the xajax Javascript file could not be included. Perhaps the URL is incorrect?\\nURL: {$sJsURI}{$sJsFile}'); } }, 6000);\n";
818 $html .= "\t</script>\n";
819 return $html;
820 }
821
822 /**
823 * This method can be used to create a new xajax.js file out of the
824 * xajax_uncompressed.js file (which will only happen if xajax.js doesn't
825 * already exist on the filesystem).
826 *
827 * @param string an optional argument containing the full server file path
828 * of xajax.js.
829 */
830 function autoCompressJavascript($sJsFullFilename=NULL)
831 {
832 $sJsFile = "xajax_js/xajax.js";
833
834 if ($sJsFullFilename) {
835 $realJsFile = $sJsFullFilename;
836 }
837 else {
838 $realPath = realpath(dirname(__FILE__));
839 $realJsFile = $realPath . "/". $sJsFile;
840 }
841
842 // Create a compressed file if necessary
843 if (!file_exists($realJsFile)) {
844 $srcFile = str_replace(".js", "_uncompressed.js", $realJsFile);
845 if (!file_exists($srcFile)) {
846 trigger_error("The xajax uncompressed Javascript file could not be found in the <b>" . dirname($realJsFile) . "</b> folder. Error ", E_USER_ERROR);
847 }
848 require(dirname(__FILE__)."/xajaxCompress.php");
849 $javaScript = implode('', file($srcFile));
850 $compressedScript = xajaxCompressJavascript($javaScript);
851 $fH = @fopen($realJsFile, "w");
852 if (!$fH) {
853 trigger_error("The xajax compressed javascript file could not be written in the <b>" . dirname($realJsFile) . "</b> folder. Error ", E_USER_ERROR);
854 }
855 else {
856 fwrite($fH, $compressedScript);
857 fclose($fH);
858 }
859 }
860 }
861
862 /**
863 * Returns the current URL based upon the SERVER vars.
864 *
865 * @access private
866 * @return string
867 */
868 function _detectURI() {
869 $aURL = array();
870
871 // Try to get the request URL
872 if (!empty($_SERVER['REQUEST_URI'])) {
873 $aURL = parse_url($_SERVER['REQUEST_URI']);
874 }
875
876 // Fill in the empty values
877 if (empty($aURL['scheme'])) {
878 if (!empty($_SERVER['HTTP_SCHEME'])) {
879 $aURL['scheme'] = $_SERVER['HTTP_SCHEME'];
880 } else {
881 $aURL['scheme'] = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http';
882 }
883 }
884
885 if (empty($aURL['host'])) {
886 if (!empty($_SERVER['HTTP_HOST'])) {
887 if (strpos($_SERVER['HTTP_HOST'], ':') > 0) {
888 list($aURL['host'], $aURL['port']) = explode(':', $_SERVER['HTTP_HOST']);
889 } else {
890 $aURL['host'] = $_SERVER['HTTP_HOST'];
891 }
892 } else if (!empty($_SERVER['SERVER_NAME'])) {
893 $aURL['host'] = $_SERVER['SERVER_NAME'];
894 } else {
895 print "xajax Error: xajax failed to automatically identify your Request URI.";
896 print "Please set the Request URI explicitly when you instantiate the xajax object.";
897 exit();
898 }
899 }
900
901 if (empty($aURL['port']) && !empty($_SERVER['SERVER_PORT'])) {
902 $aURL['port'] = $_SERVER['SERVER_PORT'];
903 }
904
905 if (empty($aURL['path'])) {
906 if (!empty($_SERVER['PATH_INFO'])) {
907 $sPath = parse_url($_SERVER['PATH_INFO']);
908 } else {
909 $sPath = parse_url($_SERVER['PHP_SELF']);
910 }
911 $aURL['path'] = $sPath['path'];
912 unset($sPath);
913 }
914
915 if (!empty($aURL['query'])) {
916 $aURL['query'] = '?'.$aURL['query'];
917 }
918
919 // Build the URL: Start with scheme, user and pass
920 $sURL = $aURL['scheme'].'://';
921 if (!empty($aURL['user'])) {
922 $sURL.= $aURL['user'];
923 if (!empty($aURL['pass'])) {
924 $sURL.= ':'.$aURL['pass'];
925 }
926 $sURL.= '@';
927 }
928
929 // Add the host
930 $sURL.= $aURL['host'];
931
932 // Add the port if needed
933 if (!empty($aURL['port']) && (($aURL['scheme'] == 'http' && $aURL['port'] != 80) || ($aURL['scheme'] == 'https' && $aURL['port'] != 443))) {
934 $sURL.= ':'.$aURL['port'];
935 }
936
937 // Add the path and the query string
938 $sURL.= $aURL['path'].@$aURL['query'];
939
940 // Clean up
941 unset($aURL);
942 return $sURL;
943 }
944
945 /**
946 * Returns true if the function name is associated with an object callback,
947 * false if not.
948 *
949 * @param string the name of the function
950 * @access private
951 * @return boolean
952 */
953 function _isObjectCallback($sFunction)
954 {
955 if (array_key_exists($sFunction, $this->aObjects)) return true;
956 return false;
957 }
958
959 /**
960 * Returns true if the function or object callback can be called, false if
961 * not.
962 *
963 * @param string the name of the function
964 * @access private
965 * @return boolean
966 */
967 function _isFunctionCallable($sFunction)
968 {
969 if ($this->_isObjectCallback($sFunction)) {
970 if (is_object($this->aObjects[$sFunction][0])) {
971 return method_exists($this->aObjects[$sFunction][0], $this->aObjects[$sFunction][1]);
972 }
973 else {
974 return is_callable($this->aObjects[$sFunction]);
975 }
976 }
977 else {
978 return function_exists($sFunction);
979 }
980 }
981
982 /**
983 * Calls the function, class method, or object method with the supplied
984 * arguments.
985 *
986 * @param string the name of the function
987 * @param array arguments to pass to the function
988 * @access private
989 * @return mixed the output of the called function or method
990 */
991 function _callFunction($sFunction, $aArgs)
992 {
993 if ($this->_isObjectCallback($sFunction)) {
994 $mReturn = call_user_func_array($this->aObjects[$sFunction], $aArgs);
995 }
996 else {
997 $mReturn = call_user_func_array($sFunction, $aArgs);
998 }
999 return $mReturn;
1000 }
1001
1002 /**
1003 * Generates the Javascript wrapper for the specified PHP function.
1004 *
1005 * @param string the name of the function
1006 * @param mixed the request type
1007 * @access private
1008 * @return string
1009 */
1010 function _wrap($sFunction,$sRequestType=XAJAX_POST)
1011 {
1012 $js = "function ".$this->sWrapperPrefix."$sFunction(){return xajax.call(\"$sFunction\", arguments, ".$sRequestType.");}\n";
1013 return $js;
1014 }
1015
1016 /**
1017 * Takes a string containing xajax xjxobj XML or xjxquery XML and builds an
1018 * array representation of it to pass as an argument to the PHP function
1019 * being called.
1020 *
1021 * @param string the root tag of the XML
1022 * @param string XML to convert
1023 * @access private
1024 * @return array
1025 */
1026 function _xmlToArray($rootTag, $sXml)
1027 {
1028 $aArray = array();
1029 $sXml = str_replace("<$rootTag>","<$rootTag>|~|",$sXml);
1030 $sXml = str_replace("</$rootTag>","</$rootTag>|~|",$sXml);
1031 $sXml = str_replace("<e>","<e>|~|",$sXml);
1032 $sXml = str_replace("</e>","</e>|~|",$sXml);
1033 $sXml = str_replace("<k>","<k>|~|",$sXml);
1034 $sXml = str_replace("</k>","|~|</k>|~|",$sXml);
1035 $sXml = str_replace("<v>","<v>|~|",$sXml);
1036 $sXml = str_replace("</v>","|~|</v>|~|",$sXml);
1037 $sXml = str_replace("<q>","<q>|~|",$sXml);
1038 $sXml = str_replace("</q>","|~|</q>|~|",$sXml);
1039
1040 $this->aObjArray = explode("|~|",$sXml);
1041
1042 $this->iPos = 0;
1043 $aArray = $this->_parseObjXml($rootTag);
1044
1045 return $aArray;
1046 }
1047
1048 /**
1049 * A recursive function that generates an array from the contents of
1050 * $this->aObjArray.
1051 *
1052 * @param string the root tag of the XML
1053 * @access private
1054 * @return array
1055 */
1056 function _parseObjXml($rootTag)
1057 {
1058 $aArray = array();
1059
1060 if ($rootTag == "xjxobj")
1061 {
1062 while(!stristr($this->aObjArray[$this->iPos],"</xjxobj>"))
1063 {
1064 $this->iPos++;
1065 if(stristr($this->aObjArray[$this->iPos],"<e>"))
1066 {
1067 $key = "";
1068 $value = null;
1069
1070 $this->iPos++;
1071 while(!stristr($this->aObjArray[$this->iPos],"</e>"))
1072 {
1073 if(stristr($this->aObjArray[$this->iPos],"<k>"))
1074 {
1075 $this->iPos++;
1076 while(!stristr($this->aObjArray[$this->iPos],"</k>"))
1077 {
1078 $key .= $this->aObjArray[$this->iPos];
1079 $this->iPos++;
1080 }
1081 }
1082 if(stristr($this->aObjArray[$this->iPos],"<v>"))
1083 {
1084 $this->iPos++;
1085 while(!stristr($this->aObjArray[$this->iPos],"</v>"))
1086 {
1087 if(stristr($this->aObjArray[$this->iPos],"<xjxobj>"))
1088 {
1089 $value = $this->_parseObjXml("xjxobj");
1090 $this->iPos++;
1091 }
1092 else
1093 {
1094 $value .= $this->aObjArray[$this->iPos];
1095 if ($this->bDecodeUTF8Input)
1096 {
1097 $value = $this->_decodeUTF8Data($value);
1098 }
1099 }
1100 $this->iPos++;
1101 }
1102 }
1103 $this->iPos++;
1104 }
1105
1106 $aArray[$key]=$value;
1107 }
1108 }
1109 }
1110
1111 if ($rootTag == "xjxquery")
1112 {
1113 $sQuery = "";
1114 $this->iPos++;
1115 while(!stristr($this->aObjArray[$this->iPos],"</xjxquery>"))
1116 {
1117 if (stristr($this->aObjArray[$this->iPos],"<q>") || stristr($this->aObjArray[$this->iPos],"</q>"))
1118 {
1119 $this->iPos++;
1120 continue;
1121 }
1122 $sQuery .= $this->aObjArray[$this->iPos];
1123 $this->iPos++;
1124 }
1125
1126 parse_str($sQuery, $aArray);
1127 if ($this->bDecodeUTF8Input)
1128 {
1129 foreach($aArray as $key => $value)
1130 {
1131 $aArray[$key] = $this->_decodeUTF8Data($value);
1132 }
1133 }
1134 // If magic quotes is on, then we need to strip the slashes from the
1135 // array values because of the parse_str pass which adds slashes
1136 if (get_magic_quotes_gpc() == 1) {
1137 $newArray = array();
1138 foreach ($aArray as $sKey => $sValue) {
1139 if (is_string($sValue))
1140 $newArray[$sKey] = stripslashes($sValue);
1141 else
1142 $newArray[$sKey] = $sValue;
1143 }
1144 $aArray = $newArray;
1145 }
1146 }
1147
1148 return $aArray;
1149 }
1150
1151 /**
1152 * Decodes string data from UTF-8 to the current xajax encoding.
1153 *
1154 * @param string data to convert
1155 * @access private
1156 * @return string converted data
1157 */
1158 function _decodeUTF8Data($sData)
1159 {
1160 $sValue = $sData;
1161 if ($this->bDecodeUTF8Input)
1162 {
1163 $sFuncToUse = NULL;
1164
1165 if (function_exists('iconv'))
1166 {
1167 $sFuncToUse = "iconv";
1168 }
1169 else if (function_exists('mb_convert_encoding'))
1170 {
1171 $sFuncToUse = "mb_convert_encoding";
1172 }
1173 else if ($this->sEncoding == "ISO-8859-1")
1174 {
1175 $sFuncToUse = "utf8_decode";
1176 }
1177 else
1178 {
1179 trigger_error("The incoming xajax data could not be converted from UTF-8", E_USER_NOTICE);
1180 }
1181
1182 if ($sFuncToUse)
1183 {
1184 if (is_string($sValue))
1185 {
1186 if ($sFuncToUse == "iconv")
1187 {
1188 $sValue = iconv("UTF-8", $this->sEncoding.'//TRANSLIT', $sValue);
1189 }
1190 else if ($sFuncToUse == "mb_convert_encoding")
1191 {
1192 $sValue = mb_convert_encoding($sValue, $this->sEncoding, "UTF-8");
1193 }
1194 else
1195 {
1196 $sValue = utf8_decode($sValue);
1197 }
1198 }
1199 }
1200 }
1201 return $sValue;
1202 }
1203
1204 }// end class xajax
1205
1206 /**
1207 * This function is registered with PHP's set_error_handler() function if
1208 * the xajax error handling system is turned on.
1209 */
1210 function xajaxErrorHandler($errno, $errstr, $errfile, $errline)
1211 {
1212 $errorReporting = error_reporting();
1213 if (($errno & $errorReporting) == 0) return;
1214
1215 if ($errno == E_NOTICE) {
1216 $errTypeStr = "NOTICE";
1217 }
1218 else if ($errno == E_WARNING) {
1219 $errTypeStr = "WARNING";
1220 }
1221 else if ($errno == E_USER_NOTICE) {
1222 $errTypeStr = "USER NOTICE";
1223 }
1224 else if ($errno == E_USER_WARNING) {
1225 $errTypeStr = "USER WARNING";
1226 }
1227 else if ($errno == E_USER_ERROR) {
1228 $errTypeStr = "USER FATAL ERROR";
1229 }
1230 else if ($errno == E_STRICT) {
1231 return;
1232 }
1233 else {
1234 $errTypeStr = "UNKNOWN: $errno";
1235 }
1236 $GLOBALS['xajaxErrorHandlerText'] .= "\n----\n[$errTypeStr] $errstr\nerror in line $errline of file $errfile";
1237 }
1238
1239 ?>