1: <?php
2: /**
3: * This abstract class should never be instantiated. It contains static methods,
4: * variables and constants to be used throughout the application.
5: *
6: * The static method "Initialize" should be called at the begin of the script by
7: * prepend.inc.
8: */
9: abstract class QApplicationBase extends QBaseClass {
10: //////////////////////////
11: // Public Static Variables
12: //////////////////////////
13:
14: /**
15: * The cache provider object used for caching ORM objects
16: * It is initialized below in Initialize(), based on the CACHE_PROVIDER and CACHE_PROVIDER_OPTIONS
17: * variables defined in configuration.inc.php
18: *
19: * @var QAbstractCacheProvider
20: */
21: public static $objCacheProvider = null;
22:
23: /**
24: * @var bool Set to true to turn on short-term caching. This is an in-memory cache that caches database
25: * objects only for as long as a single http request lasts. Depending on your application, this may speed
26: * up your database accesses. It DOES increase the amount of memory used in a request.
27: * */
28: public static $blnLocalCache = false;
29:
30: /**
31: * Internal bitmask signifying which BrowserType the user is using
32: * Use the QApplication::IsBrowser() method to do browser checking
33: *
34: * @var integer BrowserType
35: */
36: protected static $BrowserType = QBrowserType::Unsupported;
37:
38: /**
39: * @var float Major version number of browser
40: */
41: public static $BrowserVersion = null;
42:
43: /**
44: * Definition of CacheControl for the HTTP header. In general, it is
45: * recommended to keep this as "private". But this can/should be overriden
46: * for file/scripts that have special caching requirements (e.g. dynamically
47: * created images like QImageLabel).
48: *
49: * @var string CacheControl
50: */
51: public static $CacheControl = 'private';
52:
53: /**
54: * @var #P#C\QCrossScripting.Purify|?
55: * Defines the default mode for controls that need protection against
56: * cross-site scripting. Can be overridden at the individual control level,
57: * or for all controls by overriding it in QApplication.
58: *
59: * Set to QCrossScripting::Legacy for backward compatibility reasons for legacy applications;
60: * For new applications the recommended setting is QCrossScripting::Purify.
61: */
62: public static $DefaultCrossScriptingMode = QCrossScripting::Legacy;
63:
64: /**
65: * Path of the "web root" or "document root" of the web server
66: * Like "/home/www/htdocs" on Linux/Unix or "c:\inetpub\wwwroot" on Windows
67: *
68: * @var string DocumentRoot
69: */
70: public static $DocumentRoot;
71:
72: /**
73: * Whether or not we are currently trying to Process the Output of the page.
74: * Used by the OutputPage PHP output_buffering handler. As of PHP 5.2,
75: * this gets called whenever ob_get_contents() is called. Because some
76: * classes like QFormBase utilizes ob_get_contents() to perform template
77: * evaluation without wanting to actually perform OutputPage, this flag
78: * can be set/modified by QFormBase::EvaluateTemplate accordingly to
79: * prevent OutputPage from executing.
80: *
81: * Also set this to false if you are outputting custom headers, especially
82: * if you send your own "Content-Type" header.
83: *
84: * @var boolean ProcessOutput
85: */
86: public static $ProcessOutput = true;
87:
88: /**
89: * Full path of the actual PHP script being run
90: * Like "/home/www/htdocs/folder/script.php" on Linux/Unix
91: * or "c:\inetpub\wwwroot" on Windows
92: *
93: * @var string ScriptFilename
94: */
95: public static $ScriptFilename;
96:
97: /**
98: * Web-relative path of the actual PHP script being run
99: * So for "http://www.domain.com/folder/script.php",
100: * QApplication::$ScriptName would be "/folder/script.php"
101: *
102: * @var string ScriptName
103: */
104: public static $ScriptName;
105:
106: /**
107: * Extended Path Information after the script URL (if applicable)
108: * So for "http://www.domain.com/folder/script.php/15/225"
109: * QApplication::$PathInfo would be "/15/255"
110: *
111: * @var string PathInfo
112: */
113: public static $PathInfo;
114:
115: /**
116: * Query String after the script URL (if applicable)
117: * So for "http://www.domain.com/folder/script.php?item=15&value=22"
118: * QApplication::$QueryString would be "item=15&value=22"
119: *
120: * @var string QueryString
121: */
122: public static $QueryString;
123:
124: /**
125: * The full Request URI that was requested
126: * So for "http://www.domain.com/folder/script.php/15/25/?item=15&value=22"
127: * QApplication::$RequestUri would be "/folder/script.php/15/25/?item=15&value=22"
128: *
129: * @var string RequestUri
130: */
131: public static $RequestUri;
132:
133: /**
134: * The IP address of the server running the script/PHP application
135: * This is either the LOCAL_ADDR or the SERVER_ADDR server constant, depending
136: * on the server type, OS and configuration.
137: *
138: * @var string ServerAddress
139: */
140: public static $ServerAddress;
141:
142: /**
143: * The encoding type for the application (e.g. UTF-8, ISO-8859-1, etc.)
144: *
145: * @var string EncodingType
146: */
147: public static $EncodingType = "UTF-8";
148:
149: /**
150: * The content type to output.
151: *
152: * @var string ContentType
153: */
154: public static $ContentType = "text/html";
155:
156:
157: /**
158: * An array of Database objects, as initialized by QApplication::InitializeDatabaseConnections()
159: *
160: * @var QDatabaseBase[] Database
161: */
162: public static $Database;
163:
164: /**
165: * A flag to indicate whether or not this script is run as a CLI (Command Line Interface)
166: *
167: * @var boolean CliMode
168: */
169: public static $CliMode;
170:
171: /**
172: * Class File Array - used by QApplication::AutoLoad to more quickly load
173: * core class objects without making a file_exists call.
174: *
175: * @var array ClassFile
176: */
177: public static $ClassFile;
178:
179: /**
180: * Preloaded Class File Array - used by QApplication::Initialize to load
181: * any core class objects during Initailize()
182: *
183: * @var array ClassFile
184: */
185: public static $PreloadedClassFile;
186:
187: /**
188: * The QRequestMode enumerated value for the current request mode
189: *
190: * @var string RequestMode
191: */
192: public static $RequestMode;
193:
194: /**
195: * 2-letter country code to set for internationalization and localization
196: * (e.g. us, uk, jp)
197: *
198: * @var string CountryCode
199: */
200: public static $CountryCode;
201:
202: /**
203: * 2-letter language code to set for internationalization and localization
204: * (e.g. en, jp, etc.)
205: *
206: * @var string LanguageCode
207: */
208: public static $LanguageCode;
209:
210: /**
211: * The instance of the active QI18n object (which contains translation strings), if any.
212: *
213: * @var QTranslationBase $LanguageObject
214: */
215: public static $LanguageObject;
216:
217: /**
218: * True to force drawing to be minimized.
219: *
220: * @var bool
221: */
222: public static $Minimize = false;
223:
224: ////////////////////////
225: // Public Overrides
226: ////////////////////////
227: /**
228: * This faux constructor method throws a caller exception.
229: * The Application object should never be instantiated, and this constructor
230: * override simply guarantees it.
231: *
232: * @throws QCallerException
233: */
234: public final function __construct() {
235: throw new QCallerException('Application should never be instantiated. All methods and variables are publically statically accessible.');
236: }
237:
238:
239: ////////////////////////
240: // Public Static Methods
241: ////////////////////////
242:
243: /**
244: * This should be the first call to initialize all the static variables
245: * The application object also has static methods that are miscellaneous web
246: * development utilities, etc.
247: *
248: * @throws Exception
249: * @return void
250: */
251: public static function Initialize() {
252: self::$EncodingType = defined('__QAPPLICATION_ENCODING_TYPE__') ? __QAPPLICATION_ENCODING_TYPE__ : self::$EncodingType;
253:
254: // Are we running as CLI?
255: if (PHP_SAPI == 'cli')
256: QApplication::$CliMode = true;
257: else
258: QApplication::$CliMode = false;
259:
260: // Setup Server Address
261: if (array_key_exists('LOCAL_ADDR', $_SERVER))
262: QApplication::$ServerAddress = $_SERVER['LOCAL_ADDR'];
263: else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER))
264: QApplication::$ServerAddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
265: else if (array_key_exists('SERVER_ADDR', $_SERVER))
266: QApplication::$ServerAddress = $_SERVER['SERVER_ADDR'];
267:
268: // Setup ScriptFilename and ScriptName
269: QApplication::$ScriptFilename = $_SERVER['SCRIPT_FILENAME'];
270: QApplication::$ScriptName = $_SERVER['SCRIPT_NAME'];
271:
272: // Ensure both are set, or we'll have to abort
273: if ((!QApplication::$ScriptFilename) || (!QApplication::$ScriptName)) {
274: throw new Exception('Error on QApplication::Initialize() - ScriptFilename or ScriptName was not set');
275: }
276:
277: // Setup PathInfo and QueryString (if applicable)
278: QApplication::$PathInfo = null;
279: if(array_key_exists('PATH_INFO', $_SERVER)) {
280: QApplication::$PathInfo = urlencode(trim($_SERVER['PATH_INFO']));
281: QApplication::$PathInfo = str_ireplace('%2f', '/', QApplication::$PathInfo);
282: }
283: QApplication::$QueryString = array_key_exists('QUERY_STRING', $_SERVER) ? $_SERVER['QUERY_STRING'] : null;
284:
285: // Setup RequestUri
286: if (defined('__URL_REWRITE__')) {
287: switch (strtolower(__URL_REWRITE__)) {
288: case 'apache':
289: QApplication::$RequestUri = $_SERVER['REQUEST_URI'];
290: break;
291:
292: case 'none':
293: QApplication::$RequestUri = sprintf('%s%s%s',
294: QApplication::$ScriptName, QApplication::$PathInfo,
295: (QApplication::$QueryString) ? sprintf('?%s', QApplication::$QueryString) : null);
296: break;
297:
298: default:
299: throw new Exception('Invalid URL Rewrite type: ' . __URL_REWRITE__);
300: }
301: } else {
302: QApplication::$RequestUri = sprintf('%s%s%s',
303: QApplication::$ScriptName, QApplication::$PathInfo,
304: (QApplication::$QueryString) ? sprintf('?%s', QApplication::$QueryString) : null);
305: }
306:
307: // Setup DocumentRoot
308: QApplication::$DocumentRoot = trim(__DOCROOT__);
309:
310: // Setup Browser Type
311: if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
312: $strUserAgent = trim(strtolower($_SERVER['HTTP_USER_AGENT']));
313:
314: QApplication::$BrowserType = 0;
315:
316: // INTERNET EXPLORER (versions 6 through 10)
317: if (strpos($strUserAgent, 'msie') !== false) {
318: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::InternetExplorer;
319:
320: // just major version number. Will not see IE 10.6.
321: $matches = array();
322: preg_match ('#msie\s(.\d)#', $strUserAgent, $matches);
323: if ($matches) {
324: QApplication::$BrowserVersion = (int)$matches[1];
325: }
326: }
327: else if (strpos($strUserAgent, 'trident') !== false) {
328: // IE 11 significantly changes the user agent, and no longer includes 'MSIE'
329: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::InternetExplorer;
330:
331: $matches = array();
332: preg_match ('/rv:(.+)\)/', $strUserAgent, $matches);
333: if ($matches) {
334: QApplication::$BrowserVersion = (float)$matches[1];
335: }
336: // FIREFOX
337: } else if ((strpos($strUserAgent, 'firefox') !== false) || (strpos($strUserAgent, 'iceweasel') !== false)) {
338: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Firefox;
339: $strUserAgent = str_replace('iceweasel/', 'firefox/', $strUserAgent);
340:
341: $matches = array();
342: preg_match ('#firefox/(.+)#', $strUserAgent, $matches);
343: if ($matches) {
344: QApplication::$BrowserVersion = (float)$matches[1];
345: }
346: }
347: // CHROME, must come before safari because it also includes a safari string
348: elseif (strpos($strUserAgent, 'chrome') !== false) {
349: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Chrome;
350:
351: // find major version number only
352: $matches = array();
353: preg_match ('#chrome/(\d+)#', $strUserAgent, $matches);
354: if ($matches) {
355: QApplication::$BrowserVersion = (int)$matches[1];
356: }
357: }
358: // SAFARI
359: elseif (strpos($strUserAgent, 'safari') !== false) {
360: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Safari;
361:
362: $matches = array();
363: preg_match ('#version/(.+)\s#', $strUserAgent, $matches);
364: if ($matches) {
365: QApplication::$BrowserVersion = (float)$matches[1];
366: }
367: }
368: // KONQUEROR
369: elseif (strpos($strUserAgent, 'konqueror') !== false) {
370: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Konqueror;
371:
372: // only looking at major version number on this one
373: $matches = array();
374: preg_match ('#konqueror/(\d+)#', $strUserAgent, $matches);
375: if ($matches) {
376: QApplication::$BrowserVersion = (int)$matches[1];
377: }
378: }
379:
380: // OPERA
381: elseif (strpos($strUserAgent, 'opera') !== false) {
382: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Opera;
383:
384: // two different patterns;
385: $matches = array();
386: preg_match ('#version/(\d+)#', $strUserAgent, $matches);
387: if ($matches) {
388: QApplication::$BrowserVersion = (int)$matches[1];
389: } else {
390: preg_match ('#opera\s(.+)#', $strUserAgent, $matches);
391: if ($matches) {
392: QApplication::$BrowserVersion = (float)$matches[1];
393: }
394: }
395: }
396:
397: // Unknown
398: if (QApplication::$BrowserType == 0)
399: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Unsupported;
400:
401: // OS (supporting Windows, Linux and Mac)
402: if (strpos($strUserAgent, 'windows') !== false)
403: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Windows;
404: elseif (strpos($strUserAgent, 'linux') !== false)
405: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Linux;
406: elseif (strpos($strUserAgent, 'macintosh') !== false)
407: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Macintosh;
408:
409: // Mobile version of one of the above browsers, or some other unknown browser
410: if (strpos($strUserAgent, 'mobi') !== false) // opera is just 'mobi', everyone else uses 'mobile'
411: QApplication::$BrowserType = QApplication::$BrowserType | QBrowserType::Mobile;
412: }
413:
414: // Preload Class Files
415: foreach (QApplication::$PreloadedClassFile as $strClassFile) {
416: require($strClassFile);
417: }
418:
419: // Initialize any classes that might call into the autoloader
420: $strCacheProviderClass = 'QCacheProviderNoCache';
421: if (defined('CACHE_PROVIDER_CLASS')) {
422: $strCacheProviderClass = CACHE_PROVIDER_CLASS;
423: }
424: if ($strCacheProviderClass) {
425: if (defined('CACHE_PROVIDER_OPTIONS')) {
426: QApplicationBase::$objCacheProvider = new $strCacheProviderClass(unserialize(CACHE_PROVIDER_OPTIONS));
427: } else {
428: QApplicationBase::$objCacheProvider = new $strCacheProviderClass();
429: }
430: }
431:
432: if (defined('__MINIMIZE__') && __MINIMIZE__) {
433: QApplicationBase::$Minimize = true;
434: }
435: }
436:
437: /**
438: * Checks for the type of browser in use by the client.
439: * @static
440: * @param int $intBrowserType
441: * @return int
442: */
443: public static function IsBrowser($intBrowserType) {
444: return ($intBrowserType & QApplication::$BrowserType);
445: }
446:
447: /**
448: * This call will initialize the database connection(s) as defined by
449: * the constants DB_CONNECTION_X, where "X" is the index number of a
450: * particular database connection.
451: *
452: * @throws Exception
453: * @return void
454: */
455: public static function InitializeDatabaseConnections() {
456: // for backward compatibility, don't use MAX_DB_CONNECTION_INDEX directly,
457: // but check if MAX_DB_CONNECTION_INDEX is defined
458: $intMaxIndex = defined('MAX_DB_CONNECTION_INDEX') ? constant('MAX_DB_CONNECTION_INDEX') : 9;
459:
460: if (defined('DB_CONNECTION_0')) {
461: // This causes a conflict with how DbBackedSessionHandler works.
462: throw new Exception('Do not define DB_CONNECTION_0. Start at DB_CONNECTION_1');
463: }
464:
465: for ($intIndex = 1; $intIndex <= $intMaxIndex; $intIndex++) {
466: $strConstantName = sprintf('DB_CONNECTION_%s', $intIndex);
467:
468: if (defined($strConstantName)) {
469: // Expected Keys to be Set
470: $strExpectedKeys = array(
471: 'adapter', 'server', 'port', 'database',
472: 'username', 'password', 'profiling', 'dateformat'
473: );
474:
475: // Lookup the Serialized Array from the DB_CONFIG constants and unserialize it
476: $strSerialArray = constant($strConstantName);
477: $objConfigArray = unserialize($strSerialArray);
478:
479: // Set All Expected Keys
480: foreach ($strExpectedKeys as $strExpectedKey)
481: if (!array_key_exists($strExpectedKey, $objConfigArray))
482: $objConfigArray[$strExpectedKey] = null;
483:
484: if (!$objConfigArray['adapter'])
485: throw new Exception('No Adapter Defined for ' . $strConstantName . ': ' . var_export($objConfigArray, true));
486:
487: if (!$objConfigArray['server'])
488: throw new Exception('No Server Defined for ' . $strConstantName . ': ' . constant($strConstantName));
489:
490: $strDatabaseType = 'Q' . $objConfigArray['adapter'] . 'Database';
491: if (!class_exists($strDatabaseType)) {
492: $strDatabaseAdapter = sprintf('%s/database/%s.class.php', __QCUBED_CORE__, $strDatabaseType);
493: if (!file_exists($strDatabaseAdapter))
494: throw new Exception('Database Type is not valid: ' . $objConfigArray['adapter']);
495: require($strDatabaseAdapter);
496: }
497:
498: QApplication::$Database[$intIndex] = new $strDatabaseType($intIndex, $objConfigArray);
499: }
500: }
501: }
502:
503: public static function SessionOverride() {
504: // Are we using QDbBackedSessionHandler?
505: if (defined("DB_BACKED_SESSION_HANDLER_DB_INDEX") &&
506: constant("DB_BACKED_SESSION_HANDLER_DB_INDEX") != 0 && defined("DB_BACKED_SESSION_HANDLER_TABLE_NAME")) {
507: // Yes we are going to override PHP's default file based handlers.
508: QDbBackedSessionHandler::Initialize(DB_BACKED_SESSION_HANDLER_DB_INDEX, DB_BACKED_SESSION_HANDLER_TABLE_NAME);
509: }
510: }
511:
512: /**
513: * This is called by the PHP5 Autoloader. This static method can be overridden.
514: *
515: * @param $strClassName
516: * @return boolean whether or not a class was found / included
517: */
518: public static function Autoload($strClassName) {
519: if (isset(QApplication::$ClassFile[strtolower($strClassName)])) {
520: require_once (QApplication::$ClassFile[strtolower($strClassName)]);
521: return true;
522: } else if (file_exists($strFilePath = sprintf('%s/%s.class.php', __INCLUDES__, $strClassName))) {
523: require_once ($strFilePath);
524: return true;
525: } else if (file_exists($strFilePath = sprintf('%s/controls/%s.class.php', __INCLUDES__, $strClassName))) {
526: require_once ($strFilePath);
527: return true;
528: } else if (file_exists($strFilePath = sprintf('%s/plugins/%s.php', __INCLUDES__, $strClassName))) {
529: require_once ($strFilePath);
530: return true;
531: } else if (false !== ($intStart = strpos($strClassName, 'QCubed\\Plugin\\'))) {
532: $strClassName = substr($strClassName, $intStart + 14);
533: if (file_exists($strFilePath = sprintf('%s/plugins/%s.php', __INCLUDES__, $strClassName))) {
534: require_once ($strFilePath);
535: return true;
536: }
537: }
538:
539: return false;
540: }
541:
542: /**
543: * Temprorarily overrides the default error handling mechanism. Remember to call
544: * RestoreErrorHandler to restore the error handler back to the default.
545: *
546: * @param string $strName the name of the new error handler function, or NULL if none
547: * @param integer $intLevel if a error handler function is defined, then the new error reporting level (if any)
548: *
549: * @throws QCallerException
550: */
551: public static function SetErrorHandler($strName, $intLevel = null) {
552: if (!is_null(QApplicationBase::$intStoredErrorLevel))
553: throw new QCallerException('Error handler is already currently overridden. Cannot override twice. Call RestoreErrorHandler before calling SetErrorHandler again.');
554: if (!$strName) {
555: // No Error Handling is wanted -- simulate a "On Error, Resume" type of functionality
556: set_error_handler('QcubedHandleError', 0);
557: QApplicationBase::$intStoredErrorLevel = error_reporting(0);
558: } else {
559: set_error_handler($strName, $intLevel);
560: QApplicationBase::$intStoredErrorLevel = -1;
561: }
562: }
563:
564: /**
565: * Restores the temporarily overridden default error handling mechanism back to the default.
566: */
567: public static function RestoreErrorHandler() {
568: if (is_null(QApplicationBase::$intStoredErrorLevel))
569: throw new QCallerException('Error handler is not currently overridden. Cannot reset something that was never overridden.');
570: if (QApplicationBase::$intStoredErrorLevel != -1)
571: error_reporting(QApplicationBase::$intStoredErrorLevel);
572: restore_error_handler();
573: QApplicationBase::$intStoredErrorLevel = null;
574: }
575:
576: /** @var null|int Stored Error Level (used for Settings and Restoring error handler) */
577: private static $intStoredErrorLevel = null;
578:
579: /**
580: * Create a directory on file system
581: *
582: * @param string $strPath Path of the directory to be created
583: * @param null|int $intMode Octal representation of permissions ('0755' style)
584: *
585: * @return bool
586: */
587: public static function MakeDirectory($strPath, $intMode = null) {
588: return QFolder::MakeDirectory($strPath, $intMode);
589: }
590:
591:
592: /**
593: * This will redirect the user to a new web location. This can be a relative or absolute web path, or it
594: * can be an entire URL.
595: *
596: * TODO: break this into two routines, since the resulting UI behavior is really different. Redirect and LoadPage??
597: *
598: * @param string $strLocation target patch
599: * @param bool $blnAbortCurrentScript Whether to abort the current script, or finish it out so data gets saved.
600: * @return void
601: */
602: public static function Redirect($strLocation, $blnAbortCurrentScript = true) {
603:
604: if (!$blnAbortCurrentScript) {
605: // Use the javascript command mechanism
606: QApplication::$JavascriptCommandArray[QAjaxResponse::Location] = $strLocation;
607: }
608: else {
609: global $_FORM;
610:
611: if ($_FORM) {
612: $_FORM->SaveControlState();
613: }
614:
615: // Clear the output buffer (if any)
616: ob_clean();
617:
618: if ((QApplication::$RequestMode == QRequestMode::Ajax) ||
619: (array_key_exists('Qform__FormCallType', $_POST) &&
620: ($_POST['Qform__FormCallType'] == QCallType::Ajax))) {
621: QApplication::SendAjaxResponse(array(QAjaxResponse::Location => $strLocation));
622: } else {
623: // Was "DOCUMENT_ROOT" set?
624: if (array_key_exists('DOCUMENT_ROOT', $_SERVER) && ($_SERVER['DOCUMENT_ROOT'])) {
625: // If so, we're likely using PHP as a Plugin/Module
626: // Use 'header' to redirect
627: header(sprintf('Location: %s', $strLocation));
628: } else {
629: // We're likely using this as a CGI
630: // Use JavaScript to redirect
631: printf('<script type="text/javascript">document.location = "%s";</script>', $strLocation);
632: }
633: }
634:
635: // End the Response Script
636: session_write_close();
637: exit();
638: }
639: }
640:
641:
642: /**
643: * This will close the window.
644: *
645: * @param bool $blnAbortCurrentScript Whether to abort the current script, or finish it out so data gets saved.
646: * @return void
647: */
648: public static function CloseWindow($blnAbortCurrentScript = false) {
649: if (!$blnAbortCurrentScript) {
650: // Use the javascript command mechanism
651: QApplication::$JavascriptCommandArray[QAjaxResponse::Close] = true;
652: }
653: else {
654: // Clear the output buffer (if any)
655: ob_clean();
656:
657: if (QApplication::$RequestMode == QRequestMode::Ajax) {
658: // AJAX-based Response
659: $aResponse[QAjaxResponse::Close] = 1;
660: QApplication::SendAjaxResponse($aResponse);
661: } else {
662: // Use JavaScript to close
663: _p('<script type="text/javascript">window.close();</script>', false);
664: }
665:
666: // End the Response Script
667: exit();
668: }
669: }
670:
671: /**
672: * Set a cookie. Allows setting of cookies in responses to ajax requests.
673: *
674: * @param string $strName
675: * @param sring $strValue
676: * @param QDatTime $dttTimeout
677: * @param string $strPath
678: * @param null|string $strDomain
679: * @param bool $blnSecure
680: */
681: public static function SetCookie($strName, $strValue, QDateTime $dttTimeout, $strPath = '/', $strDomain = null, $blnSecure = false) {
682: if (QApplication::$RequestMode == QRequestMode::Ajax) {
683: self::ExecuteJsFunction ('qcubed.setCookie', $strName, $strValue, $dttTimeout, $strPath, $strDomain, $blnSecure);
684: }
685: else {
686: setcookie($strName, $strValue, $dttTimeout->Timestamp, $strPath, $strDomain, $blnSecure);
687: }
688: }
689:
690: /**
691: * Delete's the given cookie IF its set. In other words, you cannot set a cookie and then delete a cookie right away before the
692: * cookie gets sent to the browser.
693: *
694: * @param $strName
695: */
696: public static function DeleteCookie($strName) {
697: if (isset($_COOKIE[$strName])) { // don't post a cookie if its not set
698: $dttTimeout = QDateTime::Now();
699: $dttTimeout->AddYears(-5);
700:
701: self::SetCookie($strName, "", $dttTimeout);
702: }
703: }
704:
705: /**
706: * Gets the value of the QueryString item $strItem. Will return NULL if it doesn't exist.
707: *
708: * @param string $strItem the parameter name
709: *
710: * @return string value of the parameter
711: */
712: public static function QueryString($strItem) {
713: if (array_key_exists($strItem, $_GET))
714: return $_GET[$strItem];
715: else
716: return null;
717: }
718:
719: /**
720: * Generates a valid URL Query String based on values in the provided array. If no array is provided, it uses the global $_GET
721: * @param array $arr
722: * @return string
723: */
724: public static function GenerateQueryString($arr = null) {
725: if(null === $arr)
726: $arr = $_GET;
727: if (count($arr)) {
728: $strToReturn = '';
729: foreach ($arr as $strKey => $mixValue)
730: $strToReturn .= QApplication::GenerateQueryStringHelper(urlencode($strKey), $mixValue);
731: return '?' . substr($strToReturn, 1);
732: } else
733: return '';
734: }
735:
736: /**
737: * Generates part of query string (helps in generating the complete query string)
738: * @param string $strKey Key for the query string
739: * @param string|integer|array $mixValue Value we have to put as the value of the key
740: *
741: * @return null|string
742: */
743: protected static function GenerateQueryStringHelper($strKey, $mixValue) {
744: if (is_array($mixValue)) {
745: $strToReturn = null;
746: foreach ($mixValue as $strSubKey => $mixSubValue) {
747: $strToReturn .= QApplication::GenerateQueryStringHelper($strKey . '[' . $strSubKey . ']', $mixSubValue);
748: }
749: return $strToReturn;
750: } else
751: return '&' . $strKey . '=' . urlencode($mixValue);
752: }
753:
754: /**
755: * By default, this is used by the codegen and form drafts to do a quick check
756: * on the ALLOW_REMOTE_ADMIN constant (as defined in configuration.inc.php). If enabled,
757: * then anyone can access the page. If disabled, only "localhost" can access the page.
758: * If you want to run a script that should be accessible regardless of
759: * ALLOW_REMOTE_ADMIN, simply remove the CheckRemoteAdmin() method call from that script.
760: *
761: * @throws QRemoteAdminDeniedException
762: * @return void
763: */
764: public static function CheckRemoteAdmin() {
765: if (!QApplication::IsRemoteAdminSession()) {
766: return;
767: }
768:
769: // If we're here -- then we're not allowed to access. Present the Error/Issue.
770: header($_SERVER['SERVER_PROTOCOL'] . ' 401 Access Denied');
771: header('Status: 401 Access Denied', true);
772:
773: throw new QRemoteAdminDeniedException();
774: }
775:
776: /**
777: * Checks whether the current request was made by an ADMIN
778: * This does not refer to your Database admin or an Admin user defined in your application but an IP address
779: * (or IP address range) defined in configuration.inc.php.
780: *
781: * The function can be used to restrict access to sensitive pages to a list of IPs (or IP ranges), such as the LAN to which
782: * the server hosting the QCubed application is connected.
783: * @static
784: * @return bool
785: */
786: public static function IsRemoteAdminSession() {
787: // Allow Remote?
788: if (ALLOW_REMOTE_ADMIN === true)
789: return false;
790:
791: // Are we localhost?
792: if (substr($_SERVER['REMOTE_ADDR'],0,4) == '127.' || $_SERVER['REMOTE_ADDR'] == '::1')
793: return false;
794:
795: // Are we the correct IP?
796: if (is_string(ALLOW_REMOTE_ADMIN))
797: foreach (explode(',', ALLOW_REMOTE_ADMIN) as $strIpAddress) {
798: if (QApplication::IsIPInRange($_SERVER['REMOTE_ADDR'], $strIpAddress) ||
799: (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER) && (QApplication::IsIPInRange($_SERVER['HTTP_X_FORWARDED_FOR'], $strIpAddress)))) {
800: return false;
801: }
802: }
803:
804: return true;
805: }
806:
807: /**
808: * Checks whether the given IP falls into the given IP range
809: * @static
810: * @param string $ip the IP number to check
811: * @param string $range the IP number range. The range could be in 'IP/mask' or 'IP - IP' format. mask could be a simple
812: * integer or a dotted netmask.
813: * @return bool
814: */
815: public static function IsIPInRange($ip, $range) {
816: $ip = trim($ip);
817: if (strpos($range, '/') !== false) {
818: // we are given a IP/mask
819: list($net, $mask) = explode('/', $range);
820: $net = ip2long(trim($net));
821: $mask = trim($mask);
822: //$ip_net = ip2long($net);
823: if (strpos($mask, '.') !== false) {
824: // mask has the dotted notation
825: $ip_mask = ip2long($mask);
826: } else {
827: // mask is an integer
828: $ip_mask = ~((1 << (32 - $mask)) - 1);
829: }
830: $ip = ip2long($ip);
831: return ($net & $ip_mask) == ($ip & $ip_mask);
832: }
833: if (strpos($range, '-') !== false) {
834: // we are given an IP - IP range
835: list($first, $last) = explode('-', $range);
836: $first = ip2long(trim($first));
837: $last = ip2long(trim($last));
838: $ip = ip2long($ip);
839: return $first <= $ip && $ip <= $last;
840: }
841:
842: // $range is a simple IP
843: return $ip == trim($range);
844: }
845:
846: /**
847: * Gets the value of the PathInfo item at index $intIndex. Will return NULL if it doesn't exist.
848: *
849: * The way PathInfo index is determined is, for example, given a URL '/folder/page.php/id/15/blue',
850: * QApplication::PathInfo(0) will return 'id'
851: * QApplication::PathInfo(1) will return '15'
852: * QApplication::PathInfo(2) will return 'blue'
853: *
854: * @param int $intIndex index
855: * @return string|null
856: */
857: public static function PathInfo($intIndex) {
858: // TODO: Cache PathInfo
859: $strPathInfo = urldecode(QApplication::$PathInfo);
860:
861: // Remove Starting '/'
862: if (QString::FirstCharacter($strPathInfo) == '/')
863: $strPathInfo = substr($strPathInfo, 1);
864:
865: $strPathInfoArray = explode('/', $strPathInfo);
866:
867: if (array_key_exists($intIndex, $strPathInfoArray))
868: return $strPathInfoArray[$intIndex];
869: else
870: return null;
871: }
872:
873: /**
874: * If this particular item is set, we ensure that this command, and only this command will get invoked on the
875: * next response. The rest of the commands will wait until the next response.
876: *
877: * @var null|array;
878: */
879: public static $JavascriptExclusiveCommand = null;
880:
881: /** @var array A structured array of commands to be sent to either the ajax response, or page output.
882: * Replaces the AlertMessageArray, JavaScriptArray, JavaScriptArrayHighPriority, and JavaScriptArrayLowPriority.
883: */
884: protected static $JavascriptCommandArray = array();
885:
886: /** @var array JS files to be added to the list of files in front of the javascript commands. Should include jquery, etc. */
887: protected static $JavascriptFileArray = array();
888:
889: /*
890: public static $AlertMessageArray = array();
891: public static $JavaScriptArray = array();
892: public static $JavaScriptArrayHighPriority = array();
893: public static $JavaScriptArrayLowPriority = array();
894: public static $ControlCommands = array();*/
895:
896: /** @var bool Used to determine if an error has occurred */
897: public static $ErrorFlag = false;
898:
899: /**
900: * Causes the browser to display a JavaScript alert() box with supplied message
901: * @param string $strMessage Message to be displayed
902: */
903: public static function DisplayAlert($strMessage) {
904: QApplication::$JavascriptCommandArray[QAjaxResponse::Alert][] = $strMessage;
905: }
906:
907: /**
908: * This class can be used to call a Javascript function in the client browser from the server side.
909: * Can be used inside event handlers to do something after verification on server side.
910: *
911: * TODO: Since this is implemented with an "eval" on the client side in ajax, we should phase this out in favor
912: * of specific commands sent to the client.
913: *
914: * @static
915: * @deprecated Will be eventually removed. If you need to do something in javascript, add it to QAjaxResponse.
916: * @param string $strJavaScript the javascript to execute
917: * @param string $strPriority
918: * @throws QCallerException
919: */
920: public static function ExecuteJavaScript($strJavaScript, $strPriority = QJsPriority::Standard) {
921: if (is_bool($strPriority)) {
922: //we keep this codepath for backward compatibility
923: if ($strPriority === true) {
924: throw new QCallerException('Please specify a correct priority value');
925: }
926: } else {
927: switch ($strPriority) {
928: case QJsPriority::High:
929: QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsHigh][] = ['script'=>$strJavaScript];
930: break;
931: case QJsPriority::Low:
932: QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsLow][] = ['script'=>$strJavaScript];
933: break;
934: case QJsPriority::Exclusive:
935: QApplication::$JavascriptExclusiveCommand = ['script'=>$strJavaScript];
936: break;
937: default:
938: QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsMedium][] = ['script'=>$strJavaScript];
939: break;
940: }
941: }
942: }
943:
944: /**
945: * Execute a function on a particular control. Many javascript widgets are structured this way, and this gives us
946: * a general purpose way of sending commands to widgets without an 'eval' on the client side.
947: *
948: * Commands will be executed in the order received, along with ExecuteJavaScript commands and ExecuteObjectCommands.
949: * If you want to force a command to execute first, give it high priority, or last, give it low priority.
950: *
951: * @param string $strControlId Id of control to direct the command to.
952: * @param string $strFunctionName Function name to call. For jQueryUI, this would be the widget name
953: * @param string $strFunctionName,... Unlimited OPTIONAL parameters to use as a parameter list to the function. List can
954: * end with a QJsPriority to prioritize the command.
955: */
956: public static function ExecuteControlCommand ($strControlId, $strFunctionName /*, ..., QJsPriority */) {
957: $args = func_get_args();
958: $args[0] = '#' . $strControlId;
959: call_user_func_array('QApplication::ExecuteSelectorFunction', $args);
960: }
961:
962: /**
963: * Call a function on a jQuery selector. The selector can be a single string, or an array where the first
964: * item is a selector specifying the items within the context of the second selector.
965: *
966: * @param array|string $mixSelector
967: * @param string $strFunctionName
968: * @param string $strFunctionName,... Unlimited OPTIONAL parameters to use as a parameter list to the function. List can
969: * end with a QJsPriority to prioritize the command.
970: * @throws QCallerException
971: */
972: public static function ExecuteSelectorFunction ($mixSelector, $strFunctionName /*, ..., QJsPriority */) {
973: if (!(is_string($mixSelector) || (is_array($mixSelector) && count($mixSelector) == 2))) {
974: throw new QCallerException ('Selector must be a string or an array of two items');
975: }
976: $args = func_get_args();
977: array_shift ($args);
978: array_shift ($args);
979: if ($args && end($args) === QJsPriority::High) {
980: $code = QAjaxResponse::CommandsHigh;
981: array_pop($args);
982: }
983: elseif ($args && end($args) === QJsPriority::Low) {
984: $code = QAjaxResponse::CommandsLow;
985: array_pop($args);
986: }
987: elseif ($args && end($args) === QJsPriority::Exclusive) {
988: array_pop($args);
989: QApplication::$JavascriptExclusiveCommand = ['selector'=>$mixSelector, 'func'=>$strFunctionName, 'params'=>$args];
990: return;
991: } else {
992: $code = QAjaxResponse::CommandsMedium;
993: }
994: if (empty($args)) {
995: $args = null;
996: }
997:
998: QApplication::$JavascriptCommandArray[$code][] = ['selector'=>$mixSelector, 'func'=>$strFunctionName, 'params'=>$args];
999: }
1000:
1001:
1002: /**
1003: * Call the given function with the given arguments. If just a function name, then the window object is searched.
1004: * The function can be inside an object accessible from the global namespace by separating with periods.
1005: * @param string $strFunctionName Can be namespaced, as in "qcubed.func".
1006: * @param string $strFunctionName,... Unlimited OPTIONAL parameters to use as a parameter list to the function. List can
1007: * end with a QJsPriority to prioritize the command.
1008: */
1009: public static function ExecuteJsFunction($strFunctionName /*, ... */) {
1010: $args = func_get_args();
1011: array_shift ($args);
1012: if ($args && end($args) === QJsPriority::High) {
1013: $code = QAjaxResponse::CommandsHigh;
1014: array_pop($args);
1015: }
1016: elseif ($args && end($args) === QJsPriority::Low) {
1017: $code = QAjaxResponse::CommandsLow;
1018: array_pop($args);
1019: }
1020: elseif ($args && end($args) === QJsPriority::Exclusive) {
1021: array_pop($args);
1022: QApplication::$JavascriptExclusiveCommand = ['func'=>$strFunctionName, 'params'=>$args];
1023: return;
1024: }
1025: else {
1026: $code = QAjaxResponse::CommandsMedium;
1027: }
1028: if (empty($args)) {
1029: $args = null;
1030: }
1031:
1032: QApplication::$JavascriptCommandArray[$code][] = ['func'=>$strFunctionName, 'params'=>$args];
1033: }
1034:
1035: /**
1036: * One time add of style sheets, to be used by QForm only for last minute style sheet injection.
1037: * @param string[] $strStyleSheetArray
1038: */
1039: public static function AddStyleSheets (array $strStyleSheetArray) {
1040: if (empty(QApplication::$JavascriptCommandArray[QAjaxResponse::StyleSheets])) {
1041: QApplication::$JavascriptCommandArray[QAjaxResponse::StyleSheets] = $strStyleSheetArray;
1042: }
1043: else {
1044: QApplication::$JavascriptCommandArray[QAjaxResponse::StyleSheets] =
1045: array_merge (QApplication::$JavascriptCommandArray[QAjaxResponse::StyleSheets], $strStyleSheetArray);
1046: }
1047: }
1048:
1049: /**
1050: * Add an array of javascript files for one-time inclusion. Called by QForm. Do not call.
1051: * @param string[] $strJavaScriptFileArray
1052: */
1053: public static function AddJavaScriptFiles ($strJavaScriptFileArray) {
1054: if (empty(QApplication::$JavascriptFileArray[QAjaxResponse::JavaScripts])) {
1055: QApplication::$JavascriptFileArray[QAjaxResponse::JavaScripts] = $strJavaScriptFileArray;
1056: }
1057: else {
1058: QApplication::$JavascriptFileArray[QAjaxResponse::JavaScripts] =
1059: array_merge (QApplication::$JavascriptFileArray[QAjaxResponse::JavaScripts], $strJavaScriptFileArray);
1060: }
1061: }
1062:
1063: /**
1064: * Outputs the current page with the buffer data
1065: * @param string $strBuffer Buffer data
1066: *
1067: * @return string
1068: */
1069: public static function OutputPage($strBuffer) {
1070: // If the ProcessOutput flag is set to false, simply return the buffer
1071: // without processing anything.
1072: if (!QApplication::$ProcessOutput)
1073: return $strBuffer;
1074:
1075: if (QApplication::$ErrorFlag) {
1076: return $strBuffer;
1077: } else {
1078: if (QApplication::$RequestMode == QRequestMode::Ajax) {
1079: return trim($strBuffer);
1080: } else {
1081: // Update Cache-Control setting
1082: header('Cache-Control: ' . QApplication::$CacheControl);
1083: // make sure the server does not override the character encoding value by explicitly sending it out as a header.
1084: // some servers will use an internal default if not specified in the header, and that will override the "encoding" value sent in the text.
1085: header(sprintf('Content-Type: %s; charset=%s', strtolower(QApplication::$ContentType), strtolower(QApplication::$EncodingType)));
1086:
1087: /*
1088: * Normally, FormBase->RenderEnd will render the javascripts. In the unusual case
1089: * of not rendering with a QForm object, this will still output embedded javascript commands.
1090: */
1091: $strScript = QApplicationBase::RenderJavascript();
1092: if ($strScript) {
1093: return $strBuffer . '<script type="text/javascript">' . $strScript . '</script>';
1094: }
1095:
1096: return $strBuffer;
1097: }
1098: }
1099: }
1100:
1101: public static function StartOutputBuffering() {
1102: if (php_sapi_name() !== 'cli' && // Do not buffer the command line interface
1103: !defined('__NO_OUTPUT_BUFFER__')) {
1104:
1105: ob_start('QApplicationBase::EndOutputBuffering');
1106: }
1107: }
1108:
1109: public static function EndOutputBuffering($strBuffer) {
1110: return QApplication::OutputPage($strBuffer);
1111: }
1112:
1113:
1114: /**
1115: * Render scripts for injecting files into the html output. This is for server only, not ajax.
1116: * This list will appear ahead of the javascript commands rendered below.
1117: *
1118: * @static
1119: * @return string
1120: */
1121: public static function RenderFiles() {
1122: $strScript = '';
1123:
1124: // Javascript files should get processed before the commands.
1125: if (!empty(QApplication::$JavascriptFileArray[QAjaxResponse::JavaScripts])) {
1126: foreach (QApplication::$JavascriptFileArray[QAjaxResponse::JavaScripts] as $js) {
1127: $strScript .= sprintf('<script type="text/javascript" src="%s"></script>', QApplication::GetJsFileUri($js)) . "\n";
1128: }
1129: }
1130:
1131: QApplication::$JavascriptFileArray = array();
1132:
1133: return $strScript;
1134: }
1135:
1136: /**
1137: * Function renders all the Javascript commands as output to the client browser. This is a mirror of what
1138: * occurs in the success function in the qcubed.js ajax code.
1139: *
1140: * @param $blnBeforeControls True to only render the javascripts that need to come before the controls are defined.
1141: * This is used to break the commands issued into two groups.
1142: * @static
1143: * @return string
1144: */
1145: public static function RenderJavascript($blnBeforeControls = false) {
1146: $strScript = '';
1147:
1148: // Style sheet injection by a control. Not very common, as other ways of adding style sheets would normally be done first.
1149: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::StyleSheets])) {
1150: $str = '';
1151: foreach (QApplication::$JavascriptCommandArray[QAjaxResponse::StyleSheets] as $ss) {
1152: $str .= 'qc.loadStyleSheetFile("' . $ss . '", "all"); ';
1153: }
1154: QApplication::$JavascriptCommandArray[QAjaxResponse::StyleSheets] = null;
1155: }
1156:
1157: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::Alert])) {
1158: foreach (QApplication::$JavascriptCommandArray[QAjaxResponse::Alert] as $strAlert) {
1159: $strAlert = json_encode($strAlert);
1160: $strScript .= sprintf('alert(%s); ', $strAlert);
1161: }
1162: QApplication::$JavascriptCommandArray[QAjaxResponse::Alert] = null;
1163: }
1164:
1165: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsHigh])) {
1166: $strScript .= self::RenderCommandArray(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsHigh]);
1167: QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsHigh] = null;
1168: }
1169:
1170: if ($blnBeforeControls) return $strScript; // When we call again, everything above here will be skipped since we are emptying the arrays
1171:
1172: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsMedium])) {
1173: $strScript .= self::RenderCommandArray(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsMedium]);
1174: QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsMedium] = null;
1175: }
1176:
1177: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsLow])) {
1178: $strScript .= self::RenderCommandArray(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsLow]);
1179: }
1180:
1181: // A QApplication::Redirect
1182: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::Location])) {
1183: $strLocation = QApplication::$JavascriptCommandArray[QAjaxResponse::Location];
1184: $strScript .= sprintf('document.location = "%s";', $strLocation);
1185: }
1186: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::Close])) {
1187: $strScript .= 'window.close();';
1188: }
1189:
1190: QApplication::$JavascriptCommandArray = array();
1191:
1192: return $strScript;
1193: }
1194:
1195: private static function RenderCommandArray(array $commandArray) {
1196: $strScript = '';
1197: foreach ($commandArray as $command) {
1198: if (isset($command['script'])) { // a script to use eval on
1199: $strScript .= sprintf('%s;', $command['script']) . _nl();
1200: }
1201: elseif (isset($command['selector'])) { // a control function
1202: if (is_array($command['selector'])) {
1203: $strSelector = sprintf('"%s", "%s"', $command['selector'][0], $command['selector'][1]);
1204: }
1205: else {
1206: $strSelector = '"' . $command['selector'] . '"';
1207: }
1208:
1209: if ($params = $command['params']) {
1210: $objParams = new QJsParameterList($params);
1211: $strParams = $objParams->toJsObject();
1212: } else {
1213: $strParams = '';
1214: }
1215: $strScript .= sprintf ('jQuery(%s).%s(%s);', $strSelector, $command['func'], $strParams) . _nl();
1216: }
1217: elseif (isset($command['func'])) { // a function call
1218: if ($params = $command['params']) {
1219: $objParams = new QJsParameterList($params);
1220: $strParams = $objParams->toJsObject();
1221: }
1222: else {
1223: $strParams = '';
1224: }
1225: $strScript .= sprintf ('%s(%s);', $command['func'], $strParams) . _nl();
1226: }
1227: }
1228: return $strScript;
1229: }
1230:
1231: /**
1232: * Return the javascript command array, for use by form ajax response. Will erase the command array, so
1233: * the form better use it.
1234: * @static
1235: * @return array
1236: */
1237: public static function GetJavascriptCommandArray() {
1238:
1239: if (QApplication::$JavascriptExclusiveCommand) {
1240: // only render this one;
1241: $a[QAjaxResponse::CommandsMedium] = [QApplication::$JavascriptExclusiveCommand];
1242: QApplication::$JavascriptExclusiveCommand = null;
1243: return $a;
1244: }
1245:
1246: // Combine the javascripts into one array item
1247: $scripts = array();
1248: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsMedium])) {
1249: $scripts = QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsMedium];
1250: }
1251: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsHigh])) {
1252: $scripts = array_merge (QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsHigh], $scripts);
1253: unset (QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsHigh]);
1254: }
1255: if (!empty(QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsLow])) {
1256: $scripts = array_merge ($scripts, QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsLow]);
1257: unset (QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsLow]);
1258: }
1259: if ($scripts) {
1260: QApplication::$JavascriptCommandArray[QAjaxResponse::CommandsMedium] = $scripts;
1261: }
1262:
1263: // add the file inclusion array onto the front of the command array
1264: $a = array_merge(QApplication::$JavascriptFileArray, QApplication::$JavascriptCommandArray);
1265: QApplication::$JavascriptFileArray = array();
1266: QApplication::$JavascriptCommandArray = array();
1267: return $a;
1268: }
1269:
1270:
1271: /**
1272: * If LanguageCode is specified and QI18n::Initialize() has been called, then this
1273: * will perform a translation of the given token for the specified Language Code and optional
1274: * Country code.
1275: *
1276: * Otherwise, this will simply return the token as is.
1277: * This method is also used by the global print-translated "_t" function.
1278: *
1279: * @static
1280: * @param string $strToken
1281: * @return string the Translated token (if applicable)
1282: */
1283: public static function Translate($strToken) {
1284: if (QApplication::$LanguageObject)
1285: return QApplication::$LanguageObject->TranslateToken($strToken);
1286: else
1287: return $strToken;
1288: }
1289:
1290: /**
1291: * Global/Central HtmlEntities command to perform the PHP equivalent of htmlentities.
1292: * Feel free to override to specify encoding/quoting specific preferences (e.g. ENT_QUOTES/ENT_NOQUOTES, etc.)
1293: *
1294: * Be careful of one thing though. This now uses ENT_HTML5, to correspond with the default page DOCTYPE. This
1295: * has the added benefit of encoding newlines in data sent to controls. In particular, a multi-line textbox
1296: * needs to have newlines encoded to prevent problems when the output is formatted using _indent().
1297: *
1298: * This method is also used by the global print "_p" function.
1299: *
1300: * @param string $strText text string to perform html escaping
1301: * @return string the html escaped string
1302: */
1303: public static function HtmlEntities($strText) {
1304: return htmlentities($strText, ENT_COMPAT | ENT_HTML5, QApplication::$EncodingType);
1305: }
1306:
1307: /**
1308: * Print an ajax response to the browser.
1309: *
1310: * @param array $strResponseArray An array keyed with QAjaxResponse items. These items will be read by the qcubed.js
1311: * ajax success function and operated on. The goals is to eventually have all possible response types represented
1312: * in the QAjaxResponse so that we can remove the "eval" in qcubed.js.
1313: */
1314: public static function SendAjaxResponse(array $strResponseArray) {
1315: header('Content-Type: text/json'); // not application/json, as IE reportedly blows up on that, but jQuery knows what to do.
1316: $strJSON = JavascriptHelper::toJSON($strResponseArray);
1317: if (QApplication::$EncodingType && QApplication::$EncodingType != 'UTF-8') {
1318: $strJSON = iconv(QApplication::$EncodingType, 'UTF-8', $strJSON); // json must be UTF-8 encoded
1319: }
1320: print ($strJSON);
1321: }
1322:
1323:
1324: /**
1325: * Utility function to get the JS file URI, given a string input
1326: * @param string $strFile File name to be tested
1327: *
1328: * @return string the final JS file URI
1329: */
1330: public static function GetJsFileUri($strFile) {
1331: if ((strpos($strFile, "http") === 0) || (strpos($strFile, "https") === 0))
1332: return $strFile;
1333: if (strpos($strFile, "/") === 0)
1334: return __VIRTUAL_DIRECTORY__ . $strFile;
1335: return __VIRTUAL_DIRECTORY__ . __JS_ASSETS__ . '/' . $strFile;
1336: }
1337:
1338: /**
1339: * Utility function to get the CSS file URI, given a string input
1340: * @param string $strFile File name to be tested
1341: *
1342: * @return string the final CSS URI
1343: */
1344: public static function GetCssFileUri($strFile) {
1345: if ((strpos($strFile, "http") === 0) || (strpos($strFile, "https") === 0))
1346: return $strFile;
1347: if (strpos($strFile, "/") === 0)
1348: return __VIRTUAL_DIRECTORY__ . $strFile;
1349: return __VIRTUAL_DIRECTORY__ . __CSS_ASSETS__ . '/' . $strFile;
1350: }
1351:
1352: /**
1353: * For development purposes, this static method outputs all the Application static variables
1354: *
1355: * @return void
1356: */
1357: public static function VarDump() {
1358: _p('<div class="var-dump"><strong>QCubed Settings</strong><ul>', false);
1359: $arrValidationErrors = QInstallationValidator::Validate();
1360: foreach ($arrValidationErrors as $objResult) {
1361: printf('<li><strong class="warning">WARNING:</strong> %s</li>', $objResult->strMessage);
1362: }
1363:
1364: printf('<li>QCUBED_VERSION = "%s"</li>', QCUBED_VERSION);
1365: printf('<li>jQuery version = "%s"</li>', __JQUERY_CORE_VERSION__);
1366: printf('<li>jQuery UI version = "%s"</li>', __JQUERY_UI_VERSION__);
1367: printf('<li>__SUBDIRECTORY__ = "%s"</li>', __SUBDIRECTORY__);
1368: printf('<li>__VIRTUAL_DIRECTORY__ = "%s"</li>', __VIRTUAL_DIRECTORY__);
1369: printf('<li>__INCLUDES__ = "%s"</li>', __INCLUDES__);
1370: printf('<li>__QCUBED_CORE__ = "%s"</li>', __QCUBED_CORE__);
1371: printf('<li>ERROR_PAGE_PATH = "%s"</li>', ERROR_PAGE_PATH);
1372: printf('<li>PHP Include Path = "%s"</li>', get_include_path());
1373: printf('<li>QApplication::$DocumentRoot = "%s"</li>', QApplication::$DocumentRoot);
1374: printf('<li>QApplication::$EncodingType = "%s"</li>', QApplication::$EncodingType);
1375: printf('<li>QApplication::$PathInfo = "%s"</li>', QApplication::$PathInfo);
1376: printf('<li>QApplication::$QueryString = "%s"</li>', QApplication::$QueryString);
1377: printf('<li>QApplication::$RequestUri = "%s"</li>', QApplication::$RequestUri);
1378: printf('<li>QApplication::$ScriptFilename = "%s"</li>', QApplication::$ScriptFilename);
1379: printf('<li>QApplication::$ScriptName = "%s"</li>', QApplication::$ScriptName);
1380: printf('<li>QApplication::$ServerAddress = "%s"</li>', QApplication::$ServerAddress);
1381:
1382: if (QApplication::$Database) foreach (QApplication::$Database as $intKey => $objObject) {
1383: printf('<li>QApplication::$Database[%s] settings:</li>', $intKey);
1384: _p("<ul>", false);
1385: foreach (unserialize(constant('DB_CONNECTION_' . $intKey)) as $key => $value) {
1386: if ($key == "password") {
1387: $value = "hidden for security purposes";
1388: }
1389:
1390: _p("<li>" . $key. " = " . var_export($value, true). "</li>", false);
1391: }
1392: _p("</ul>", false);
1393:
1394: }
1395: _p('</ul></div>', false);
1396: }
1397: }
1398:
1399: /**
1400: * Class for enumerating Javascript priority.
1401: * These are taken out of a parameter list, and so are very unlikely strings to include normally.
1402: */
1403: class QJsPriority {
1404: /** Standard Priority */
1405: const Standard = '*jsMed*';
1406: /** High prioriy JS */
1407: const High = '*jsHigh*';
1408: /** Low Priority JS */
1409: const Low = '*jsLow*';
1410: /** Execute ONLY this command and exclude all others */
1411: const Exclusive = '*jsExclusive*';
1412:
1413: }
1414:
1415: /**
1416: * This is an enumerator class for listing Request Modes
1417: */
1418: class QRequestMode {
1419: /** Normal request (initial request) */
1420: const Standard = 'Standard';
1421: /** Ajax Request (mostly calls triggered by events) */
1422: const Ajax = 'Ajax';
1423: }
1424:
1425: /**
1426: * Class QBrowserType: Type of browsers we can identify
1427: */
1428: class QBrowserType {
1429: /** IE */
1430: const InternetExplorer = 1;
1431:
1432: /* Deprecated. See QApplication::BrowserVersion **
1433: const InternetExplorer_6_0 = 2;
1434: const InternetExplorer_7_0 = 4;
1435: const InternetExplorer_8_0 = 8;*/
1436:
1437: /** Firefox */
1438: const Firefox = 0x10;
1439:
1440: /* Deprecated. See QApplication::BrowserVersion **
1441: const Firefox_1_0 = 0x20;
1442: const Firefox_1_5 = 0x40;
1443: const Firefox_2_0 = 0x80;
1444: const Firefox_3_0 = 0x100;*/
1445:
1446: /** Apple's Safari */
1447: const Safari = 0x200;
1448: /* Deprecated. See QApplication::BrowserVersion **
1449: const Safari_2_0 = 0x400;
1450: const Safari_3_0 = 0x800;
1451: const Safari_4_0 = 0x1000;*/
1452:
1453: /** Browser */
1454: const Opera = 0x2000;
1455: /* Deprecated. See QApplication::BrowserVersion **
1456: const Opera_7 = 0x4000;
1457: const Opera_8 = 0x8000;
1458: const Opera_9 = 0x10000;*/
1459:
1460: /** KDE's failed rocket that never took off */
1461: const Konqueror = 0x20000;
1462: /* Deprecated. See QApplication::BrowserVersion **
1463: const Konqueror_3 = 0x40000;
1464: const Konqueror_4 = 0x80000;*/
1465:
1466: /** Google Chrome (and chromium) */
1467: const Chrome = 0x100000;
1468: /* Deprecated. See QApplication::BrowserVersion **
1469: const Chrome_0 = 0x200000;
1470: const Chrome_1 = 0x400000;*/
1471:
1472: /** Windows OS */
1473: const Windows = 0x800000;
1474: /** Linux based OS */
1475: const Linux = 0x1000000;
1476: /** Apple's OS X */
1477: const Macintosh = 0x2000000;
1478: /** Some kind of Mobile browser */
1479: const Mobile = 0x4000000; // some kind of mobile browser
1480:
1481: /** We don't know this gentleman...err...gentlebrowser */
1482: const Unsupported = 0x8000000;
1483: }
1484: