xajax.inc.php 36 KB

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