1: <?php
2: //error_reporting(E_STRICT | E_ERROR | E_WARNING | E_PARSE);
3: /*
4: File: xajax.inc.php
5:
6: Main xajax class and setup file.
7:
8: Title: xajax class
9:
10: Please see <copyright.inc.php> for a detailed description, copyright
11: and license information.
12: */
13:
14: /*
15: @package xajax
16: @version $Id: xajax.inc.php 362 2007-05-29 15:32:24Z calltoconstruct $
17: @copyright Copyright (c) 2005-2007 by Jared White & J. Max Wilson
18: @copyright Copyright (c) 2008-2010 by Joseph Woolley, Steffen Konerow, Jared White & J. Max Wilson
19: @license http://www.xajaxproject.org/bsd_license.txt BSD License
20: */
21:
22: /*
23: Section: Standard Definitions
24: */
25:
26: /*
27: String: XAJAX_DEFAULT_CHAR_ENCODING
28:
29: Default character encoding used by both the <xajax> and
30: <xajaxResponse> classes.
31: */
32: if (!defined ('XAJAX_DEFAULT_CHAR_ENCODING')) define ('XAJAX_DEFAULT_CHAR_ENCODING', 'utf-8');
33:
34: /*
35: String: XAJAX_PROCESSING_EVENT
36: String: XAJAX_PROCESSING_EVENT_BEFORE
37: String: XAJAX_PROCESSING_EVENT_AFTER
38: String: XAJAX_PROCESSING_EVENT_INVALID
39:
40: Identifiers used to register processing events. Processing events are essentially
41: hooks into the xajax core that can be used to add functionality into the request
42: processing sequence.
43: */
44: if (!defined ('XAJAX_PROCESSING_EVENT')) define ('XAJAX_PROCESSING_EVENT', 'xajax processing event');
45: if (!defined ('XAJAX_PROCESSING_EVENT_BEFORE')) define ('XAJAX_PROCESSING_EVENT_BEFORE', 'beforeProcessing');
46: if (!defined ('XAJAX_PROCESSING_EVENT_AFTER')) define ('XAJAX_PROCESSING_EVENT_AFTER', 'afterProcessing');
47: if (!defined ('XAJAX_PROCESSING_EVENT_INVALID')) define ('XAJAX_PROCESSING_EVENT_INVALID', 'invalidRequest');
48:
49: /*
50: Class: xajax
51:
52: The xajax class uses a modular plug-in system to facilitate the processing
53: of special Ajax requests made by a PHP page. It generates Javascript that
54: the page must include in order to make requests. It handles the output
55: of response commands (see <xajaxResponse>). Many flags and settings can be
56: adjusted to effect the behavior of the xajax class as well as the client-side
57: javascript.
58: */
59: final class xajax
60: {
61: /*
62: Array: aSettings
63:
64: This array is used to store all the configuration settings that are set during
65: the run of the script. This provides a single data store for the settings
66: in case we need to return the value of a configuration option for some reason.
67:
68: It is advised that individual plugins store a local copy of the settings they
69: wish to track, however, settings are available via a reference to the <xajax>
70: object using <xajax->getConfiguration>.
71: */
72: private $aSettings = array();
73:
74: /*
75: Boolean: bErrorHandler
76:
77: This is a configuration setting that the main xajax object tracks. It is used
78: to enable an error handler function which will trap php errors and return them
79: to the client as part of the response. The client can then display the errors
80: to the user if so desired.
81: */
82: private $bErrorHandler;
83:
84: /*
85: Array: aProcessingEvents
86:
87: Stores the processing event handlers that have been assigned during this run
88: of the script.
89: */
90: private $aProcessingEvents;
91:
92: /*
93: Boolean: bExitAllowed
94:
95: A configuration option that is tracked by the main <xajax>object. Setting this
96: to true allows <xajax> to exit immediatly after processing a xajax request. If
97: this is set to false, xajax will allow the remaining code and HTML to be sent
98: as part of the response. Typically this would result in an error, however,
99: a response processor on the client side could be designed to handle this condition.
100: */
101: private $bExitAllowed;
102:
103: /*
104: Boolean: bCleanBuffer
105:
106: A configuration option that is tracked by the main <xajax> object. Setting this
107: to true allows <xajax> to clear out any pending output buffers so that the
108: <xajaxResponse> is (virtually) the only output when handling a request.
109: */
110: private $bCleanBuffer;
111:
112: /*
113: String: sLogFile
114:
115: A configuration setting tracked by the main <xajax> object. Set the name of the
116: file on the server that you wish to have php error messages written to during
117: the processing of <xajax> requests.
118: */
119: private $sLogFile;
120:
121: /*
122: String: sCoreIncludeOutput
123:
124: This is populated with any errors or warnings produced while including the xajax
125: core components. This is useful for debugging core updates.
126: */
127: private $sCoreIncludeOutput;
128:
129: /*
130: Object: objPluginManager
131:
132: This stores a reference to the global <xajaxPluginManager>
133: */
134: private $objPluginManager;
135:
136: /*
137: Object: objArgumentManager
138:
139: Stores a reference to the global <xajaxArgumentManager>
140: */
141: private $objArgumentManager;
142:
143: /*
144: Object: objResponseManager
145:
146: Stores a reference to the global <xajaxResponseManager>
147: */
148: private $objResponseManager;
149:
150: /*
151: Object: objLanguageManager
152:
153: Stores a reference to the global <xajaxLanguageManager>
154: */
155: private $objLanguageManager;
156:
157: private $challengeResponse;
158:
159: /*
160: Constructor: xajax
161:
162: Constructs a xajax instance and initializes the plugin system.
163:
164: Parameters:
165:
166: sRequestURI - (optional): The <xajax->sRequestURI> to be used
167: for calls back to the server. If empty, xajax fills in the current
168: URI that initiated this request.
169: */
170: public function __construct($sRequestURI=null, $sLanguage=null)
171: {
172: $this->bErrorHandler = false;
173: $this->aProcessingEvents = array();
174: $this->bExitAllowed = true;
175: $this->bCleanBuffer = true;
176: $this->sLogFile = '';
177:
178: $this->__wakeup();
179:
180: // The default configuration settings.
181: $this->configureMany(
182: array(
183: 'characterEncoding' => XAJAX_DEFAULT_CHAR_ENCODING,
184: 'decodeUTF8Input' => false,
185: 'outputEntities' => false,
186: 'responseType' => 'JSON',
187: 'defaultMode' => 'asynchronous',
188: 'defaultMethod' => 'POST', // W3C: Method is case sensitive
189: 'wrapperPrefix' => 'xajax_',
190: 'debug' => false,
191: 'verbose' => false,
192: 'useUncompressedScripts' => false,
193: 'statusMessages' => false,
194: 'waitCursor' => true,
195: 'scriptDeferral' => false,
196: 'exitAllowed' => true,
197: 'errorHandler' => false,
198: 'cleanBuffer' => false,
199: 'allowBlankResponse' => false,
200: 'allowAllResponseTypes' => false,
201: 'generateStubs' => true,
202: 'logFile' => '',
203: 'timeout' => 6000,
204: 'version' => $this->getVersion()
205: )
206: );
207:
208: if (null !== $sRequestURI)
209: $this->configure('requestURI', $sRequestURI);
210: else
211: $this->configure('requestURI', $this->_detectURI());
212:
213: if (null !== $sLanguage)
214: $this->configure('language', $sLanguage);
215:
216: if ('utf-8' != XAJAX_DEFAULT_CHAR_ENCODING) $this->configure("decodeUTF8Input", true);
217:
218: }
219:
220: /*
221: Function: __sleep
222: */
223: public function __sleep()
224: {
225: $aMembers = get_class_vars(get_class($this));
226:
227: if (isset($aMembers['objLanguageManager']))
228: unset($aMembers['objLanguageManager']);
229:
230: if (isset($aMembers['objPluginManager']))
231: unset($aMembers['objPluginManager']);
232:
233: if (isset($aMembers['objArgumentManager']))
234: unset($aMembers['objArgumentManager']);
235:
236: if (isset($aMembers['objResponseManager']))
237: unset($aMembers['objResponseManager']);
238:
239: if (isset($aMembers['sCoreIncludeOutput']))
240: unset($aMembers['sCoreIncludeOutput']);
241:
242: return array_keys($aMembers);
243: }
244:
245: /*
246: Function: __wakeup
247: */
248: public function __wakeup()
249: {
250: ob_start();
251:
252: $sLocalFolder = dirname(__FILE__);
253:
254: //SkipAIO
255: require $sLocalFolder . '/xajaxPluginManager.inc.php';
256: require $sLocalFolder . '/xajaxLanguageManager.inc.php';
257: require $sLocalFolder . '/xajaxArgumentManager.inc.php';
258: require $sLocalFolder . '/xajaxResponseManager.inc.php';
259: require $sLocalFolder . '/xajaxRequest.inc.php';
260: require $sLocalFolder . '/xajaxResponse.inc.php';
261: //EndSkipAIO
262:
263: // this is the list of folders where xajax will look for plugins
264: // that will be automatically included at startup.
265: $aPluginFolders = array();
266: $aPluginFolders[] = dirname($sLocalFolder) . '/xajax_plugins';
267:
268: //SkipAIO
269: $aPluginFolders[] = $sLocalFolder . '/plugin_layer';
270: //EndSkipAIO
271:
272: // Setup plugin manager
273: $this->objPluginManager = xajaxPluginManager::getInstance();
274: $this->objPluginManager->loadPlugins($aPluginFolders);
275:
276: $this->objLanguageManager = xajaxLanguageManager::getInstance();
277: $this->objArgumentManager = xajaxArgumentManager::getInstance();
278: $this->objResponseManager = xajaxResponseManager::getInstance();
279:
280: $this->sCoreIncludeOutput = ob_get_clean();
281: $this->configureMany($this->aSettings);
282:
283: }
284:
285: /*
286: Function: getGlobalResponse
287:
288: Returns the <xajaxResponse> object preconfigured with the encoding
289: and entity settings from this instance of <xajax>. This is used
290: for singleton-pattern response development.
291:
292: Returns:
293:
294: <xajaxResponse> : A <xajaxResponse> object which can be used to return
295: response commands. See also the <xajaxResponseManager> class.
296: */
297: public static function &getGlobalResponse()
298: {
299: static $obj;
300: if (!$obj) {
301: $obj = new xajaxResponse();
302: }
303: return $obj;
304: }
305:
306: /*
307: Function: getVersion
308:
309: Returns:
310:
311: string : The current xajax version.
312: */
313: public static function getVersion()
314: {
315: return 'xajax 0.5';
316: }
317:
318: /*
319: Function: register
320:
321: Call this function to register request handlers, including functions,
322: callable objects and events. New plugins can be added that support
323: additional registration methods and request processors.
324:
325:
326: Parameters:
327:
328: $sType - (string): Type of request handler being registered; standard
329: options include:
330: XAJAX_FUNCTION: a function declared at global scope.
331: XAJAX_CALLABLE_OBJECT: an object who's methods are to be registered.
332: XAJAX_EVENT: an event which will cause zero or more event handlers
333: to be called.
334: XAJAX_EVENT_HANDLER: register an event handler function.
335:
336: $sFunction || $objObject || $sEvent - (mixed):
337: when registering a function, this is the name of the function
338: when registering a callable object, this is the object being registered
339: when registering an event or event handler, this is the name of the event
340:
341: $sIncludeFile || $aCallOptions || $sEventHandler
342: when registering a function, this is the (optional) include file.
343: when registering a callable object, this is an (optional) array
344: of call options for the functions being registered.
345: when registering an event handler, this is the name of the function.
346: */
347: public function register($sType, $mArg)
348: {
349: $aArgs = func_get_args();
350: $nArgs = func_num_args();
351:
352: if (2 < $nArgs)
353: {
354: if (XAJAX_PROCESSING_EVENT == $aArgs[0])
355: {
356: $sEvent = $aArgs[1];
357: $xuf = $aArgs[2];
358:
359: if (false == is_a($xuf, 'xajaxUserFunction'))
360: $xuf = new xajaxUserFunction($xuf);
361:
362: $this->aProcessingEvents[$sEvent] = $xuf;
363:
364: return true;
365: }
366: }
367:
368: return $this->objPluginManager->register($aArgs);
369: }
370:
371: /*
372: Function: configure
373:
374: Call this function to set options that will effect the processing of
375: xajax requests. Configuration settings can be specific to the xajax
376: core, request processor plugins and response plugins.
377:
378:
379: Parameters:
380:
381: Options include:
382: javascript URI - (string): The path to the folder that contains the
383: xajax javascript files.
384: errorHandler - (boolean): true to enable the xajax error handler, see
385: <xajax->bErrorHandler>
386: exitAllowed - (boolean): true to allow xajax to exit after processing
387: a request. See <xajax->bExitAllowed> for more information.
388: */
389: public function configure($sName, $mValue)
390: {
391: if ('errorHandler' == $sName) {
392: if (true === $mValue || false === $mValue)
393: $this->bErrorHandler = $mValue;
394: } else if ('exitAllowed' == $sName) {
395: if (true === $mValue || false === $mValue)
396: $this->bExitAllowed = $mValue;
397: } else if ('cleanBuffer' == $sName) {
398: if (true === $mValue || false === $mValue)
399: $this->bCleanBuffer = $mValue;
400: } else if ('logFile' == $sName) {
401: $this->sLogFile = $mValue;
402: }
403:
404: $this->objLanguageManager->configure($sName, $mValue);
405: $this->objArgumentManager->configure($sName, $mValue);
406: $this->objPluginManager->configure($sName, $mValue);
407: $this->objResponseManager->configure($sName, $mValue);
408:
409: $this->aSettings[$sName] = $mValue;
410: }
411:
412: /*
413: Function: configureMany
414:
415: Set an array of configuration options.
416:
417: Parameters:
418:
419: $aOptions - (array): Associative array of configuration settings
420: */
421: public function configureMany($aOptions)
422: {
423: foreach ($aOptions as $sName => $mValue)
424: $this->configure($sName, $mValue);
425: }
426:
427: /*
428: Function: getConfiguration
429:
430: Get the current value of a configuration setting that was previously set
431: via <xajax->configure> or <xajax->configureMany>
432:
433: Parameters:
434:
435: $sName - (string): The name of the configuration setting
436:
437: Returns:
438:
439: $mValue : (mixed): The value of the setting if set, null otherwise.
440: */
441: public function getConfiguration($sName)
442: {
443: if (isset($this->aSettings[$sName]))
444: return $this->aSettings[$sName];
445: return NULL;
446: }
447:
448: /*
449: Function: canProcessRequest
450:
451: Determines if a call is a xajax request or a page load request.
452:
453: Return:
454:
455: boolean - True if this is a xajax request, false otherwise.
456: */
457: public function canProcessRequest()
458: {
459: return $this->objPluginManager->canProcessRequest();
460: }
461:
462: /*
463: Function: VerifySession
464:
465: Ensure that an active session is available (primarily used
466: for storing challenge / response codes).
467: */
468: private function verifySession()
469: {
470: $sessionID = session_id();
471: if ($sessionID === '') {
472: $this->objResponseManager->debug(
473: 'Must enable sessions to use challenge/response.'
474: );
475: return false;
476: }
477: return true;
478: }
479:
480: private function loadChallenges($sessionKey)
481: {
482: $challenges = array();
483:
484: if (isset($_SESSION[$sessionKey]))
485: $challenges = $_SESSION[$sessionKey];
486:
487: return $challenges;
488: }
489:
490: private function saveChallenges($sessionKey, $challenges)
491: {
492: if (count($challenges) > 10)
493: array_shift($challenges);
494:
495: $_SESSION[$sessionKey] = $challenges;
496: }
497:
498: private function makeChallenge($algo, $value)
499: {
500: // TODO: Move to configuration option
501: if (null === $algo)
502: $algo = 'md5';
503:
504: // TODO: Move to configuration option
505: if (null === $value)
506: $value = rand(100000, 999999);
507:
508: return hash($algo, $value);
509: }
510:
511: /*
512: Function: challenge
513:
514: Call this from the top of a xajax enabled request handler
515: to introduce a challenge and response cycle into the request
516: response process.
517:
518: NOTE: Sessions must be enabled to use this feature.
519: */
520: public function challenge($algo=null, $value=null)
521: {
522: if (false === $this->verifySession())
523: return false;
524:
525: // TODO: Move to configuration option
526: $sessionKey = 'xajax_challenges';
527:
528: $challenges = $this->loadChallenges($sessionKey);
529:
530: if (isset($this->challengeResponse))
531: {
532: $key = array_search($this->challengeResponse, $challenges);
533:
534: if ($key !== false)
535: {
536: unset($challenges[$key]);
537: $this->saveChallenges($sessionKey, $challenges);
538: return true;
539: }
540: }
541:
542: $challenge = $this->makeChallenge($algo, $value);
543:
544: $challenges[] = $challenge;
545:
546: $this->saveChallenges($sessionKey, $challenges);
547:
548: header("challenge: {$challenge}");
549:
550: return false;
551: }
552:
553: /*
554: Function: processRequest
555:
556: If this is a xajax request (see <xajax->canProcessRequest>), call the
557: requested PHP function, build the response and send it back to the
558: browser.
559:
560: This is the main server side engine for xajax. It handles all the
561: incoming requests, including the firing of events and handling of the
562: response. If your RequestURI is the same as your web page, then this
563: function should be called before ANY headers or HTML is output from
564: your script.
565:
566: This function may exit, if a request is processed. See <xajax->bAllowExit>
567: */
568: public function processRequest()
569: {
570: if (isset($_SERVER['HTTP_CHALLENGE_RESPONSE']))
571: $this->challengeResponse = $_SERVER['HTTP_CHALLENGE_RESPONSE'];
572:
573: //SkipDebug
574: // Check to see if headers have already been sent out, in which case we can't do our job
575: if (headers_sent($filename, $linenumber)) {
576: echo "Output has already been sent to the browser at {$filename}:{$linenumber}.\n";
577: echo 'Please make sure the command $xajax->processRequest() is placed before this.';
578: exit();
579: }
580: //EndSkipDebug
581:
582: if ($this->canProcessRequest())
583: {
584: // Use xajax error handler if necessary
585: if ($this->bErrorHandler) {
586: $GLOBALS['xajaxErrorHandlerText'] = "";
587: set_error_handler("xajaxErrorHandler");
588: }
589:
590: $mResult = true;
591:
592: // handle beforeProcessing event
593: if (isset($this->aProcessingEvents[XAJAX_PROCESSING_EVENT_BEFORE]))
594: {
595: $bEndRequest = false;
596:
597: $this->aProcessingEvents[XAJAX_PROCESSING_EVENT_BEFORE]->call(
598: array(&$bEndRequest)
599: );
600:
601: $mResult = (false === $bEndRequest);
602: }
603:
604: if (true === $mResult)
605: $mResult = $this->objPluginManager->processRequest();
606:
607: if (true === $mResult)
608: {
609: if ($this->bCleanBuffer) {
610: $er = error_reporting(0);
611: while (ob_get_level() > 0) ob_end_clean();
612: error_reporting($er);
613: }
614:
615: // handle afterProcessing event
616: if (isset($this->aProcessingEvents[XAJAX_PROCESSING_EVENT_AFTER]))
617: {
618: $bEndRequest = false;
619:
620: $this->aProcessingEvents[XAJAX_PROCESSING_EVENT_AFTER]->call(
621: array($bEndRequest)
622: );
623:
624: if (true === $bEndRequest)
625: {
626: $this->objResponseManager->clear();
627: $this->objResponseManager->append($aResult[1]);
628: }
629: }
630: }
631: else if (is_string($mResult))
632: {
633: if ($this->bCleanBuffer) {
634: $er = error_reporting(0);
635: while (ob_get_level() > 0) ob_end_clean();
636: error_reporting($er);
637: }
638:
639: // $mResult contains an error message
640: // the request was missing the cooresponding handler function
641: // or an error occurred while attempting to execute the
642: // handler. replace the response, if one has been started
643: // and send a debug message.
644:
645: $this->objResponseManager->clear();
646: $this->objResponseManager->append(new xajaxResponse());
647:
648: // handle invalidRequest event
649: if (isset($this->aProcessingEvents[XAJAX_PROCESSING_EVENT_INVALID]))
650: $this->aProcessingEvents[XAJAX_PROCESSING_EVENT_INVALID]->call();
651: else
652: $this->objResponseManager->debug($mResult);
653: }
654:
655: if ($this->bErrorHandler) {
656: $sErrorMessage = $GLOBALS['xajaxErrorHandlerText'];
657: if (!empty($sErrorMessage)) {
658: if (0 < strlen($this->sLogFile)) {
659: $fH = @fopen($this->sLogFile, "a");
660: if (NULL != $fH) {
661: fwrite(
662: $fH,
663: $this->objLanguageManager->getText('LOGHDR:01')
664: . strftime("%b %e %Y %I:%M:%S %p")
665: . $this->objLanguageManager->getText('LOGHDR:02')
666: . $sErrorMessage
667: . $this->objLanguageManager->getText('LOGHDR:03')
668: );
669: fclose($fH);
670: } else {
671: $this->objResponseManager->debug(
672: $this->objLanguageManager->getText('LOGERR:01')
673: . $this->sLogFile
674: );
675: }
676: }
677: $this->objResponseManager->debug(
678: $this->objLanguageManager->getText('LOGMSG:01')
679: . $sErrorMessage
680: );
681: }
682: }
683:
684: $this->objResponseManager->send();
685:
686: if ($this->bErrorHandler) restore_error_handler();
687:
688: if ($this->bExitAllowed) exit();
689: }
690: }
691:
692: /*
693: Function: printJavascript
694:
695: Prints the xajax Javascript header and wrapper code into your page.
696: This should be used to print the javascript code between the HEAD
697: and /HEAD tags at the top of the page.
698:
699: The javascript code output by this function is dependent on the plugins
700: that are included and the functions that are registered.
701:
702: */
703: public function printJavascript()
704: {
705: $this->objPluginManager->generateClientScript();
706: }
707:
708: /*
709: Function: getJavascript
710:
711: See <xajax->printJavascript> for more information.
712: */
713: public function getJavascript()
714: {
715: ob_start();
716: $this->printJavascript();
717: return ob_get_clean();
718: }
719:
720: /*
721: Function: autoCompressJavascript
722:
723: Creates a new xajax_core, xajax_debug, etc... file out of the
724: _uncompressed file with a similar name. This strips out the
725: comments and extraneous whitespace so the file is as small as
726: possible without modifying the function of the code.
727:
728: Parameters:
729:
730: sJsFullFilename - (string): The relative path and name of the file
731: to be compressed.
732: bAlways - (boolean): Compress the file, even if it already exists.
733: */
734: public function autoCompressJavascript($sJsFullFilename=NULL, $bAlways=false)
735: {
736: $sJsFile = 'xajax_js/xajax_core.js';
737:
738: if ($sJsFullFilename) {
739: $realJsFile = $sJsFullFilename;
740: }
741: else {
742: $realPath = realpath(dirname(dirname(__FILE__)));
743: $realJsFile = $realPath . '/'. $sJsFile;
744: }
745:
746: // Create a compressed file if necessary
747: if (!file_exists($realJsFile) || true == $bAlways) {
748: $srcFile = str_replace('.js', '_uncompressed.js', $realJsFile);
749: if (!file_exists($srcFile)) {
750: trigger_error(
751: $this->objLanguageManager->getText('CMPRSJS:RDERR:01')
752: . dirname($realJsFile)
753: . $this->objLanguageManager->getText('CMPRSJS:RDERR:02')
754: , E_USER_ERROR
755: );
756: }
757:
758: require_once(dirname(__FILE__) . '/xajaxCompress.inc.php');
759: $javaScript = implode('', file($srcFile));
760: $compressedScript = xajaxCompressFile($javaScript);
761: $fH = @fopen($realJsFile, 'w');
762: if (!$fH) {
763: trigger_error(
764: $this->objLanguageManager->getText('CMPRSJS:WTERR:01')
765: . dirname($realJsFile)
766: . $this->objLanguageManager->getText('CMPRSJS:WTERR:02')
767: , E_USER_ERROR
768: );
769: }
770: else {
771: fwrite($fH, $compressedScript);
772: fclose($fH);
773: }
774: }
775: }
776:
777: private function _compressSelf($sFolder=null)
778: {
779: if (null == $sFolder)
780: $sFolder = dirname(dirname(__FILE__));
781:
782: require_once(dirname(__FILE__) . '/xajaxCompress.inc.php');
783:
784: if ($handle = opendir($sFolder)) {
785: while (!(false === ($sName = readdir($handle)))) {
786: if ('.' != $sName && '..' != $sName && is_dir($sFolder . '/' . $sName)) {
787: $this->_compressSelf($sFolder . '/' . $sName);
788: } else if (8 < strlen($sName) && 0 == strpos($sName, '.compressed')) {
789: if ('.inc.php' == substr($sName, strlen($sName) - 8, 8)) {
790: $sName = substr($sName, 0, strlen($sName) - 8);
791: $sPath = $sFolder . '/' . $sName . '.inc.php';
792: if (file_exists($sPath)) {
793:
794: $aParsed = array();
795: $aFile = file($sPath);
796: $nSkip = 0;
797: foreach (array_keys($aFile) as $sKey)
798: if ('//SkipDebug' == $aFile[$sKey])
799: ++$nSkip;
800: else if ('//EndSkipDebug' == $aFile[$sKey])
801: --$nSkip;
802: else if (0 == $nSkip)
803: $aParsed[] = $aFile[$sKey];
804: unset($aFile);
805:
806: $compressedScript = xajaxCompressFile(implode('', $aParsed));
807:
808: $sNewPath = $sPath;
809: $fH = @fopen($sNewPath, 'w');
810: if (!$fH) {
811: trigger_error(
812: $this->objLanguageManager->getText('CMPRSPHP:WTERR:01')
813: . $sNewPath
814: . $this->objLanguageManager->getText('CMPRSPHP:WTERR:02')
815: , E_USER_ERROR
816: );
817: }
818: else {
819: fwrite($fH, $compressedScript);
820: fclose($fH);
821: }
822: }
823: }
824: }
825: }
826:
827: closedir($handle);
828: }
829: }
830:
831: public function _compile($sFolder=null, $bWriteFile=true)
832: {
833: if (null == $sFolder)
834: $sFolder = dirname(__FILE__);
835:
836: require_once(dirname(__FILE__) . '/xajaxCompress.inc.php');
837:
838: $aOutput = array();
839:
840: if ($handle = opendir($sFolder)) {
841: while (!(false === ($sName = readdir($handle)))) {
842: if ('.' != $sName && '..' != $sName && is_dir($sFolder . '/' . $sName)) {
843: $aOutput[] = $this->_compile($sFolder . '/' . $sName, false);
844: } else if (8 < strlen($sName)) {
845: if ('.inc.php' == substr($sName, strlen($sName) - 8, 8)) {
846: $sName = substr($sName, 0, strlen($sName) - 8);
847: $sPath = $sFolder . '/' . $sName . '.inc.php';
848: if (
849: 'xajaxAIO' != $sName &&
850: 'xajaxCompress' != $sName
851: ) {
852: if (file_exists($sPath)) {
853:
854: $aParsed = array();
855: $aFile = file($sPath);
856: $nSkip = 0;
857: foreach (array_keys($aFile) as $sKey)
858: if ('//SkipDebug' == substr($aFile[$sKey], 0, 11))
859: ++$nSkip;
860: else if ('//EndSkipDebug' == substr($aFile[$sKey], 0, 14))
861: --$nSkip;
862: else if ('//SkipAIO' == substr($aFile[$sKey], 0, 9))
863: ++$nSkip;
864: else if ('//EndSkipAIO' == substr($aFile[$sKey], 0, 12))
865: --$nSkip;
866: else if ('<'.'?php' == substr($aFile[$sKey], 0, 5)) {}
867: else if ('?'.'>' == substr($aFile[$sKey], 0, 2)) {}
868: else if (0 == $nSkip)
869: $aParsed[] = $aFile[$sKey];
870: unset($aFile);
871:
872: $aOutput[] = xajaxCompressFile(implode('', $aParsed));
873: }
874: }
875: }
876: }
877: }
878:
879: closedir($handle);
880: }
881:
882: if ($bWriteFile)
883: {
884: $fH = @fopen($sFolder . '/xajaxAIO.inc.php', 'w');
885: if (!$fH) {
886: trigger_error(
887: $this->objLanguageManager->getText('CMPRSAIO:WTERR:01')
888: . $sFolder
889: . $this->objLanguageManager->getText('CMPRSAIO:WTERR:02')
890: , E_USER_ERROR
891: );
892: }
893: else {
894: fwrite($fH, '<'.'?php ');
895: fwrite($fH, implode('', $aOutput));
896: fclose($fH);
897: }
898: }
899:
900: return implode('', $aOutput);
901: }
902:
903: /*
904: Function: _detectURI
905:
906: Returns the current requests URL based upon the SERVER vars.
907:
908: Returns:
909:
910: string : The URL of the current request.
911: */
912: private function _detectURI() {
913: $aURL = array();
914:
915: // Try to get the request URL
916: if (!empty($_SERVER['REQUEST_URI'])) {
917:
918: $_SERVER['REQUEST_URI'] = str_replace(
919: array('"',"'",'<','>'),
920: array('%22','%27','%3C','%3E'),
921: $_SERVER['REQUEST_URI']
922: );
923:
924: $aURL = parse_url($_SERVER['REQUEST_URI']);
925: }
926:
927: // Fill in the empty values
928: if (empty($aURL['scheme'])) {
929: if (!empty($_SERVER['HTTP_SCHEME'])) {
930: $aURL['scheme'] = $_SERVER['HTTP_SCHEME'];
931: } else {
932: $aURL['scheme'] =
933: (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off')
934: ? 'https'
935: : 'http';
936: }
937: }
938:
939: if (empty($aURL['host'])) {
940: if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
941: if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ':') > 0) {
942: list($aURL['host'], $aURL['port']) = explode(':', $_SERVER['HTTP_X_FORWARDED_HOST']);
943: } else {
944: $aURL['host'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
945: }
946: } else if (!empty($_SERVER['HTTP_HOST'])) {
947: if (strpos($_SERVER['HTTP_HOST'], ':') > 0) {
948: list($aURL['host'], $aURL['port']) = explode(':', $_SERVER['HTTP_HOST']);
949: } else {
950: $aURL['host'] = $_SERVER['HTTP_HOST'];
951: }
952: } else if (!empty($_SERVER['SERVER_NAME'])) {
953: $aURL['host'] = $_SERVER['SERVER_NAME'];
954: } else {
955: echo $this->objLanguageManager->getText('DTCTURI:01');
956: echo $this->objLanguageManager->getText('DTCTURI:02');
957: exit();
958: }
959: }
960:
961: if (empty($aURL['port']) && !empty($_SERVER['SERVER_PORT'])) {
962: $aURL['port'] = $_SERVER['SERVER_PORT'];
963: }
964:
965: if (!empty($aURL['path']))
966: if (0 == strlen(basename($aURL['path'])))
967: unset($aURL['path']);
968:
969: if (empty($aURL['path'])) {
970: $sPath = array();
971: if (!empty($_SERVER['PATH_INFO'])) {
972: $sPath = parse_url($_SERVER['PATH_INFO']);
973: } else {
974: $sPath = parse_url($_SERVER['PHP_SELF']);
975: }
976: if (isset($sPath['path']))
977: $aURL['path'] = str_replace(array('"',"'",'<','>'), array('%22','%27','%3C','%3E'), $sPath['path']);
978: unset($sPath);
979: }
980:
981: if (empty($aURL['query']) && !empty($_SERVER['QUERY_STRING'])) {
982: $aURL['query'] = $_SERVER['QUERY_STRING'];
983: }
984:
985: if (!empty($aURL['query'])) {
986: $aURL['query'] = '?'.$aURL['query'];
987: }
988:
989: // Build the URL: Start with scheme, user and pass
990: $sURL = $aURL['scheme'].'://';
991: if (!empty($aURL['user'])) {
992: $sURL.= $aURL['user'];
993: if (!empty($aURL['pass'])) {
994: $sURL.= ':'.$aURL['pass'];
995: }
996: $sURL.= '@';
997: }
998:
999: // Add the host
1000: $sURL.= $aURL['host'];
1001:
1002: // Add the port if needed
1003: if (!empty($aURL['port'])
1004: && (($aURL['scheme'] == 'http' && $aURL['port'] != 80)
1005: || ($aURL['scheme'] == 'https' && $aURL['port'] != 443))) {
1006: $sURL.= ':'.$aURL['port'];
1007: }
1008:
1009: // Add the path and the query string
1010: $sURL.= $aURL['path'].@$aURL['query'];
1011:
1012: // Clean up
1013: unset($aURL);
1014:
1015: $aURL = explode("?", $sURL);
1016:
1017: if (1 < count($aURL))
1018: {
1019: $aQueries = explode("&", $aURL[1]);
1020:
1021: foreach ($aQueries as $sKey => $sQuery)
1022: {
1023: if ("xjxGenerate" == substr($sQuery, 0, 11))
1024: unset($aQueries[$sKey]);
1025: }
1026:
1027: $sQueries = implode("&", $aQueries);
1028:
1029: $aURL[1] = $sQueries;
1030:
1031: $sURL = implode("?", $aURL);
1032: }
1033:
1034: return $sURL;
1035: }
1036:
1037: }
1038:
1039: /*
1040: Section: Global functions
1041: */
1042:
1043: /*
1044: Function xajaxErrorHandler
1045:
1046: This function is registered with PHP's set_error_handler if the xajax
1047: error handling system is enabled.
1048:
1049: See <xajax->bUserErrorHandler>
1050: */
1051: function xajaxErrorHandler($errno, $errstr, $errfile, $errline)
1052: {
1053: $errorReporting = error_reporting();
1054: if (($errno & $errorReporting) == 0) return;
1055:
1056: if ($errno == E_NOTICE) {
1057: $errTypeStr = 'NOTICE';
1058: }
1059: else if ($errno == E_WARNING) {
1060: $errTypeStr = 'WARNING';
1061: }
1062: else if ($errno == E_USER_NOTICE) {
1063: $errTypeStr = 'USER NOTICE';
1064: }
1065: else if ($errno == E_USER_WARNING) {
1066: $errTypeStr = 'USER WARNING';
1067: }
1068: else if ($errno == E_USER_ERROR) {
1069: $errTypeStr = 'USER FATAL ERROR';
1070: }
1071: else if (defined('E_STRICT') && $errno == E_STRICT) {
1072: return;
1073: }
1074: else {
1075: $errTypeStr = 'UNKNOWN: ' . $errno;
1076: }
1077:
1078: $sCrLf = "\n";
1079:
1080: ob_start();
1081: echo $GLOBALS['xajaxErrorHandlerText'];
1082: echo $sCrLf;
1083: echo '----';
1084: echo $sCrLf;
1085: echo '[';
1086: echo $errTypeStr;
1087: echo '] ';
1088: echo $errstr;
1089: echo $sCrLf;
1090: echo 'Error on line ';
1091: echo $errline;
1092: echo ' of file ';
1093: echo $errfile;
1094: $GLOBALS['xajaxErrorHandlerText'] = ob_get_clean();
1095: }
1096:
1097: