CWIS Developer Documentation

- Home
- Main Page
- Classes
- Files

- File List
- File Members

ApplicationFramework.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: ApplicationFramework.php
4 #
5 # Part of the ScoutLib application support library
6 # Copyright 2009-2014 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu
8 #
9
14 class ApplicationFramework {
15
16 # ---- PUBLIC INTERFACE --------------------------------------------------
17 /*@(*/
19
24 function __construct()
25 {
26 # save execution start time
27 $this->ExecutionStartTime = microtime(TRUE);
28
29 # begin/restore PHP session
30 $SessionDomain = isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"]
31 : isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"]
32 : php_uname("n");
33 if (is_writable(session_save_path()))
34 {
35 $SessionStorage = session_save_path()
36 ."/".self::$AppName."_".md5($SessionDomain.dirname(__FILE__));
37 if (!is_dir($SessionStorage)) { mkdir($SessionStorage, 0700 ); }
38 if (is_writable($SessionStorage)) { session_save_path($SessionStorage); }
39 }
40 ini_set("session.gc_maxlifetime", self::$SessionLifetime);
41 session_set_cookie_params(
42 self::$SessionLifetime, "/", $SessionDomain);
43 session_start();
44
45 # set up object file autoloader
46 $this->SetUpObjectAutoloading();
47
48 # set up function to output any buffered text in case of crash
49 register_shutdown_function(array($this, "OnCrash"));
50
51 # set up our internal environment
52 $this->DB = new Database();
53
54 # set up our exception handler
55 set_exception_handler(array($this, "GlobalExceptionHandler"));
56
57 # perform any work needed to undo PHP magic quotes
58 $this->UndoMagicQuotes();
59
60 # load our settings from database
61 $this->LoadSettings();
62
63 # set PHP maximum execution time
64 $this->MaxExecutionTime($this->Settings["MaxExecTime"]);
65
66 # register events we handle internally
67 $this->RegisterEvent($this->PeriodicEvents);
68 $this->RegisterEvent($this->UIEvents);
69
70 # attempt to create SCSS cache directory if needed and it does not exist
71 if ($this->UseScss && !is_dir(self::$ScssCacheDir))
72 { mkdir(self::$ScssCacheDir, 0777, TRUE); }
73 }
80 function __destruct()
81 {
82 # if template location cache is flagged to be saved
83 if ($this->SaveTemplateLocationCache)
84 {
85 # write template location cache out and update cache expiration
86 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
87 ." SET TemplateLocationCache = '"
88 .addslashes(serialize(
89 $this->Settings["TemplateLocationCache"]))."',"
90 ." TemplateLocationCacheExpiration = "
91 ." NOW() + INTERVAL "
92 .$this->Settings["TemplateLocationCacheInterval"]
93 ." MINUTE");
94 }
95
96 # if object location cache is flagged to be saved
97 if (self::$SaveObjectLocationCache)
98 {
99 # write object location cache out and update cache expiration
100 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
101 ." SET ObjectLocationCache = '"
102 .addslashes(serialize(
103 self::$ObjectLocationCache))."',"
104 ." ObjectLocationCacheExpiration = "
105 ." NOW() + INTERVAL "
106 .self::$ObjectLocationCacheInterval
107 ." MINUTE");
108 }
109 }
116 function GlobalExceptionHandler($Exception)
117 {
118 # display exception info
119 $Location = $Exception->getFile()."[".$Exception->getLine()."]";
120 ?><table width="100%" cellpadding="5"
121 style="border: 2px solid #666666; background: #CCCCCC;
122 font-family: Courier New, Courier, monospace;
123 margin-top: 10px;"><tr><td>
124 <div style="color: #666666;">
125 <span style="font-size: 150%;">
126 <b>Uncaught Exception</b></span><br />
127 <b>Message:</b> <i><?PHP print $Exception->getMessage(); ?></i><br />
128 <b>Location:</b> <i><?PHP print $Location; ?></i><br />
129 <b>Trace:</b>
130 <blockquote><pre><?PHP print $Exception->getTraceAsString();
131 ?></pre></blockquote>
132 </div>
133 </td></tr></table><?PHP
134
135 # log exception if possible
136 $LogMsg = "Uncaught exception (".$Exception->getMessage().").";
137 $this->LogError(self::LOGLVL_ERROR, $LogMsg);
138 }
152 static function AddObjectDirectory(
153 $Dir, $Prefix = "", $ClassPattern = NULL, $ClassReplacement = NULL)
154 {
155 # make sure directory has trailing slash
156 $Dir = $Dir.((substr($Dir, -1) != "/") ? "/" : "");
157
158 # add directory to directory list
159 self::$ObjectDirectories = array_merge(
160 array($Dir => array(
161 "Prefix" => $Prefix,
162 "ClassPattern" => $ClassPattern,
163 "ClassReplacement" => $ClassReplacement,
164 )),
165 self::$ObjectDirectories);
166 }
167
187 function AddImageDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
188 {
189 # add directories to existing image directory list
190 $this->ImageDirList = $this->AddToDirList(
191 $this->ImageDirList, $Dir, $SearchLast, $SkipSlashCheck);
192 }
193
214 function AddIncludeDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
215 {
216 # add directories to existing image directory list
217 $this->IncludeDirList = $this->AddToDirList(
218 $this->IncludeDirList, $Dir, $SearchLast, $SkipSlashCheck);
219 }
220
240 function AddInterfaceDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
241 {
242 # add directories to existing image directory list
243 $this->InterfaceDirList = $this->AddToDirList(
244 $this->InterfaceDirList, $Dir, $SearchLast, $SkipSlashCheck);
245 }
246
266 function AddFunctionDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
267 {
268 # add directories to existing image directory list
269 $this->FunctionDirList = $this->AddToDirList(
270 $this->FunctionDirList, $Dir, $SearchLast, $SkipSlashCheck);
271 }
272
278 function SetBrowserDetectionFunc($DetectionFunc)
279 {
280 $this->BrowserDetectFunc = $DetectionFunc;
281 }
282
289 function AddUnbufferedCallback($Callback, $Parameters=array())
290 {
291 if (is_callable($Callback))
292 {
293 $this->UnbufferedCallbacks[] = array($Callback, $Parameters);
294 }
295 }
296
303 function TemplateLocationCacheExpirationInterval($NewInterval = DB_NOVALUE)
304 {
305 return $this->UpdateSetting("TemplateLocationCacheInterval", $NewInterval);
306 }
307
314 function ObjectLocationCacheExpirationInterval($NewInterval = DB_NOVALUE)
315 {
316 return $this->UpdateSetting("ObjectLocationCacheInterval", $NewInterval);
317 }
318
331 function RecordContextInCaseOfCrash(
332 $BacktraceOptions = 0, $BacktraceLimit = 0)
333 {
334 if (version_compare(PHP_VERSION, "5.4.0", ">="))
335 {
336 $this->SavedContext = debug_backtrace(
337 $BacktraceOptions, $BacktraceLimit);
338 }
339 else
340 {
341 $this->SavedContext = debug_backtrace($BacktraceOptions);
342 }
343 array_shift($this->SavedContext);
344 }
345
350 function LoadPage($PageName)
351 {
352 # perform any clean URL rewriting
353 $PageName = $this->RewriteCleanUrls($PageName);
354
355 # sanitize incoming page name and save local copy
356 $PageName = preg_replace("/[^a-zA-Z0-9_.-]/", "", $PageName);
357 $this->PageName = $PageName;
358
359 # buffer any output from includes or PHP file
360 ob_start();
361
362 # include any files needed to set up execution environment
363 foreach ($this->EnvIncludes as $IncludeFile)
364 {
365 include($IncludeFile);
366 }
367
368 # signal page load
369 $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName));
370
371 # signal PHP file load
372 $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array(
373 "PageName" => $PageName));
374
375 # if signal handler returned new page name value
376 $NewPageName = $PageName;
377 if (($SignalResult["PageName"] != $PageName)
378 && strlen($SignalResult["PageName"]))
379 {
380 # if new page name value is page file
381 if (file_exists($SignalResult["PageName"]))
382 {
383 # use new value for PHP file name
384 $PageFile = $SignalResult["PageName"];
385 }
386 else
387 {
388 # use new value for page name
389 $NewPageName = $SignalResult["PageName"];
390 }
391
392 # update local copy of page name
393 $this->PageName = $NewPageName;
394 }
395
396 # if we do not already have a PHP file
397 if (!isset($PageFile))
398 {
399 # look for PHP file for page
400 $OurPageFile = "pages/".$NewPageName.".php";
401 $LocalPageFile = "local/pages/".$NewPageName.".php";
402 $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
403 : (file_exists($OurPageFile) ? $OurPageFile
404 : "pages/".$this->DefaultPage.".php");
405 }
406
407 # load PHP file
408 include($PageFile);
409
410 # save buffered output to be displayed later after HTML file loads
411 $PageOutput = ob_get_contents();
412 ob_end_clean();
413
414 # signal PHP file load is complete
415 ob_start();
416 $Context["Variables"] = get_defined_vars();
417 $this->SignalEvent("EVENT_PHP_FILE_LOAD_COMPLETE",
418 array("PageName" => $PageName, "Context" => $Context));
419 $PageCompleteOutput = ob_get_contents();
420 ob_end_clean();
421
422 # set up for possible TSR (Terminate and Stay Resident :))
423 $ShouldTSR = $this->PrepForTSR();
424
425 # if PHP file indicated we should autorefresh to somewhere else
426 if ($this->JumpToPage)
427 {
428 if (!strlen(trim($PageOutput)))
429 {
430 ?><html>
431 <head>
432 <meta http-equiv="refresh" content="0; URL=<?PHP
433 print($this->JumpToPage); ?>">
434 </head>
435 <body bgcolor="white">
436 </body>
437 </html><?PHP
438 }
439 }
440 # else if HTML loading is not suppressed
441 elseif (!$this->SuppressHTML)
442 {
443 # set content-type to get rid of diacritic errors
444 header("Content-Type: text/html; charset="
445 .$this->HtmlCharset, TRUE);
446
447 # load common HTML file (defines common functions) if available
448 $CommonHtmlFile = $this->FindFile($this->IncludeDirList,
449 "Common", array("tpl", "html"));
450 if ($CommonHtmlFile) { include($CommonHtmlFile); }
451
452 # load UI functions
453 $this->LoadUIFunctions();
454
455 # begin buffering content
456 ob_start();
457
458 # signal HTML file load
459 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array(
460 "PageName" => $PageName));
461
462 # if signal handler returned new page name value
463 $NewPageName = $PageName;
464 $PageContentFile = NULL;
465 if (($SignalResult["PageName"] != $PageName)
466 && strlen($SignalResult["PageName"]))
467 {
468 # if new page name value is HTML file
469 if (file_exists($SignalResult["PageName"]))
470 {
471 # use new value for HTML file name
472 $PageContentFile = $SignalResult["PageName"];
473 }
474 else
475 {
476 # use new value for page name
477 $NewPageName = $SignalResult["PageName"];
478 }
479 }
480
481 # load page content HTML file if available
482 if ($PageContentFile === NULL)
483 {
484 $PageContentFile = $this->FindFile(
485 $this->InterfaceDirList, $NewPageName,
486 array("tpl", "html"));
487 }
488 if ($PageContentFile)
489 {
490 include($PageContentFile);
491 }
492 else
493 {
494 print "<h2>ERROR: No HTML/TPL template found"
495 ." for this page.</h2>";
496 }
497
498 # signal HTML file load complete
499 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE");
500
501 # stop buffering and save output
502 $PageContentOutput = ob_get_contents();
503 ob_end_clean();
504
505 # load page start HTML file if available
506 ob_start();
507 $PageStartFile = $this->FindFile($this->IncludeDirList, "Start",
508 array("tpl", "html"), array("StdPage", "StandardPage"));
509 if ($PageStartFile) { include($PageStartFile); }
510 $PageStartOutput = ob_get_contents();
511 ob_end_clean();
512
513 # load page end HTML file if available
514 ob_start();
515 $PageEndFile = $this->FindFile($this->IncludeDirList, "End",
516 array("tpl", "html"), array("StdPage", "StandardPage"));
517 if ($PageEndFile) { include($PageEndFile); }
518 $PageEndOutput = ob_get_contents();
519 ob_end_clean();
520
521 # get list of any required files not loaded
522 $RequiredFiles = $this->GetRequiredFilesNotYetLoaded($PageContentFile);
523
524 # if a browser detection function has been made available
525 if (is_callable($this->BrowserDetectFunc))
526 {
527 # call function to get browser list
528 $Browsers = call_user_func($this->BrowserDetectFunc);
529
530 # for each required file
531 $NewRequiredFiles = array();
532 foreach ($RequiredFiles as $File)
533 {
534 # if file name includes browser keyword
535 if (preg_match("/%BROWSER%/", $File))
536 {
537 # for each browser
538 foreach ($Browsers as $Browser)
539 {
540 # substitute in browser name and add to new file list
541 $NewRequiredFiles[] = preg_replace(
542 "/%BROWSER%/", $Browser, $File);
543 }
544 }
545 else
546 {
547 # add to new file list
548 $NewRequiredFiles[] = $File;
549 }
550 }
551 $RequiredFiles = $NewRequiredFiles;
552 }
553 else
554 {
555 # filter out any files with browser keyword in their name
556 $NewRequiredFiles = array();
557 foreach ($RequiredFiles as $File)
558 {
559 if (!preg_match("/%BROWSER%/", $File))
560 {
561 $NewRequiredFiles[] = $File;
562 }
563 }
564 $RequiredFiles = $NewRequiredFiles;
565 }
566
567 # for each required file
568 foreach ($RequiredFiles as $File)
569 {
570 # locate specific file to use
571 $FilePath = $this->GUIFile($File);
572
573 # if file was found
574 if ($FilePath)
575 {
576 # determine file type
577 $NamePieces = explode(".", $File);
578 $FileSuffix = strtolower(array_pop($NamePieces));
579
580 # add file to HTML output based on file type
581 $FilePath = htmlspecialchars($FilePath);
582 switch ($FileSuffix)
583 {
584 case "js":
585 $Tag = '<script type="text/javascript" src="'
586 .$FilePath.'"></script>';
587 $PageEndOutput = preg_replace(
588 "#</body>#i", $Tag."\n</body>", $PageEndOutput, 1);
589 break;
590
591 case "css":
592 $Tag = '<link rel="stylesheet" type="text/css"'
593 .' media="all" href="'.$FilePath.'">';
594 $PageStartOutput = preg_replace(
595 "#</head>#i", $Tag."\n</head>", $PageStartOutput, 1);
596 break;
597 }
598 }
599 }
600
601 # assemble full page
602 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
603
604 # perform any regular expression replacements in output
605 $FullPageOutput = preg_replace($this->OutputModificationPatterns,
606 $this->OutputModificationReplacements, $FullPageOutput);
607
608 # perform any callback replacements in output
609 foreach ($this->OutputModificationCallbacks as $Info)
610 {
611 $this->OutputModificationCallbackInfo = $Info;
612 $FullPageOutput = preg_replace_callback($Info["SearchPattern"],
613 array($this, "OutputModificationCallbackShell"),
614 $FullPageOutput);
615 }
616
617 # if relative paths may not work because we were invoked via clean URL
618 if ($this->CleanUrlRewritePerformed || self::WasUrlRewritten())
619 {
620 # if using the <base> tag is okay
621 $BaseUrl = $this->BaseUrl();
622 if ($this->UseBaseTag)
623 {
624 # add <base> tag to header
625 $PageStartOutput = preg_replace("%<head>%",
626 "<head><base href=\"".$BaseUrl."\" />",
627 $PageStartOutput);
628
629 # re-assemble full page with new header
630 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
631
632 # the absolute URL to the current page
633 $FullUrl = $BaseUrl . $this->GetPageLocation();
634
635 # make HREF attribute values with just a fragment ID
636 # absolute since they don't work with the <base> tag because
637 # they are relative to the current page/URL, not the site
638 # root
639 $FullPageOutput = preg_replace(
640 array("%href=\"(#[^:\" ]+)\"%i", "%href='(#[^:' ]+)'%i"),
641 array("href=\"".$FullUrl."$1\"", "href='".$FullUrl."$1'"),
642 $FullPageOutput);
643 }
644 else
645 {
646 # try to fix any relative paths throughout code
647 $FullPageOutput = preg_replace(array(
648 "%src=\"/?([^?*:;{}\\\\\" ]+)\.(js|css|gif|png|jpg)\"%i",
649 "%src='/?([^?*:;{}\\\\' ]+)\.(js|css|gif|png|jpg)'%i",
650 # don't rewrite HREF attributes that are just
651 # fragment IDs because they are relative to the
652 # current page/URL, not the site root
653 "%href=\"/?([^#][^:\" ]*)\"%i",
654 "%href='/?([^#][^:' ]*)'%i",
655 "%action=\"/?([^#][^:\" ]*)\"%i",
656 "%action='/?([^#][^:' ]*)'%i",
657 "%@import\s+url\(\"/?([^:\" ]+)\"\s*\)%i",
658 "%@import\s+url\('/?([^:\" ]+)'\s*\)%i",
659 "%@import\s+\"/?([^:\" ]+)\"\s*%i",
660 "%@import\s+'/?([^:\" ]+)'\s*%i",
661 ),
662 array(
663 "src=\"".$BaseUrl."$1.$2\"",
664 "src=\"".$BaseUrl."$1.$2\"",
665 "href=\"".$BaseUrl."$1\"",
666 "href=\"".$BaseUrl."$1\"",
667 "action=\"".$BaseUrl."$1\"",
668 "action=\"".$BaseUrl."$1\"",
669 "@import url(\"".$BaseUrl."$1\")",
670 "@import url('".$BaseUrl."$1')",
671 "@import \"".$BaseUrl."$1\"",
672 "@import '".$BaseUrl."$1'",
673 ),
674 $FullPageOutput);
675 }
676 }
677
678 # provide the opportunity to modify full page output
679 $SignalResult = $this->SignalEvent("EVENT_PAGE_OUTPUT_FILTER", array(
680 "PageOutput" => $FullPageOutput));
681 if (isset($SignalResult["PageOutput"])
682 && strlen($SignalResult["PageOutput"]))
683 {
684 $FullPageOutput = $SignalResult["PageOutput"];
685 }
686
687 # write out full page
688 print $FullPageOutput;
689 }
690
691 # run any post-processing routines
692 foreach ($this->PostProcessingFuncs as $Func)
693 {
694 call_user_func_array($Func["FunctionName"], $Func["Arguments"]);
695 }
696
697 # write out any output buffered from page code execution
698 if (strlen($PageOutput))
699 {
700 if (!$this->SuppressHTML)
701 {
702 ?><table width="100%" cellpadding="5"
703 style="border: 2px solid #666666; background: #CCCCCC;
704 font-family: Courier New, Courier, monospace;
705 margin-top: 10px;"><tr><td><?PHP
706 }
707 if ($this->JumpToPage)
708 {
709 ?><div style="color: #666666;"><span style="font-size: 150%;">
710 <b>Page Jump Aborted</b></span>
711 (because of error or other unexpected output)<br />
712 <b>Jump Target:</b>
713 <i><?PHP print($this->JumpToPage); ?></i></div><?PHP
714 }
715 print $PageOutput;
716 if (!$this->SuppressHTML)
717 {
718 ?></td></tr></table><?PHP
719 }
720 }
721
722 # write out any output buffered from the page code execution complete signal
723 if (!$this->JumpToPage && !$this->SuppressHTML && strlen($PageCompleteOutput))
724 {
725 print $PageCompleteOutput;
726 }
727
728 # execute callbacks that should not have their output buffered
729 foreach ($this->UnbufferedCallbacks as $Callback)
730 {
731 call_user_func_array($Callback[0], $Callback[1]);
732 }
733
734 # log high memory usage
735 if (function_exists("memory_get_peak_usage"))
736 {
737 $MemoryThreshold = ($this->HighMemoryUsageThreshold()
738 * $this->GetPhpMemoryLimit()) / 100;
739 if ($this->LogHighMemoryUsage()
740 && (memory_get_peak_usage() >= $MemoryThreshold))
741 {
742 $HighMemUsageMsg = "High peak memory usage ("
743 .intval(memory_get_peak_usage()).") for "
744 .$this->FullUrl()." from "
745 .$_SERVER["REMOTE_ADDR"];
746 $this->LogMessage(self::LOGLVL_INFO, $HighMemUsageMsg);
747 }
748 }
749
750 # log slow page loads
751 if ($this->LogSlowPageLoads()
752 && ($this->GetElapsedExecutionTime()
753 >= ($this->SlowPageLoadThreshold())))
754 {
755 $SlowPageLoadMsg = "Slow page load ("
756 .intval($this->GetElapsedExecutionTime())."s) for "
757 .$this->FullUrl()." from "
758 .$_SERVER["REMOTE_ADDR"];
759 $this->LogMessage(self::LOGLVL_INFO, $SlowPageLoadMsg);
760 }
761
762 # terminate and stay resident (TSR!) if indicated and HTML has been output
763 # (only TSR if HTML has been output because otherwise browsers will misbehave)
764 if ($ShouldTSR) { $this->LaunchTSR(); }
765 }
766
772 function GetPageName()
773 {
774 return $this->PageName;
775 }
776
782 function GetPageLocation()
783 {
784 # retrieve current URL
785 $Url = $this->GetScriptUrl();
786
787 # remove the base path if present
788 $BasePath = $this->Settings["BasePath"];
789 if (stripos($Url, $BasePath) === 0)
790 {
791 $Url = substr($Url, strlen($BasePath));
792 }
793
794 return $Url;
795 }
796
802 function GetPageUrl()
803 {
804 return self::BaseUrl() . $this->GetPageLocation();
805 }
806
815 function SetJumpToPage($Page, $IsLiteral = FALSE)
816 {
817 if (!is_null($Page)
818 && (!$IsLiteral)
819 && (strpos($Page, "?") === FALSE)
820 && ((strpos($Page, "=") !== FALSE)
821 || ((stripos($Page, ".php") === FALSE)
822 && (stripos($Page, ".htm") === FALSE)
823 && (strpos($Page, "/") === FALSE)))
824 && (stripos($Page, "http://") !== 0)
825 && (stripos($Page, "https://") !== 0))
826 {
827 $this->JumpToPage = self::BaseUrl() . "index.php?P=".$Page;
828 }
829 else
830 {
831 $this->JumpToPage = $Page;
832 }
833 }
834
839 function JumpToPageIsSet()
840 {
841 return ($this->JumpToPage === NULL) ? FALSE : TRUE;
842 }
843
853 function HtmlCharset($NewSetting = NULL)
854 {
855 if ($NewSetting !== NULL) { $this->HtmlCharset = $NewSetting; }
856 return $this->HtmlCharset;
857 }
858
865 public function UseMinimizedJavascript($NewSetting = NULL)
866 {
867 if ($NewSetting !== NULL) { $this->UseMinimizedJavascript = $NewSetting; }
868 return $this->UseMinimizedJavascript;
869 }
870
881 function UseBaseTag($NewValue = NULL)
882 {
883 if ($NewValue !== NULL) { $this->UseBaseTag = $NewValue ? TRUE : FALSE; }
884 return $this->UseBaseTag;
885 }
886
893 function SuppressHTMLOutput($NewSetting = TRUE)
894 {
895 $this->SuppressHTML = $NewSetting;
896 }
897
904 function ActiveUserInterface($UIName = NULL)
905 {
906 if ($UIName !== NULL)
907 {
908 $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
909 }
910 return $this->ActiveUI;
911 }
912
918 function GetUserInterfaces()
919 {
920 # possible UI directories
921 $InterfaceDirs = array(
922 "interface",
923 "local/interface");
924
925 # start out with an empty list
926 $Interfaces = array();
927
928 # for each possible UI directory
929 foreach ($InterfaceDirs as $InterfaceDir)
930 {
931 $Dir = dir($InterfaceDir);
932
933 # for each file in current directory
934 while (($DirEntry = $Dir->read()) !== FALSE)
935 {
936 $InterfacePath = $InterfaceDir."/".$DirEntry;
937
938 # skip anything that doesn't have a name in the required format
939 if (!preg_match('/^[a-zA-Z0-9]+$/', $DirEntry))
940 {
941 continue;
942 }
943
944 # skip anything that isn't a directory
945 if (!is_dir($InterfacePath))
946 {
947 continue;
948 }
949
950 # read the UI name (if available)
951 $UIName = @file_get_contents($InterfacePath."/NAME");
952
953 # use the directory name if the UI name isn't available
954 if ($UIName === FALSE || !strlen($UIName))
955 {
956 $UIName = $DirEntry;
957 }
958
959 $Interfaces[$InterfacePath] = $UIName;
960 }
961
962 $Dir->close();
963 }
964
965 # return list to caller
966 return $Interfaces;
967 }
968
984 function AddPostProcessingCall($FunctionName,
985 &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
986 &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
987 &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
988 {
989 $FuncIndex = count($this->PostProcessingFuncs);
990 $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
991 $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
992 $Index = 1;
993 while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
994 {
995 $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
996 =& ${"Arg".$Index};
997 $Index++;
998 }
999 }
1000
1006 function AddEnvInclude($FileName)
1007 {
1008 $this->EnvIncludes[] = $FileName;
1009 }
1010
1017 function GUIFile($FileName)
1018 {
1019 # determine file type (being clever because this is run so often)
1020 static $FTOther = 0;
1021 static $FTCSS = 1;
1022 static $FTImage = 2;
1023 static $FTJavaScript = 3;
1024 $FileSuffix = strtolower(substr($FileName, -3));
1025 if ($FileSuffix == "css") { $FileType = $FTCSS; }
1026 elseif ($FileSuffix == ".js") { $FileType = $FTJavaScript; }
1027 elseif (($FileSuffix == "gif")
1028 || ($FileSuffix == "jpg")
1029 || ($FileSuffix == "png")) { $FileType = $FTImage; }
1030 else { $FileType = $FTOther; }
1031
1032 # determine which location to search based on file suffix
1033 $DirList = ($FileType == $FTImage)
1034 ? $this->ImageDirList : $this->IncludeDirList;
1035
1036 # if directed to get a minimized JavaScript file
1037 if (($FileType == $FTJavaScript) && $this->UseMinimizedJavascript)
1038 {
1039 # first try to find the minimized JavaScript file
1040 $MinimizedFileName = substr_replace($FileName, ".min", -3, 0);
1041 $FoundFileName = $this->FindFile($DirList, $MinimizedFileName);
1042
1043 # search for the regular file if a minimized file wasn't found
1044 if (is_null($FoundFileName))
1045 {
1046 $FoundFileName = $this->FindFile($DirList, $FileName);
1047 }
1048 }
1049 # else if directed to use SCSS files
1050 elseif (($FileType == $FTCSS) && $this->UseScss)
1051 {
1052 # look for SCSS version of file
1053 $SourceFileName = preg_replace("/.css$/", ".scss", $FileName);
1054 $FoundSourceFileName = $this->FindFile($DirList, $SourceFileName);
1055
1056 # if SCSS file not found
1057 if ($FoundSourceFileName === NULL)
1058 {
1059 # look for CSS file
1060 $FoundFileName = $this->FindFile($DirList, $FileName);
1061 }
1062 else
1063 {
1064 # compile SCSS file (if updated) and return resulting CSS file
1065 $FoundFileName = $this->CompileScssFile($FoundSourceFileName);
1066 }
1067 }
1068 # otherwise just search for the file
1069 else
1070 {
1071 $FoundFileName = $this->FindFile($DirList, $FileName);
1072 }
1073
1074 # add non-image files to list of found files (used for required files loading)
1075 if ($FileType != $FTImage)
1076 { $this->FoundUIFiles[] = basename($FoundFileName); }
1077
1078 # return file name to caller
1079 return $FoundFileName;
1080 }
1081
1091 function PUIFile($FileName)
1092 {
1093 $FullFileName = $this->GUIFile($FileName);
1094 if ($FullFileName) { print($FullFileName); }
1095 }
1096
1104 function RequireUIFile($FileName)
1105 {
1106 $this->AdditionalRequiredUIFiles[] = $FileName;
1107 }
1108
1117 function LoadFunction($Callback)
1118 {
1119 # if specified function is not currently available
1120 if (!is_callable($Callback))
1121 {
1122 # if function info looks legal
1123 if (is_string($Callback) && strlen($Callback))
1124 {
1125 # start with function directory list
1126 $Locations = $this->FunctionDirList;
1127
1128 # add object directories to list
1129 $Locations = array_merge(
1130 $Locations, array_keys(self::$ObjectDirectories));
1131
1132 # look for function file
1133 $FunctionFileName = $this->FindFile($Locations, "F-".$Callback,
1134 array("php", "html"));
1135
1136 # if function file was found
1137 if ($FunctionFileName)
1138 {
1139 # load function file
1140 include_once($FunctionFileName);
1141 }
1142 else
1143 {
1144 # log error indicating function load failed
1145 $this->LogError(self::LOGLVL_ERROR, "Unable to load function"
1146 ." for callback \"".$Callback."\".");
1147 }
1148 }
1149 else
1150 {
1151 # log error indicating specified function info was bad
1152 $this->LogError(self::LOGLVL_ERROR, "Unloadable callback value"
1153 ." (".$Callback.")"
1154 ." passed to AF::LoadFunction().");
1155 }
1156 }
1157
1158 # report to caller whether function load succeeded
1159 return is_callable($Callback);
1160 }
1161
1166 function GetElapsedExecutionTime()
1167 {
1168 return microtime(TRUE) - $this->ExecutionStartTime;
1169 }
1170
1175 function GetSecondsBeforeTimeout()
1176 {
1177 return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
1178 }
1179
1180 /*@)*/ /* Application Framework */
1181
1182
1183 # ---- Logging -----------------------------------------------------------
1184 /*@(*/
1186
1197 function LogSlowPageLoads($NewValue = DB_NOVALUE)
1198 {
1199 return $this->UpdateSetting("LogSlowPageLoads", $NewValue);
1200 }
1201
1209 function SlowPageLoadThreshold($NewValue = DB_NOVALUE)
1210 {
1211 return $this->UpdateSetting("SlowPageLoadThreshold", $NewValue);
1212 }
1213
1224 function LogHighMemoryUsage($NewValue = DB_NOVALUE)
1225 {
1226 return $this->UpdateSetting("LogHighMemoryUsage", $NewValue);
1227 }
1228
1237 function HighMemoryUsageThreshold($NewValue = DB_NOVALUE)
1238 {
1239 return $this->UpdateSetting("HighMemoryUsageThreshold", $NewValue);
1240 }
1241
1255 function LogError($Level, $Msg)
1256 {
1257 # if error level is at or below current logging level
1258 if ($this->Settings["LoggingLevel"] >= $Level)
1259 {
1260 # attempt to log error message
1261 $Result = $this->LogMessage($Level, $Msg);
1262
1263 # if logging attempt failed and level indicated significant error
1264 if (($Result === FALSE) && ($Level <= self::LOGLVL_ERROR))
1265 {
1266 # throw exception about inability to log error
1267 static $AlreadyThrewException = FALSE;
1268 if (!$AlreadyThrewException)
1269 {
1270 $AlreadyThrewException = TRUE;
1271 throw new Exception("Unable to log error (".$Level.": ".$Msg.").");
1272 }
1273 }
1274
1275 # report to caller whether message was logged
1276 return $Result;
1277 }
1278 else
1279 {
1280 # report to caller that message was not logged
1281 return FALSE;
1282 }
1283 }
1284
1296 function LogMessage($Level, $Msg)
1297 {
1298 # if message level is at or below current logging level
1299 if ($this->Settings["LoggingLevel"] >= $Level)
1300 {
1301 # attempt to open log file
1302 $FHndl = @fopen($this->LogFileName, "a");
1303
1304 # if log file could not be open
1305 if ($FHndl === FALSE)
1306 {
1307 # report to caller that message was not logged
1308 return FALSE;
1309 }
1310 else
1311 {
1312 # format log entry
1313 $ErrorAbbrevs = array(
1314 self::LOGLVL_FATAL => "FTL",
1315 self::LOGLVL_ERROR => "ERR",
1316 self::LOGLVL_WARNING => "WRN",
1317 self::LOGLVL_INFO => "INF",
1318 self::LOGLVL_DEBUG => "DBG",
1319 self::LOGLVL_TRACE => "TRC",
1320 );
1321 $LogEntry = date("Y-m-d H:i:s")
1322 ." ".($this->RunningInBackground ? "B" : "F")
1323 ." ".$ErrorAbbrevs[$Level]
1324 ." ".$Msg;
1325
1326 # write entry to log
1327 $Success = fwrite($FHndl, $LogEntry."\n");
1328
1329 # close log file
1330 fclose($FHndl);
1331
1332 # report to caller whether message was logged
1333 return ($Success === FALSE) ? FALSE : TRUE;
1334 }
1335 }
1336 else
1337 {
1338 # report to caller that message was not logged
1339 return FALSE;
1340 }
1341 }
1342
1364 function LoggingLevel($NewValue = DB_NOVALUE)
1365 {
1366 # constrain new level (if supplied) to within legal bounds
1367 if ($NewValue !== DB_NOVALUE)
1368 {
1369 $NewValue = max(min($NewValue, 6), 1);
1370 }
1371
1372 # set new logging level (if supplied) and return current level to caller
1373 return $this->UpdateSetting("LoggingLevel", $NewValue);
1374 }
1375
1382 function LogFile($NewValue = NULL)
1383 {
1384 if ($NewValue !== NULL) { $this->LogFileName = $NewValue; }
1385 return $this->LogFileName;
1386 }
1387
1392 const LOGLVL_TRACE = 6;
1397 const LOGLVL_DEBUG = 5;
1403 const LOGLVL_INFO = 4;
1408 const LOGLVL_WARNING = 3;
1414 const LOGLVL_ERROR = 2;
1419 const LOGLVL_FATAL = 1;
1420
1421 /*@)*/ /* Logging */
1422
1423
1424 # ---- Event Handling ----------------------------------------------------
1425 /*@(*/
1427
1431 const EVENTTYPE_DEFAULT = 1;
1437 const EVENTTYPE_CHAIN = 2;
1443 const EVENTTYPE_FIRST = 3;
1451 const EVENTTYPE_NAMED = 4;
1452
1454 const ORDER_FIRST = 1;
1456 const ORDER_MIDDLE = 2;
1458 const ORDER_LAST = 3;
1459
1468 function RegisterEvent($EventsOrEventName, $EventType = NULL)
1469 {
1470 # convert parameters to array if not already in that form
1471 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1472 : array($EventsOrEventName => $EventType);
1473
1474 # for each event
1475 foreach ($Events as $Name => $Type)
1476 {
1477 # store event information
1478 $this->RegisteredEvents[$Name]["Type"] = $Type;
1479 $this->RegisteredEvents[$Name]["Hooks"] = array();
1480 }
1481 }
1482
1489 function IsRegisteredEvent($EventName)
1490 {
1491 return array_key_exists($EventName, $this->RegisteredEvents)
1492 ? TRUE : FALSE;
1493 }
1494
1501 function IsHookedEvent($EventName)
1502 {
1503 # the event isn't hooked to if it isn't even registered
1504 if (!$this->IsRegisteredEvent($EventName))
1505 {
1506 return FALSE;
1507 }
1508
1509 # return TRUE if there is at least one callback hooked to the event
1510 return count($this->RegisteredEvents[$EventName]["Hooks"]) > 0;
1511 }
1512
1526 function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
1527 {
1528 # convert parameters to array if not already in that form
1529 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1530 : array($EventsOrEventName => $Callback);
1531
1532 # for each event
1533 $Success = TRUE;
1534 foreach ($Events as $EventName => $EventCallback)
1535 {
1536 # if callback is valid
1537 if (is_callable($EventCallback))
1538 {
1539 # if this is a periodic event we process internally
1540 if (isset($this->PeriodicEvents[$EventName]))
1541 {
1542 # process event now
1543 $this->ProcessPeriodicEvent($EventName, $EventCallback);
1544 }
1545 # if specified event has been registered
1546 elseif (isset($this->RegisteredEvents[$EventName]))
1547 {
1548 # add callback for event
1549 $this->RegisteredEvents[$EventName]["Hooks"][]
1550 = array("Callback" => $EventCallback, "Order" => $Order);
1551
1552 # sort callbacks by order
1553 if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
1554 {
1555 usort($this->RegisteredEvents[$EventName]["Hooks"],
1556 array("ApplicationFramework", "HookEvent_OrderCompare"));
1557 }
1558 }
1559 else
1560 {
1561 $Success = FALSE;
1562 }
1563 }
1564 else
1565 {
1566 $Success = FALSE;
1567 }
1568 }
1569
1570 # report to caller whether all callbacks were hooked
1571 return $Success;
1572 }
1574 private static function HookEvent_OrderCompare($A, $B)
1575 {
1576 if ($A["Order"] == $B["Order"]) { return 0; }
1577 return ($A["Order"] < $B["Order"]) ? -1 : 1;
1578 }
1579
1590 function SignalEvent($EventName, $Parameters = NULL)
1591 {
1592 $ReturnValue = NULL;
1593
1594 # if event has been registered
1595 if (isset($this->RegisteredEvents[$EventName]))
1596 {
1597 # set up default return value (if not NULL)
1598 switch ($this->RegisteredEvents[$EventName]["Type"])
1599 {
1600 case self::EVENTTYPE_CHAIN:
1601 $ReturnValue = $Parameters;
1602 break;
1603
1604 case self::EVENTTYPE_NAMED:
1605 $ReturnValue = array();
1606 break;
1607 }
1608
1609 # for each callback for this event
1610 foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
1611 {
1612 # invoke callback
1613 $Callback = $Hook["Callback"];
1614 $Result = ($Parameters !== NULL)
1615 ? call_user_func_array($Callback, $Parameters)
1616 : call_user_func($Callback);
1617
1618 # process return value based on event type
1619 switch ($this->RegisteredEvents[$EventName]["Type"])
1620 {
1621 case self::EVENTTYPE_CHAIN:
1622 if ($Result !== NULL)
1623 {
1624 foreach ($Parameters as $Index => $Value)
1625 {
1626 if (array_key_exists($Index, $Result))
1627 {
1628 $Parameters[$Index] = $Result[$Index];
1629 }
1630 }
1631 $ReturnValue = $Parameters;
1632 }
1633 break;
1634
1635 case self::EVENTTYPE_FIRST:
1636 if ($Result !== NULL)
1637 {
1638 $ReturnValue = $Result;
1639 break 2;
1640 }
1641 break;
1642
1643 case self::EVENTTYPE_NAMED:
1644 $CallbackName = is_array($Callback)
1645 ? (is_object($Callback[0])
1646 ? get_class($Callback[0])
1647 : $Callback[0])."::".$Callback[1]
1648 : $Callback;
1649 $ReturnValue[$CallbackName] = $Result;
1650 break;
1651
1652 default:
1653 break;
1654 }
1655 }
1656 }
1657 else
1658 {
1659 $this->LogError(self::LOGLVL_WARNING,
1660 "Unregistered event signaled (".$EventName.").");
1661 }
1662
1663 # return value if any to caller
1664 return $ReturnValue;
1665 }
1666
1672 function IsStaticOnlyEvent($EventName)
1673 {
1674 return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
1675 }
1676
1687 function EventWillNextRunAt($EventName, $Callback)
1688 {
1689 # if event is not a periodic event report failure to caller
1690 if (!array_key_exists($EventName, $this->EventPeriods)) { return FALSE; }
1691
1692 # retrieve last execution time for event if available
1693 $Signature = self::GetCallbackSignature($Callback);
1694 $LastRunTime = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
1695 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
1696
1697 # if event was not found report failure to caller
1698 if ($LastRunTime === NULL) { return FALSE; }
1699
1700 # calculate next run time based on event period
1701 $NextRunTime = strtotime($LastRunTime) + $this->EventPeriods[$EventName];
1702
1703 # report next run time to caller
1704 return $NextRunTime;
1705 }
1706
1722 function GetKnownPeriodicEvents()
1723 {
1724 # retrieve last execution times
1725 $this->DB->Query("SELECT * FROM PeriodicEvents");
1726 $LastRunTimes = $this->DB->FetchColumn("LastRunAt", "Signature");
1727
1728 # for each known event
1729 $Events = array();
1730 foreach ($this->KnownPeriodicEvents as $Signature => $Info)
1731 {
1732 # if last run time for event is available
1733 if (array_key_exists($Signature, $LastRunTimes))
1734 {
1735 # calculate next run time for event
1736 $LastRun = strtotime($LastRunTimes[$Signature]);
1737 $NextRun = $LastRun + $this->EventPeriods[$Info["Period"]];
1738 if ($Info["Period"] == "EVENT_PERIODIC") { $LastRun = FALSE; }
1739 }
1740 else
1741 {
1742 # set info to indicate run times are not known
1743 $LastRun = FALSE;
1744 $NextRun = FALSE;
1745 }
1746
1747 # add event info to list
1748 $Events[$Signature] = $Info;
1749 $Events[$Signature]["LastRun"] = $LastRun;
1750 $Events[$Signature]["NextRun"] = $NextRun;
1751 $Events[$Signature]["Parameters"] = NULL;
1752 }
1753
1754 # return list of known events to caller
1755 return $Events;
1756 }
1757
1758 /*@)*/ /* Event Handling */
1759
1760
1761 # ---- Task Management ---------------------------------------------------
1762 /*@(*/
1764
1766 const PRIORITY_HIGH = 1;
1768 const PRIORITY_MEDIUM = 2;
1770 const PRIORITY_LOW = 3;
1772 const PRIORITY_BACKGROUND = 4;
1773
1786 function QueueTask($Callback, $Parameters = NULL,
1787 $Priority = self::PRIORITY_LOW, $Description = "")
1788 {
1789 # pack task info and write to database
1790 if ($Parameters === NULL) { $Parameters = array(); }
1791 $this->DB->Query("INSERT INTO TaskQueue"
1792 ." (Callback, Parameters, Priority, Description)"
1793 ." VALUES ('".addslashes(serialize($Callback))."', '"
1794 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
1795 .addslashes($Description)."')");
1796 }
1797
1815 function QueueUniqueTask($Callback, $Parameters = NULL,
1816 $Priority = self::PRIORITY_LOW, $Description = "")
1817 {
1818 if ($this->TaskIsInQueue($Callback, $Parameters))
1819 {
1820 $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
1821 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
1822 .($Parameters ? " AND Parameters = '"
1823 .addslashes(serialize($Parameters))."'" : ""));
1824 if ($QueryResult !== FALSE)
1825 {
1826 $Record = $this->DB->FetchRow();
1827 if ($Record["Priority"] > $Priority)
1828 {
1829 $this->DB->Query("UPDATE TaskQueue"
1830 ." SET Priority = ".intval($Priority)
1831 ." WHERE TaskId = ".intval($Record["TaskId"]));
1832 }
1833 }
1834 return FALSE;
1835 }
1836 else
1837 {
1838 $this->QueueTask($Callback, $Parameters, $Priority, $Description);
1839 return TRUE;
1840 }
1841 }
1842
1852 function TaskIsInQueue($Callback, $Parameters = NULL)
1853 {
1854 $QueuedCount = $this->DB->Query(
1855 "SELECT COUNT(*) AS FoundCount FROM TaskQueue"
1856 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
1857 .($Parameters ? " AND Parameters = '"
1858 .addslashes(serialize($Parameters))."'" : ""),
1859 "FoundCount");
1860 $RunningCount = $this->DB->Query(
1861 "SELECT COUNT(*) AS FoundCount FROM RunningTasks"
1862 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
1863 .($Parameters ? " AND Parameters = '"
1864 .addslashes(serialize($Parameters))."'" : ""),
1865 "FoundCount");
1866 $FoundCount = $QueuedCount + $RunningCount;
1867 return ($FoundCount ? TRUE : FALSE);
1868 }
1869
1875 function GetTaskQueueSize($Priority = NULL)
1876 {
1877 return $this->GetQueuedTaskCount(NULL, NULL, $Priority);
1878 }
1879
1887 function GetQueuedTaskList($Count = 100, $Offset = 0)
1888 {
1889 return $this->GetTaskList("SELECT * FROM TaskQueue"
1890 ." ORDER BY Priority, TaskId ", $Count, $Offset);
1891 }
1892
1906 function GetQueuedTaskCount($Callback = NULL,
1907 $Parameters = NULL, $Priority = NULL, $Description = NULL)
1908 {
1909 $Query = "SELECT COUNT(*) AS TaskCount FROM TaskQueue";
1910 $Sep = " WHERE";
1911 if ($Callback !== NULL)
1912 {
1913 $Query .= $Sep." Callback = '".addslashes(serialize($Callback))."'";
1914 $Sep = " AND";
1915 }
1916 if ($Parameters !== NULL)
1917 {
1918 $Query .= $Sep." Parameters = '".addslashes(serialize($Parameters))."'";
1919 $Sep = " AND";
1920 }
1921 if ($Priority !== NULL)
1922 {
1923 $Query .= $Sep." Priority = ".intval($Priority);
1924 $Sep = " AND";
1925 }
1926 if ($Description !== NULL)
1927 {
1928 $Query .= $Sep." Description = '".addslashes($Description)."'";
1929 }
1930 return $this->DB->Query($Query, "TaskCount");
1931 }
1932
1940 function GetRunningTaskList($Count = 100, $Offset = 0)
1941 {
1942 return $this->GetTaskList("SELECT * FROM RunningTasks"
1943 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
1944 (time() - ini_get("max_execution_time")))."'"
1945 ." ORDER BY StartedAt", $Count, $Offset);
1946 }
1947
1955 function GetOrphanedTaskList($Count = 100, $Offset = 0)
1956 {
1957 return $this->GetTaskList("SELECT * FROM RunningTasks"
1958 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
1959 (time() - ini_get("max_execution_time")))."'"
1960 ." ORDER BY StartedAt", $Count, $Offset);
1961 }
1962
1967 function GetOrphanedTaskCount()
1968 {
1969 return $this->DB->Query("SELECT COUNT(*) AS Count FROM RunningTasks"
1970 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
1971 (time() - ini_get("max_execution_time")))."'",
1972 "Count");
1973 }
1974
1980 function ReQueueOrphanedTask($TaskId, $NewPriority = NULL)
1981 {
1982 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
1983 $this->DB->Query("INSERT INTO TaskQueue"
1984 ." (Callback,Parameters,Priority,Description) "
1985 ."SELECT Callback, Parameters, Priority, Description"
1986 ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
1987 if ($NewPriority !== NULL)
1988 {
1989 $NewTaskId = $this->DB->LastInsertId();
1990 $this->DB->Query("UPDATE TaskQueue SET Priority = "
1991 .intval($NewPriority)
1992 ." WHERE TaskId = ".intval($NewTaskId));
1993 }
1994 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
1995 $this->DB->Query("UNLOCK TABLES");
1996 }
1997
2002 function DeleteTask($TaskId)
2003 {
2004 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2005 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2006 }
2007
2015 function GetTask($TaskId)
2016 {
2017 # assume task will not be found
2018 $Task = NULL;
2019
2020 # look for task in task queue
2021 $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2022
2023 # if task was not found in queue
2024 if (!$this->DB->NumRowsSelected())
2025 {
2026 # look for task in running task list
2027 $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = "
2028 .intval($TaskId));
2029 }
2030
2031 # if task was found
2032 if ($this->DB->NumRowsSelected())
2033 {
2034 # if task was periodic
2035 $Row = $this->DB->FetchRow();
2036 if ($Row["Callback"] ==
2037 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
2038 {
2039 # unpack periodic task callback
2040 $WrappedCallback = unserialize($Row["Parameters"]);
2041 $Task["Callback"] = $WrappedCallback[1];
2042 $Task["Parameters"] = $WrappedCallback[2];
2043 }
2044 else
2045 {
2046 # unpack task callback and parameters
2047 $Task["Callback"] = unserialize($Row["Callback"]);
2048 $Task["Parameters"] = unserialize($Row["Parameters"]);
2049 }
2050 }
2051
2052 # return task to caller
2053 return $Task;
2054 }
2055
2063 function TaskExecutionEnabled($NewValue = DB_NOVALUE)
2064 {
2065 return $this->UpdateSetting("TaskExecutionEnabled", $NewValue);
2066 }
2067
2073 function MaxTasks($NewValue = DB_NOVALUE)
2074 {
2075 return $this->UpdateSetting("MaxTasksRunning", $NewValue);
2076 }
2077
2085 function MaxExecutionTime($NewValue = NULL)
2086 {
2087 if (func_num_args() && !ini_get("safe_mode"))
2088 {
2089 if ($NewValue != $this->Settings["MaxExecTime"])
2090 {
2091 $this->Settings["MaxExecTime"] = max($NewValue, 5);
2092 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2093 ." SET MaxExecTime = '"
2094 .intval($this->Settings["MaxExecTime"])."'");
2095 }
2096 ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
2097 set_time_limit($this->Settings["MaxExecTime"]);
2098 }
2099 return ini_get("max_execution_time");
2100 }
2101
2102 /*@)*/ /* Task Management */
2103
2104
2105 # ---- Clean URL Support -------------------------------------------------
2106 /*@(*/
2108
2135 function AddCleanUrl($Pattern, $Page, $GetVars = NULL, $Template = NULL)
2136 {
2137 # save clean URL mapping parameters
2138 $this->CleanUrlMappings[] = array(
2139 "Pattern" => $Pattern,
2140 "Page" => $Page,
2141 "GetVars" => $GetVars,
2142 );
2143
2144 # if replacement template specified
2145 if ($Template !== NULL)
2146 {
2147 # if GET parameters specified
2148 if (count($GetVars))
2149 {
2150 # retrieve all possible permutations of GET parameters
2151 $GetPerms = $this->ArrayPermutations(array_keys($GetVars));
2152
2153 # for each permutation of GET parameters
2154 foreach ($GetPerms as $VarPermutation)
2155 {
2156 # construct search pattern for permutation
2157 $SearchPattern = "/href=([\"'])index\\.php\\?P=".$Page;
2158 $GetVarSegment = "";
2159 foreach ($VarPermutation as $GetVar)
2160 {
2161 if (preg_match("%\\\$[0-9]+%", $GetVars[$GetVar]))
2162 {
2163 $GetVarSegment .= "&amp;".$GetVar."=((?:(?!\\1)[^&])+)";
2164 }
2165 else
2166 {
2167 $GetVarSegment .= "&amp;".$GetVar."=".$GetVars[$GetVar];
2168 }
2169 }
2170 $SearchPattern .= $GetVarSegment."\\1/i";
2171
2172 # if template is actually a callback
2173 if (is_callable($Template))
2174 {
2175 # add pattern to HTML output mod callbacks list
2176 $this->OutputModificationCallbacks[] = array(
2177 "Pattern" => $Pattern,
2178 "Page" => $Page,
2179 "SearchPattern" => $SearchPattern,
2180 "Callback" => $Template,
2181 );
2182 }
2183 else
2184 {
2185 # construct replacement string for permutation
2186 $Replacement = $Template;
2187 $Index = 2;
2188 foreach ($VarPermutation as $GetVar)
2189 {
2190 $Replacement = str_replace(
2191 "\$".$GetVar, "\$".$Index, $Replacement);
2192 $Index++;
2193 }
2194 $Replacement = "href=\"".$Replacement."\"";
2195
2196 # add pattern to HTML output modifications list
2197 $this->OutputModificationPatterns[] = $SearchPattern;
2198 $this->OutputModificationReplacements[] = $Replacement;
2199 }
2200 }
2201 }
2202 else
2203 {
2204 # construct search pattern
2205 $SearchPattern = "/href=\"index\\.php\\?P=".$Page."\"/i";
2206
2207 # if template is actually a callback
2208 if (is_callable($Template))
2209 {
2210 # add pattern to HTML output mod callbacks list
2211 $this->OutputModificationCallbacks[] = array(
2212 "Pattern" => $Pattern,
2213 "Page" => $Page,
2214 "SearchPattern" => $SearchPattern,
2215 "Callback" => $Template,
2216 );
2217 }
2218 else
2219 {
2220 # add simple pattern to HTML output modifications list
2221 $this->OutputModificationPatterns[] = $SearchPattern;
2222 $this->OutputModificationReplacements[] = "href=\"".$Template."\"";
2223 }
2224 }
2225 }
2226 }
2227
2233 function CleanUrlIsMapped($Path)
2234 {
2235 foreach ($this->CleanUrlMappings as $Info)
2236 {
2237 if (preg_match($Info["Pattern"], $Path))
2238 {
2239 return TRUE;
2240 }
2241 }
2242 return FALSE;
2243 }
2244
2251 function GetCleanUrlForPath($Path)
2252 {
2253 # the search patterns and callbacks require a specific format
2254 $Format = "href=\"".str_replace("&", "&amp;", $Path)."\"";
2255 $Search = $Format;
2256
2257 # perform any regular expression replacements on the search string
2258 $Search = preg_replace(
2259 $this->OutputModificationPatterns,
2260 $this->OutputModificationReplacements,
2261 $Search);
2262
2263 # only run the callbacks if a replacement hasn't already been performed
2264 if ($Search == $Format)
2265 {
2266 # perform any callback replacements on the search string
2267 foreach ($this->OutputModificationCallbacks as $Info)
2268 {
2269 # make the information available to the callback
2270 $this->OutputModificationCallbackInfo = $Info;
2271
2272 # execute the callback
2273 $Search = preg_replace_callback(
2274 $Info["SearchPattern"],
2275 array($this, "OutputModificationCallbackShell"),
2276 $Search);
2277 }
2278 }
2279
2280 # return the path untouched if no replacements were performed
2281 if ($Search == $Format)
2282 {
2283 return $Path;
2284 }
2285
2286 # remove the bits added to the search string to get it recognized by
2287 # the replacement expressions and callbacks
2288 $Result = substr($Search, 6, -1);
2289
2290 return $Result;
2291 }
2292
2299 public function GetUncleanUrlForPath($Path)
2300 {
2301 # for each clean URL mapping
2302 foreach ($this->CleanUrlMappings as $Info)
2303 {
2304 # if current path matches the clean URL pattern
2305 if (preg_match($Info["Pattern"], $Path, $Matches))
2306 {
2307 # the GET parameters for the URL, starting with the page name
2308 $GetVars = array("P" => $Info["Page"]);
2309
2310 # if additional $_GET variables specified for clean URL
2311 if ($Info["GetVars"] !== NULL)
2312 {
2313 # for each $_GET variable specified for clean URL
2314 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
2315 {
2316 # start with template for variable value
2317 $Value = $VarTemplate;
2318
2319 # for each subpattern matched in current URL
2320 foreach ($Matches as $Index => $Match)
2321 {
2322 # if not first (whole) match
2323 if ($Index > 0)
2324 {
2325 # make any substitutions in template
2326 $Value = str_replace("$".$Index, $Match, $Value);
2327 }
2328 }
2329
2330 # add the GET variable
2331 $GetVars[$VarName] = $Value;
2332 }
2333 }
2334
2335 # return the unclean URL
2336 return "index.php?" . http_build_query($GetVars);
2337 }
2338 }
2339
2340 # return the path unchanged
2341 return $Path;
2342 }
2343
2349 function GetCleanUrl()
2350 {
2351 return $this->GetCleanUrlForPath($this->GetUncleanUrl());
2352 }
2353
2358 function GetUncleanUrl()
2359 {
2360 $GetVars = array("P" => $this->GetPageName()) + $_GET;
2361 return "index.php?" . http_build_query($GetVars);
2362 }
2363
2364 /*@)*/ /* Clean URL Support */
2365
2366
2367 # ---- Server Environment ------------------------------------------------
2368 /*@(*/
2370
2376 static function SessionLifetime($NewValue = NULL)
2377 {
2378 if ($NewValue !== NULL)
2379 {
2380 self::$SessionLifetime = $NewValue;
2381 }
2382 return self::$SessionLifetime;
2383 }
2384
2390 static function HtaccessSupport()
2391 {
2392 # HTACCESS_SUPPORT is set in the .htaccess file
2393 return isset($_SERVER["HTACCESS_SUPPORT"]);
2394 }
2395
2403 static function RootUrl()
2404 {
2405 # return override value if one is set
2406 if (self::$RootUrlOverride !== NULL)
2407 {
2408 return self::$RootUrlOverride;
2409 }
2410
2411 # determine scheme name
2412 $Protocol = (isset($_SERVER["HTTPS"]) ? "https" : "http");
2413
2414 # if HTTP_HOST is preferred or SERVER_NAME points to localhost
2415 # and HTTP_HOST is set
2416 if ((self::$PreferHttpHost || ($_SERVER["SERVER_NAME"] == "127.0.0.1"))
2417 && isset($_SERVER["HTTP_HOST"]))
2418 {
2419 # use HTTP_HOST for domain name
2420 $DomainName = $_SERVER["HTTP_HOST"];
2421 }
2422 else
2423 {
2424 # use SERVER_NAME for domain name
2425 $DomainName = $_SERVER["HTTP_HOST"];
2426 }
2427
2428 # build URL root and return to caller
2429 return $Protocol."://".$DomainName;
2430 }
2431
2446 static function RootUrlOverride($NewValue = self::NOVALUE)
2447 {
2448 if ($NewValue !== self::NOVALUE)
2449 {
2450 self::$RootUrlOverride = strlen(trim($NewValue)) ? $NewValue : NULL;
2451 }
2452 return self::$RootUrlOverride;
2453 }
2454
2464 static function BaseUrl()
2465 {
2466 $BaseUrl = self::RootUrl().dirname($_SERVER["SCRIPT_NAME"]);
2467 if (substr($BaseUrl, -1) != "/") { $BaseUrl .= "/"; }
2468 return $BaseUrl;
2469 }
2470
2478 static function FullUrl()
2479 {
2480 return self::RootUrl().$_SERVER["REQUEST_URI"];
2481 }
2482
2493 static function PreferHttpHost($NewValue = NULL)
2494 {
2495 if ($NewValue !== NULL)
2496 {
2497 self::$PreferHttpHost = ($NewValue ? TRUE : FALSE);
2498 }
2499 return self::$PreferHttpHost;
2500 }
2501
2506 static function BasePath()
2507 {
2508 $BasePath = dirname($_SERVER["SCRIPT_NAME"]);
2509
2510 if (substr($BasePath, -1) != "/")
2511 {
2512 $BasePath .= "/";
2513 }
2514
2515 return $BasePath;
2516 }
2517
2523 static function GetScriptUrl()
2524 {
2525 if (array_key_exists("SCRIPT_URL", $_SERVER))
2526 {
2527 return $_SERVER["SCRIPT_URL"];
2528 }
2529 elseif (array_key_exists("REDIRECT_URL", $_SERVER))
2530 {
2531 return $_SERVER["REDIRECT_URL"];
2532 }
2533 elseif (array_key_exists("REQUEST_URI", $_SERVER))
2534 {
2535 $Pieces = parse_url($_SERVER["REQUEST_URI"]);
2536 return $Pieces["path"];
2537 }
2538 else
2539 {
2540 return NULL;
2541 }
2542 }
2543
2552 static function WasUrlRewritten($ScriptName="index.php")
2553 {
2554 # needed to get the path of the URL minus the query and fragment pieces
2555 $Components = parse_url(self::GetScriptUrl());
2556
2557 # if parsing was successful and a path is set
2558 if (is_array($Components) && isset($Components["path"]))
2559 {
2560 $BasePath = self::BasePath();
2561 $Path = $Components["path"];
2562
2563 # the URL was rewritten if the path isn't the base path, i.e., the
2564 # home page, and the file in the URL isn't the script generating the
2565 # page
2566 if ($BasePath != $Path && basename($Path) != $ScriptName)
2567 {
2568 return TRUE;
2569 }
2570 }
2571
2572 # the URL wasn't rewritten
2573 return FALSE;
2574 }
2575
2581 static function GetFreeMemory()
2582 {
2583 return self::GetPhpMemoryLimit() - memory_get_usage();
2584 }
2585
2591 static function GetPhpMemoryLimit()
2592 {
2593 $Str = strtoupper(ini_get("memory_limit"));
2594 if (substr($Str, -1) == "B") { $Str = substr($Str, 0, strlen($Str) - 1); }
2595 switch (substr($Str, -1))
2596 {
2597 case "K": $MemoryLimit = (int)$Str * 1024; break;
2598 case "M": $MemoryLimit = (int)$Str * 1048576; break;
2599 case "G": $MemoryLimit = (int)$Str * 1073741824; break;
2600 default: $MemoryLimit = (int)$Str; break;
2601 }
2602 return $MemoryLimit;
2603 }
2604
2605 /*@)*/ /* Server Environment */
2606
2607
2608 # ---- Backward Compatibility --------------------------------------------
2609 /*@(*/
2611
2616 function FindCommonTemplate($BaseName)
2617 {
2618 return $this->FindFile(
2619 $this->IncludeDirList, $BaseName, array("tpl", "html"));
2620 }
2621
2622 /*@)*/ /* Backward Compatibility */
2623
2624
2625 # ---- PRIVATE INTERFACE -------------------------------------------------
2626
2627 private $ActiveUI = "default";
2628 private $BrowserDetectFunc;
2629 private $CleanUrlMappings = array();
2630 private $CleanUrlRewritePerformed = FALSE;
2631 private $DB;
2632 private $DefaultPage = "Home";
2633 private $EnvIncludes = array();
2634 private $ExecutionStartTime;
2635 private $FoundUIFiles = array();
2636 private $AdditionalRequiredUIFiles = array();
2637 private $GenerateCompactCss = TRUE;
2638 private $HtmlCharset = "UTF-8";
2639 private $JumpToPage = NULL;
2640 private $LogFileName = "local/logs/site.log";
2641 private $MaxRunningTasksToTrack = 250;
2642 private $OutputModificationPatterns = array();
2643 private $OutputModificationReplacements = array();
2644 private $OutputModificationCallbacks = array();
2645 private $OutputModificationCallbackInfo;
2646 private $PageName;
2647 private $PostProcessingFuncs = array();
2648 private $RunningInBackground = FALSE;
2649 private $RunningTask;
2650 private $SavedContext;
2651 private $Settings;
2652 private $SuppressHTML = FALSE;
2653 private $SaveTemplateLocationCache = FALSE;
2654 private $UnbufferedCallbacks = array();
2655 private $UseBaseTag = FALSE;
2656 private $UseMinimizedJavascript = FALSE;
2657 private $UseScss = TRUE;
2658
2659 private static $AppName = "ScoutAF";
2660 private static $ObjectDirectories = array();
2661 private static $ObjectLocationCache;
2662 private static $ObjectLocationCacheInterval = 60;
2663 private static $ObjectLocationCacheExpiration;
2664 private static $PreferHttpHost = FALSE;
2665 private static $RootUrlOverride = NULL;
2666 private static $SaveObjectLocationCache = FALSE;
2667 private static $ScssCacheDir = "local/data/caches/SCSS";
2668 private static $SessionLifetime = 1440;
2669
2674 private $NoTSR = FALSE;
2675
2676 private $KnownPeriodicEvents = array();
2677 private $PeriodicEvents = array(
2678 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
2679 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
2680 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
2681 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
2682 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
2683 );
2684 private $EventPeriods = array(
2685 "EVENT_HOURLY" => 3600,
2686 "EVENT_DAILY" => 86400,
2687 "EVENT_WEEKLY" => 604800,
2688 "EVENT_MONTHLY" => 2592000,
2689 "EVENT_PERIODIC" => 0,
2690 );
2691 private $UIEvents = array(
2692 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
2693 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2694 "EVENT_PHP_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2695 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2696 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2697 "EVENT_PAGE_OUTPUT_FILTER" => self::EVENTTYPE_CHAIN,
2698 );
2699
2703 private function LoadSettings()
2704 {
2705 # read settings in from database
2706 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2707 $this->Settings = $this->DB->FetchRow();
2708
2709 # if settings were not previously initialized
2710 if (!$this->Settings)
2711 {
2712 # initialize settings in database
2713 $this->DB->Query("INSERT INTO ApplicationFrameworkSettings"
2714 ." (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')");
2715
2716 # read new settings in from database
2717 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2718 $this->Settings = $this->DB->FetchRow();
2719 }
2720
2721 # if base path was not previously set or we appear to have moved
2722 if (!array_key_exists("BasePath", $this->Settings)
2723 || (!strlen($this->Settings["BasePath"]))
2724 || (!array_key_exists("BasePathCheck", $this->Settings))
2725 || (__FILE__ != $this->Settings["BasePathCheck"]))
2726 {
2727 # attempt to extract base path from Apache .htaccess file
2728 if (is_readable(".htaccess"))
2729 {
2730 $Lines = file(".htaccess");
2731 foreach ($Lines as $Line)
2732 {
2733 if (preg_match("/\\s*RewriteBase\\s+/", $Line))
2734 {
2735 $Pieces = preg_split(
2736 "/\\s+/", $Line, NULL, PREG_SPLIT_NO_EMPTY);
2737 $BasePath = $Pieces[1];
2738 }
2739 }
2740 }
2741
2742 # if base path was found
2743 if (isset($BasePath))
2744 {
2745 # save base path locally
2746 $this->Settings["BasePath"] = $BasePath;
2747
2748 # save base path to database
2749 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2750 ." SET BasePath = '".addslashes($BasePath)."'"
2751 .", BasePathCheck = '".addslashes(__FILE__)."'");
2752 }
2753 }
2754
2755 # if template location cache has been saved to database
2756 if (isset($this->Settings["TemplateLocationCache"]))
2757 {
2758 # unserialize cache values into array and use if valid
2759 $Cache = unserialize($this->Settings["TemplateLocationCache"]);
2760 $this->Settings["TemplateLocationCache"] =
2761 count($Cache) ? $Cache : array();
2762 }
2763 else
2764 {
2765 # start with empty cache
2766 $this->Settings["TemplateLocationCache"] = array();
2767 }
2768
2769 # if object location cache has been saved to database
2770 if (isset($this->Settings["ObjectLocationCache"]))
2771 {
2772 # unserialize cache values into array and use if valid
2773 $Cache = unserialize($this->Settings["ObjectLocationCache"]);
2774 $this->Settings["ObjectLocationCache"] =
2775 count($Cache) ? $Cache : array();
2776
2777 # store static versions for use when autoloading objects
2778 self::$ObjectLocationCache =
2779 $this->Settings["ObjectLocationCache"];
2780 self::$ObjectLocationCacheInterval =
2781 $this->Settings["ObjectLocationCacheInterval"];
2782 self::$ObjectLocationCacheExpiration =
2783 $this->Settings["ObjectLocationCacheExpiration"];
2784 }
2785 else
2786 {
2787 # start with empty cache
2788 $this->Settings["ObjectLocationCache"] = array();
2789 }
2790 }
2791
2798 private function RewriteCleanUrls($PageName)
2799 {
2800 # if URL rewriting is supported by the server
2801 if ($this->HtaccessSupport())
2802 {
2803 # retrieve current URL and remove base path if present
2804 $Url = $this->GetPageLocation();
2805
2806 # for each clean URL mapping
2807 foreach ($this->CleanUrlMappings as $Info)
2808 {
2809 # if current URL matches clean URL pattern
2810 if (preg_match($Info["Pattern"], $Url, $Matches))
2811 {
2812 # set new page
2813 $PageName = $Info["Page"];
2814
2815 # if $_GET variables specified for clean URL
2816 if ($Info["GetVars"] !== NULL)
2817 {
2818 # for each $_GET variable specified for clean URL
2819 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
2820 {
2821 # start with template for variable value
2822 $Value = $VarTemplate;
2823
2824 # for each subpattern matched in current URL
2825 foreach ($Matches as $Index => $Match)
2826 {
2827 # if not first (whole) match
2828 if ($Index > 0)
2829 {
2830 # make any substitutions in template
2831 $Value = str_replace("$".$Index, $Match, $Value);
2832 }
2833 }
2834
2835 # set $_GET variable
2836 $_GET[$VarName] = $Value;
2837 }
2838 }
2839
2840 # set flag indicating clean URL mapped
2841 $this->CleanUrlRewritePerformed = TRUE;
2842
2843 # stop looking for a mapping
2844 break;
2845 }
2846 }
2847 }
2848
2849 # return (possibly) updated page name to caller
2850 return $PageName;
2851 }
2852
2871 private function FindFile($DirectoryList, $BaseName,
2872 $PossibleSuffixes = NULL, $PossiblePrefixes = NULL)
2873 {
2874 # generate template cache index for this page
2875 $CacheIndex = md5(serialize($DirectoryList))
2876 .":".$this->ActiveUI.":".$BaseName;
2877
2878 # if we have cached location and cache expiration time has not elapsed
2879 if (($this->Settings["TemplateLocationCacheInterval"] > 0)
2880 && count($this->Settings["TemplateLocationCache"])
2881 && array_key_exists($CacheIndex,
2882 $this->Settings["TemplateLocationCache"])
2883 && (time() < strtotime(
2884 $this->Settings["TemplateLocationCacheExpiration"])))
2885 {
2886 # use template location from cache
2887 $FoundFileName = $this->Settings[
2888 "TemplateLocationCache"][$CacheIndex];
2889 }
2890 else
2891 {
2892 # if suffixes specified and base name does not include suffix
2893 if (count($PossibleSuffixes)
2894 && !preg_match("/\.[a-zA-Z0-9]+$/", $BaseName))
2895 {
2896 # add versions of file names with suffixes to file name list
2897 $FileNames = array();
2898 foreach ($PossibleSuffixes as $Suffix)
2899 {
2900 $FileNames[] = $BaseName.".".$Suffix;
2901 }
2902 }
2903 else
2904 {
2905 # use base name as file name
2906 $FileNames = array($BaseName);
2907 }
2908
2909 # if prefixes specified
2910 if (count($PossiblePrefixes))
2911 {
2912 # add versions of file names with prefixes to file name list
2913 $NewFileNames = array();
2914 foreach ($FileNames as $FileName)
2915 {
2916 foreach ($PossiblePrefixes as $Prefix)
2917 {
2918 $NewFileNames[] = $Prefix.$FileName;
2919 }
2920 }
2921 $FileNames = $NewFileNames;
2922 }
2923
2924 # for each possible location
2925 $FoundFileName = NULL;
2926 foreach ($DirectoryList as $Dir)
2927 {
2928 # substitute active UI name into path
2929 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
2930
2931 # for each possible file name
2932 foreach ($FileNames as $File)
2933 {
2934 # if template is found at location
2935 if (file_exists($Dir.$File))
2936 {
2937 # save full template file name and stop looking
2938 $FoundFileName = $Dir.$File;
2939 break 2;
2940 }
2941 }
2942 }
2943
2944 # save location in cache
2945 $this->Settings["TemplateLocationCache"][$CacheIndex]
2946 = $FoundFileName;
2947
2948 # set flag indicating that cache should be saved
2949 $this->SaveTemplateLocationCache = TRUE;
2950 }
2951
2952 # return full template file name to caller
2953 return $FoundFileName;
2954 }
2955
2963 private function CompileScssFile($SrcFile)
2964 {
2965 # build path to CSS file
2966 $DstFile = "local/data/caches/SCSS/"
2967 .str_replace("/", "_", dirname($SrcFile))
2968 ."_".basename($SrcFile);
2969 $DstFile = substr_replace($DstFile, "css", -4);
2970
2971 # if SCSS file is newer than CSS file
2972 if (!file_exists($DstFile)
2973 || (filemtime($SrcFile) > filemtime($DstFile)))
2974 {
2975 # if CSS cache directory and CSS file path appear writable
2976 static $CacheDirIsWritable;
2977 if (!isset($CacheDirIsWritable))
2978 { $CacheDirIsWritable = is_writable(self::$ScssCacheDir); }
2979 if (is_writable($DstFile)
2980 || (!file_exists($DstFile) && $CacheDirIsWritable))
2981 {
2982 # compile SCSS file to CSS file
2983 $ScssCompiler = new scssc();
2984 $ScssCompiler->setFormatter($this->GenerateCompactCss
2985 ? "scss_formatter_compressed" : "scss_formatter");
2986 $ScssCode = file_get_contents($SrcFile);
2987 try
2988 {
2989 $CssCode = $ScssCompiler->compile($ScssCode);
2990 file_put_contents($DstFile, $CssCode);
2991 }
2992 catch (Exception $Ex)
2993 {
2994 $this->LogError(self::LOGLVL_ERROR,
2995 "Error compiling SCSS file ".$SrcFile.": "
2996 .$Ex->getMessage());
2997 $DstFile = NULL;
2998 }
2999 }
3000 else
3001 {
3002 # log error and set CSS file path to indicate failure
3003 $this->LogError(self::LOGLVL_ERROR,
3004 "Unable to write out CSS file for SCSS file ".$SrcFile);
3005 $DstFile = NULL;
3006 }
3007 }
3008
3009 # return CSS file path to caller
3010 return $DstFile;
3011 }
3012
3019 private function GetRequiredFilesNotYetLoaded($PageContentFile)
3020 {
3021 # start out assuming no files required
3022 $RequiredFiles = array();
3023
3024 # if page content file supplied
3025 if ($PageContentFile)
3026 {
3027 # if file containing list of required files is available
3028 $Path = dirname($PageContentFile);
3029 $RequireListFile = $Path."/REQUIRES";
3030 if (file_exists($RequireListFile))
3031 {
3032 # read in list of required files
3033 $RequestedFiles = file($RequireListFile);
3034
3035 # for each line in required file list
3036 foreach ($RequestedFiles as $Line)
3037 {
3038 # if line is not a comment
3039 $Line = trim($Line);
3040 if (!preg_match("/^#/", $Line))
3041 {
3042 # if file has not already been loaded
3043 if (!in_array($Line, $this->FoundUIFiles))
3044 {
3045 # add to list of required files
3046 $RequiredFiles[] = $Line;
3047 }
3048 }
3049 }
3050 }
3051 }
3052
3053 # add in additional required files if any
3054 if (count($this->AdditionalRequiredUIFiles))
3055 {
3056 # make sure there are no duplicates
3057 $AdditionalRequiredUIFiles = array_unique(
3058 $this->AdditionalRequiredUIFiles);
3059
3060 $RequiredFiles = array_merge(
3061 $RequiredFiles, $AdditionalRequiredUIFiles);
3062 }
3063
3064 # return list of required files to caller
3065 return $RequiredFiles;
3066 }
3067
3071 private function SetUpObjectAutoloading()
3072 {
3074 function __autoload($ClassName)
3075 {
3076 ApplicationFramework::AutoloadObjects($ClassName);
3077 }
3078 }
3079
3085 static function AutoloadObjects($ClassName)
3086 {
3087 # if caching is not turned off
3088 # and we have a cached location for class
3089 # and cache expiration has not elapsed
3090 # and file at cached location is readable
3091 if ((self::$ObjectLocationCacheInterval > 0)
3092 && count(self::$ObjectLocationCache)
3093 && array_key_exists($ClassName,
3094 self::$ObjectLocationCache)
3095 && (time() < strtotime(
3096 self::$ObjectLocationCacheExpiration))
3097 && is_readable(self::$ObjectLocationCache[$ClassName]))
3098 {
3099 # use object location from cache
3100 require_once(self::$ObjectLocationCache[$ClassName]);
3101 }
3102 else
3103 {
3104 # for each possible object file directory
3105 static $FileLists;
3106 foreach (self::$ObjectDirectories as $Location => $Info)
3107 {
3108 # if directory looks valid
3109 if (is_dir($Location))
3110 {
3111 # build class file name
3112 $NewClassName = ($Info["ClassPattern"] && $Info["ClassReplacement"])
3113 ? preg_replace($Info["ClassPattern"],
3114 $Info["ClassReplacement"], $ClassName)
3115 : $ClassName;
3116
3117 # read in directory contents if not already retrieved
3118 if (!isset($FileLists[$Location]))
3119 {
3120 $FileLists[$Location] = self::ReadDirectoryTree(
3121 $Location, '/^.+\.php$/i');
3122 }
3123
3124 # for each file in target directory
3125 $FileNames = $FileLists[$Location];
3126 $TargetName = strtolower($Info["Prefix"].$NewClassName.".php");
3127 foreach ($FileNames as $FileName)
3128 {
3129 # if file matches our target object file name
3130 if (strtolower($FileName) == $TargetName)
3131 {
3132 # include object file
3133 require_once($Location.$FileName);
3134
3135 # save location to cache
3136 self::$ObjectLocationCache[$ClassName]
3137 = $Location.$FileName;
3138
3139 # set flag indicating that cache should be saved
3140 self::$SaveObjectLocationCache = TRUE;
3141
3142 # stop looking
3143 break 2;
3144 }
3145 }
3146 }
3147 }
3148 }
3149 }
3159 private static function ReadDirectoryTree($Directory, $Pattern)
3160 {
3161 $CurrentDir = getcwd();
3162 chdir($Directory);
3163 $DirIter = new RecursiveDirectoryIterator(".");
3164 $IterIter = new RecursiveIteratorIterator($DirIter);
3165 $RegexResults = new RegexIterator($IterIter, $Pattern,
3166 RecursiveRegexIterator::GET_MATCH);
3167 $FileList = array();
3168 foreach ($RegexResults as $Result)
3169 {
3170 $FileList[] = substr($Result[0], 2);
3171 }
3172 chdir($CurrentDir);
3173 return $FileList;
3174 }
3175
3179 private function UndoMagicQuotes()
3180 {
3181 # if this PHP version has magic quotes support
3182 if (version_compare(PHP_VERSION, "5.4.0", "<"))
3183 {
3184 # turn off runtime magic quotes if on
3185 if (get_magic_quotes_runtime())
3186 {
3187 // @codingStandardsIgnoreStart
3188 set_magic_quotes_runtime(FALSE);
3189 // @codingStandardsIgnoreEnd
3190 }
3191
3192 # if magic quotes GPC is on
3193 if (get_magic_quotes_gpc())
3194 {
3195 # strip added slashes from incoming variables
3196 $GPC = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
3197 array_walk_recursive($GPC,
3198 array($this, "UndoMagicQuotes_StripCallback"));
3199 }
3200 }
3201 }
3202 private function UndoMagicQuotes_StripCallback(&$Value)
3203 {
3204 $Value = stripslashes($Value);
3205 }
3206
3211 private function LoadUIFunctions()
3212 {
3213 $Dirs = array(
3214 "local/interface/%ACTIVEUI%/include",
3215 "interface/%ACTIVEUI%/include",
3216 "local/interface/default/include",
3217 "interface/default/include",
3218 );
3219 foreach ($Dirs as $Dir)
3220 {
3221 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
3222 if (is_dir($Dir))
3223 {
3224 $FileNames = scandir($Dir);
3225 foreach ($FileNames as $FileName)
3226 {
3227 if (preg_match("/^F-([A-Za-z0-9_]+)\.php/", $FileName, $Matches)
3228 || preg_match("/^F-([A-Za-z0-9_]+)\.html/", $FileName, $Matches))
3229 {
3230 if (!function_exists($Matches[1]))
3231 {
3232 include_once($Dir."/".$FileName);
3233 }
3234 }
3235 }
3236 }
3237 }
3238 }
3239
3245 private function ProcessPeriodicEvent($EventName, $Callback)
3246 {
3247 # retrieve last execution time for event if available
3248 $Signature = self::GetCallbackSignature($Callback);
3249 $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
3250 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
3251
3252 # determine whether enough time has passed for event to execute
3253 $ShouldExecute = (($LastRun === NULL)
3254 || (time() > (strtotime($LastRun) + $this->EventPeriods[$EventName])))
3255 ? TRUE : FALSE;
3256
3257 # if event should run
3258 if ($ShouldExecute)
3259 {
3260 # add event to task queue
3261 $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
3262 $WrapperParameters = array(
3263 $EventName, $Callback, array("LastRunAt" => $LastRun));
3264 $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
3265 }
3266
3267 # add event to list of periodic events
3268 $this->KnownPeriodicEvents[$Signature] = array(
3269 "Period" => $EventName,
3270 "Callback" => $Callback,
3271 "Queued" => $ShouldExecute);
3272 }
3273
3281 private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
3282 {
3283 static $DB;
3284 if (!isset($DB)) { $DB = new Database(); }
3285
3286 # run event
3287 $ReturnVal = call_user_func_array($Callback, $Parameters);
3288
3289 # if event is already in database
3290 $Signature = self::GetCallbackSignature($Callback);
3291 if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
3292 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
3293 {
3294 # update last run time for event
3295 $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
3296 .(($EventName == "EVENT_PERIODIC")
3297 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
3298 : "NOW()")
3299 ." WHERE Signature = '".addslashes($Signature)."'");
3300 }
3301 else
3302 {
3303 # add last run time for event to database
3304 $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
3305 ."('".addslashes($Signature)."', "
3306 .(($EventName == "EVENT_PERIODIC")
3307 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
3308 : "NOW()").")");
3309 }
3310 }
3311
3317 private static function GetCallbackSignature($Callback)
3318 {
3319 return !is_array($Callback) ? $Callback
3320 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
3321 ."::".$Callback[1];
3322 }
3323
3328 private function PrepForTSR()
3329 {
3330 # if HTML has been output and it's time to launch another task
3331 # (only TSR if HTML has been output because otherwise browsers
3332 # may misbehave after connection is closed)
3333 if (($this->JumpToPage || !$this->SuppressHTML)
3334 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
3335 + (ini_get("max_execution_time")
3336 / $this->Settings["MaxTasksRunning"]) + 5))
3337 && $this->GetTaskQueueSize()
3338 && $this->Settings["TaskExecutionEnabled"])
3339 {
3340 # begin buffering output for TSR
3341 ob_start();
3342
3343 # let caller know it is time to launch another task
3344 return TRUE;
3345 }
3346 else
3347 {
3348 # let caller know it is not time to launch another task
3349 return FALSE;
3350 }
3351 }
3352
3357 private function LaunchTSR()
3358 {
3359 # set headers to close out connection to browser
3360 if (!$this->NoTSR)
3361 {
3362 ignore_user_abort(TRUE);
3363 header("Connection: close");
3364 header("Content-Length: ".ob_get_length());
3365 }
3366
3367 # output buffered content
3368 while (ob_get_level()) { ob_end_flush(); }
3369 flush();
3370
3371 # write out any outstanding data and end HTTP session
3372 session_write_close();
3373
3374 # set flag indicating that we are now running in background
3375 $this->RunningInBackground = TRUE;
3376
3377 # if there is still a task in the queue
3378 if ($this->GetTaskQueueSize())
3379 {
3380 # turn on output buffering to (hopefully) record any crash output
3381 ob_start();
3382
3383 # lock tables and grab last task run time to double check
3384 $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
3385 $this->LoadSettings();
3386
3387 # if still time to launch another task
3388 if (time() > (strtotime($this->Settings["LastTaskRunAt"])
3389 + (ini_get("max_execution_time")
3390 / $this->Settings["MaxTasksRunning"]) + 5))
3391 {
3392 # update the "last run" time and release tables
3393 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
3394 ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
3395 $this->DB->Query("UNLOCK TABLES");
3396
3397 # run tasks while there is a task in the queue and enough time left
3398 do
3399 {
3400 # run the next task
3401 $this->RunNextTask();
3402 }
3403 while ($this->GetTaskQueueSize()
3404 && ($this->GetSecondsBeforeTimeout() > 65));
3405 }
3406 else
3407 {
3408 # release tables
3409 $this->DB->Query("UNLOCK TABLES");
3410 }
3411 }
3412 }
3413
3421 private function GetTaskList($DBQuery, $Count, $Offset)
3422 {
3423 $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
3424 $Tasks = array();
3425 while ($Row = $this->DB->FetchRow())
3426 {
3427 $Tasks[$Row["TaskId"]] = $Row;
3428 if ($Row["Callback"] ==
3429 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
3430 {
3431 $WrappedCallback = unserialize($Row["Parameters"]);
3432 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
3433 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
3434 }
3435 else
3436 {
3437 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
3438 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
3439 }
3440 }
3441 return $Tasks;
3442 }
3443
3447 private function RunNextTask()
3448 {
3449 # lock tables to prevent same task from being run by multiple sessions
3450 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
3451
3452 # look for task at head of queue
3453 $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
3454 $Task = $this->DB->FetchRow();
3455
3456 # if there was a task available
3457 if ($Task)
3458 {
3459 # move task from queue to running tasks list
3460 $this->DB->Query("INSERT INTO RunningTasks "
3461 ."(TaskId,Callback,Parameters,Priority,Description) "
3462 ."SELECT * FROM TaskQueue WHERE TaskId = "
3463 .intval($Task["TaskId"]));
3464 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
3465 .intval($Task["TaskId"]));
3466
3467 # release table locks to again allow other sessions to run tasks
3468 $this->DB->Query("UNLOCK TABLES");
3469
3470 # unpack stored task info
3471 $Callback = unserialize($Task["Callback"]);
3472 $Parameters = unserialize($Task["Parameters"]);
3473
3474 # attempt to load task callback if not already available
3475 $this->LoadFunction($Callback);
3476
3477 # run task
3478 $this->RunningTask = $Task;
3479 if ($Parameters)
3480 {
3481 call_user_func_array($Callback, $Parameters);
3482 }
3483 else
3484 {
3485 call_user_func($Callback);
3486 }
3487 unset($this->RunningTask);
3488
3489 # remove task from running tasks list
3490 $this->DB->Query("DELETE FROM RunningTasks"
3491 ." WHERE TaskId = ".intval($Task["TaskId"]));
3492
3493 # prune running tasks list if necessary
3494 $RunningTasksCount = $this->DB->Query(
3495 "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
3496 if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
3497 {
3498 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
3499 ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
3500 }
3501 }
3502 else
3503 {
3504 # release table locks to again allow other sessions to run tasks
3505 $this->DB->Query("UNLOCK TABLES");
3506 }
3507 }
3508
3514 function OnCrash()
3515 {
3516 # attempt to remove any memory limits
3517 ini_set("memory_limit", -1);
3518
3519 # if there is a background task currently running
3520 if (isset($this->RunningTask))
3521 {
3522 # add info about error that caused crash (if available)
3523 if (function_exists("error_get_last"))
3524 {
3525 $CrashInfo["LastError"] = error_get_last();
3526 }
3527
3528 # add info about current output buffer contents (if available)
3529 if (ob_get_length() !== FALSE)
3530 {
3531 $CrashInfo["OutputBuffer"] = ob_get_contents();
3532 }
3533
3534 # if backtrace info is available for the crash
3535 $Backtrace = debug_backtrace();
3536 if (count($Backtrace) > 1)
3537 {
3538 # discard the current context from the backtrace
3539 array_shift($Backtrace);
3540
3541 # add the backtrace to the crash info
3542 $CrashInfo["Backtrace"] = $Backtrace;
3543 }
3544 # else if saved backtrace info is available
3545 elseif (isset($this->SavedContext))
3546 {
3547 # add the saved backtrace to the crash info
3548 $CrashInfo["Backtrace"] = $this->SavedContext;
3549 }
3550
3551 # if we have crash info to recod
3552 if (isset($CrashInfo))
3553 {
3554 # save crash info for currently running task
3555 $DB = new Database();
3556 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
3557 .addslashes(serialize($CrashInfo))
3558 ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
3559 }
3560 }
3561
3562 print("\n");
3563 return;
3564 }
3565
3582 private function AddToDirList($DirList, $Dir, $SearchLast, $SkipSlashCheck)
3583 {
3584 # convert incoming directory to array of directories (if needed)
3585 $Dirs = is_array($Dir) ? $Dir : array($Dir);
3586
3587 # reverse array so directories are searched in specified order
3588 $Dirs = array_reverse($Dirs);
3589
3590 # for each directory
3591 foreach ($Dirs as $Location)
3592 {
3593 # make sure directory includes trailing slash
3594 if (!$SkipSlashCheck)
3595 {
3596 $Location = $Location
3597 .((substr($Location, -1) != "/") ? "/" : "");
3598 }
3599
3600 # remove directory from list if already present
3601 if (in_array($Location, $DirList))
3602 {
3603 $DirList = array_diff(
3604 $DirList, array($Location));
3605 }
3606
3607 # add directory to list of directories
3608 if ($SearchLast)
3609 {
3610 array_push($DirList, $Location);
3611 }
3612 else
3613 {
3614 array_unshift($DirList, $Location);
3615 }
3616 }
3617
3618 # return updated directory list to caller
3619 return $DirList;
3620 }
3621
3629 private function ArrayPermutations($Items, $Perms = array())
3630 {
3631 if (empty($Items))
3632 {
3633 $Result = array($Perms);
3634 }
3635 else
3636 {
3637 $Result = array();
3638 for ($Index = count($Items) - 1; $Index >= 0; --$Index)
3639 {
3640 $NewItems = $Items;
3641 $NewPerms = $Perms;
3642 list($Segment) = array_splice($NewItems, $Index, 1);
3643 array_unshift($NewPerms, $Segment);
3644 $Result = array_merge($Result,
3645 $this->ArrayPermutations($NewItems, $NewPerms));
3646 }
3647 }
3648 return $Result;
3649 }
3650
3657 private function OutputModificationCallbackShell($Matches)
3658 {
3659 # call previously-stored external function
3660 return call_user_func($this->OutputModificationCallbackInfo["Callback"],
3661 $Matches,
3662 $this->OutputModificationCallbackInfo["Pattern"],
3663 $this->OutputModificationCallbackInfo["Page"],
3664 $this->OutputModificationCallbackInfo["SearchPattern"]);
3665 }
3666
3673 function UpdateSetting($FieldName, $NewValue = DB_NOVALUE)
3674 {
3675 return $this->DB->UpdateValue("ApplicationFrameworkSettings",
3676 $FieldName, $NewValue, NULL, $this->Settings);
3677 }
3678
3680 private $InterfaceDirList = array(
3681 "local/interface/%ACTIVEUI%/",
3682 "interface/%ACTIVEUI%/",
3683 "local/interface/default/",
3684 "interface/default/",
3685 );
3690 private $IncludeDirList = array(
3691 "local/interface/%ACTIVEUI%/include/",
3692 "interface/%ACTIVEUI%/include/",
3693 "local/interface/default/include/",
3694 "interface/default/include/",
3695 );
3697 private $ImageDirList = array(
3698 "local/interface/%ACTIVEUI%/images/",
3699 "interface/%ACTIVEUI%/images/",
3700 "local/interface/default/images/",
3701 "interface/default/images/",
3702 );
3704 private $FunctionDirList = array(
3705 "local/interface/%ACTIVEUI%/include/",
3706 "interface/%ACTIVEUI%/include/",
3707 "local/interface/default/include/",
3708 "interface/default/include/",
3709 "local/include/",
3710 "include/",
3711 );
3712
3713 const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
3714 }
3715
3716
ApplicationFramework\MaxTasks
MaxTasks($NewValue=DB_NOVALUE)
Get/set maximum number of tasks to have running simultaneously.
Definition: ApplicationFramework.php:2073
ApplicationFramework\LOGLVL_ERROR
const LOGLVL_ERROR
ERROR error logging level.
Definition: ApplicationFramework.php:1414
ApplicationFramework\GetOrphanedTaskList
GetOrphanedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:1955
ApplicationFramework\SuppressHTMLOutput
SuppressHTMLOutput($NewSetting=TRUE)
Suppress loading of HTML files.
Definition: ApplicationFramework.php:893
ApplicationFramework\AddInterfaceDirectories
AddInterfaceDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for user interface (HTML/TPL) files.
Definition: ApplicationFramework.php:240
ApplicationFramework\AddIncludeDirectories
AddIncludeDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for user interface include (CSS, JavaScript, common PHP, common HTML, etc) files.
Definition: ApplicationFramework.php:214
ApplicationFramework\GetScriptUrl
static GetScriptUrl()
Retrieve SCRIPT_URL server value, pulling it from elsewhere if that variable isn't set...
Definition: ApplicationFramework.php:2523
ApplicationFramework\LOGLVL_INFO
const LOGLVL_INFO
INFO error logging level.
Definition: ApplicationFramework.php:1403
ApplicationFramework\AddUnbufferedCallback
AddUnbufferedCallback($Callback, $Parameters=array())
Add a callback that will be executed after buffered content has been output and that won't have its o...
Definition: ApplicationFramework.php:289
ApplicationFramework\QueueUniqueTask
QueueUniqueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue if not already in queue or currently running.
Definition: ApplicationFramework.php:1815
ApplicationFramework\LOGLVL_FATAL
const LOGLVL_FATAL
FATAL error logging level.
Definition: ApplicationFramework.php:1419
ApplicationFramework\UseMinimizedJavascript
UseMinimizedJavascript($NewSetting=NULL)
Get/set whether or not to check for and use minimized JavaScript files when getting a JavaScript UI f...
Definition: ApplicationFramework.php:865
ApplicationFramework\AddPostProcessingCall
AddPostProcessingCall($FunctionName, &$Arg1=self::NOVALUE, &$Arg2=self::NOVALUE, &$Arg3=self::NOVALUE, &$Arg4=self::NOVALUE, &$Arg5=self::NOVALUE, &$Arg6=self::NOVALUE, &$Arg7=self::NOVALUE, &$Arg8=self::NOVALUE, &$Arg9=self::NOVALUE)
Add function to be called after HTML has been loaded.
Definition: ApplicationFramework.php:984
ApplicationFramework\GetCleanUrlForPath
GetCleanUrlForPath($Path)
Get the clean URL mapped for a path.
Definition: ApplicationFramework.php:2251
ApplicationFramework\PRIORITY_LOW
const PRIORITY_LOW
Lower priority.
Definition: ApplicationFramework.php:1770
Message
Abstraction for forum messages and resource comments.
Definition: Message.php:15
ApplicationFramework\GetQueuedTaskList
GetQueuedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:1887
ApplicationFramework\LogFile
LogFile($NewValue=NULL)
Get/set log file name.
Definition: ApplicationFramework.php:1382
ApplicationFramework\GetCleanUrl
GetCleanUrl()
Get the clean URL for the current page if one is available.
Definition: ApplicationFramework.php:2349
ApplicationFramework\MaxExecutionTime
MaxExecutionTime($NewValue=NULL)
Get/set maximum PHP execution time.
Definition: ApplicationFramework.php:2085
ApplicationFramework\PreferHttpHost
static PreferHttpHost($NewValue=NULL)
Get/set whether to prefer $_SERVER["HTTP_HOST"] (if available) over $_SERVER["SERVER_NAME"] when dete...
Definition: ApplicationFramework.php:2493
ApplicationFramework\RequireUIFile
RequireUIFile($FileName)
Add file to list of required UI files.
Definition: ApplicationFramework.php:1104
ApplicationFramework\FullUrl
static FullUrl()
Get current full URL, before any clean URL remapping and with any query string (e.g.
Definition: ApplicationFramework.php:2478
ApplicationFramework
Top-level framework for web applications.
Definition: ApplicationFramework.php:14
ApplicationFramework\BaseUrl
static BaseUrl()
Get current base URL (the part before index.php) (e.g.
Definition: ApplicationFramework.php:2464
ApplicationFramework\GetOrphanedTaskCount
GetOrphanedTaskCount()
Retrieve current number of orphaned tasks.
Definition: ApplicationFramework.php:1967
Database
SQL database abstraction object with smart query caching.
Definition: Axis--Database.php:22
ApplicationFramework\LogSlowPageLoads
LogSlowPageLoads($NewValue=DB_NOVALUE)
Get/set whether logging of long page load times is enabled.
Definition: ApplicationFramework.php:1197
ApplicationFramework\SlowPageLoadThreshold
SlowPageLoadThreshold($NewValue=DB_NOVALUE)
Get/set how long a page load can take before it should be considered "slow" and may be logged...
Definition: ApplicationFramework.php:1209
ApplicationFramework\GetTaskQueueSize
GetTaskQueueSize($Priority=NULL)
Retrieve current number of tasks in queue.
Definition: ApplicationFramework.php:1875
DB_NOVALUE
const DB_NOVALUE
Definition: Axis--Database.php:1284
ApplicationFramework\RootUrlOverride
static RootUrlOverride($NewValue=self::NOVALUE)
Get/set root URL override.
Definition: ApplicationFramework.php:2446
ApplicationFramework\GetQueuedTaskCount
GetQueuedTaskCount($Callback=NULL, $Parameters=NULL, $Priority=NULL, $Description=NULL)
Get number of queued tasks that match supplied values.
Definition: ApplicationFramework.php:1906
ApplicationFramework\AutoloadObjects
static AutoloadObjects($ClassName)
Definition: ApplicationFramework.php:3085
ApplicationFramework\DeleteTask
DeleteTask($TaskId)
Remove task from task queues.
Definition: ApplicationFramework.php:2002
ApplicationFramework\LOGLVL_DEBUG
const LOGLVL_DEBUG
DEBUG error logging leve.
Definition: ApplicationFramework.php:1397
ApplicationFramework\EVENTTYPE_NAMED
const EVENTTYPE_NAMED
Named result event type.
Definition: ApplicationFramework.php:1451
ApplicationFramework\EVENTTYPE_FIRST
const EVENTTYPE_FIRST
First response event type.
Definition: ApplicationFramework.php:1443
ApplicationFramework\WasUrlRewritten
static WasUrlRewritten($ScriptName="index.php")
Determine if the URL was rewritten, i.e., the script is being accessed through a URL that isn't direc...
Definition: ApplicationFramework.php:2552
ApplicationFramework\EVENTTYPE_DEFAULT
const EVENTTYPE_DEFAULT
Default event type.
Definition: ApplicationFramework.php:1431
ApplicationFramework\GetPageUrl
GetPageUrl()
Get the full URL to the page.
Definition: ApplicationFramework.php:802
ApplicationFramework\IsStaticOnlyEvent
IsStaticOnlyEvent($EventName)
Report whether specified event only allows static callbacks.
Definition: ApplicationFramework.php:1672
ApplicationFramework\IsRegisteredEvent
IsRegisteredEvent($EventName)
Check if event has been registered (is available to be signaled).
Definition: ApplicationFramework.php:1489
ApplicationFramework\AddObjectDirectory
static AddObjectDirectory($Dir, $Prefix="", $ClassPattern=NULL, $ClassReplacement=NULL)
Add directory to be searched for object files when autoloading.
Definition: ApplicationFramework.php:152
ApplicationFramework\SignalEvent
SignalEvent($EventName, $Parameters=NULL)
Signal that an event has occured.
Definition: ApplicationFramework.php:1590
ApplicationFramework\BasePath
static BasePath()
Get current base path (usually the part after the host name).
Definition: ApplicationFramework.php:2506
ApplicationFramework\LOGLVL_TRACE
const LOGLVL_TRACE
TRACE error logging level.
Definition: ApplicationFramework.php:1392
ApplicationFramework\LOGLVL_WARNING
const LOGLVL_WARNING
WARNING error logging level.
Definition: ApplicationFramework.php:1408
ApplicationFramework\PRIORITY_MEDIUM
const PRIORITY_MEDIUM
Medium (default) priority.
Definition: ApplicationFramework.php:1768
ApplicationFramework\LogError
LogError($Level, $Msg)
Write error message to log.
Definition: ApplicationFramework.php:1255
ApplicationFramework\OnCrash
OnCrash()
Called automatically at program termination to ensure output is written out.
Definition: ApplicationFramework.php:3514
ApplicationFramework\GetKnownPeriodicEvents
GetKnownPeriodicEvents()
Get list of known periodic events.
Definition: ApplicationFramework.php:1722
ApplicationFramework\EVENTTYPE_CHAIN
const EVENTTYPE_CHAIN
Result chaining event type.
Definition: ApplicationFramework.php:1437
scssc
SCSS compiler written in PHP.
Definition: scssc.php:45
ApplicationFramework\GetSecondsBeforeTimeout
GetSecondsBeforeTimeout()
Get remaining available (PHP) execution time.
Definition: ApplicationFramework.php:1175
ApplicationFramework\TaskIsInQueue
TaskIsInQueue($Callback, $Parameters=NULL)
Check if task is already in queue or currently running.
Definition: ApplicationFramework.php:1852
ApplicationFramework\AddFunctionDirectories
AddFunctionDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for function ("F-") files.
Definition: ApplicationFramework.php:266
ApplicationFramework\LoggingLevel
LoggingLevel($NewValue=DB_NOVALUE)
Get/set logging level.
Definition: ApplicationFramework.php:1364
ApplicationFramework\ORDER_MIDDLE
const ORDER_MIDDLE
Run hooked function after ORDER_FIRST and before ORDER_LAST events.
Definition: ApplicationFramework.php:1456
PHP
PHP
Definition: OAIClient.php:39
ApplicationFramework\RegisterEvent
RegisterEvent($EventsOrEventName, $EventType=NULL)
Register one or more events that may be signaled.
Definition: ApplicationFramework.php:1468
ApplicationFramework\SetJumpToPage
SetJumpToPage($Page, $IsLiteral=FALSE)
Set URL of page to autoload after PHP page file is executed.
Definition: ApplicationFramework.php:815
ApplicationFramework\GetPageName
GetPageName()
Get name of page being loaded.
Definition: ApplicationFramework.php:772
ApplicationFramework\CleanUrlIsMapped
CleanUrlIsMapped($Path)
Report whether clean URL has already been mapped.
Definition: ApplicationFramework.php:2233
ApplicationFramework\PRIORITY_HIGH
const PRIORITY_HIGH
Highest priority.
Definition: ApplicationFramework.php:1766
ApplicationFramework\LoadFunction
LoadFunction($Callback)
Attempt to load code for function or method if not currently available.
Definition: ApplicationFramework.php:1117
ApplicationFramework\GetRunningTaskList
GetRunningTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:1940
ApplicationFramework\FindCommonTemplate
FindCommonTemplate($BaseName)
Preserved for backward compatibility for use with code written prior to October 2012.
Definition: ApplicationFramework.php:2616
ApplicationFramework\EventWillNextRunAt
EventWillNextRunAt($EventName, $Callback)
Get date/time a periodic event will next run.
Definition: ApplicationFramework.php:1687
ApplicationFramework\SessionLifetime
static SessionLifetime($NewValue=NULL)
Get/set session timeout in seconds.
Definition: ApplicationFramework.php:2376
ApplicationFramework\HookEvent
HookEvent($EventsOrEventName, $Callback=NULL, $Order=self::ORDER_MIDDLE)
Hook one or more functions to be called when the specified event is signaled.
Definition: ApplicationFramework.php:1526
ApplicationFramework\IsHookedEvent
IsHookedEvent($EventName)
Check if an event is registered and is hooked to.
Definition: ApplicationFramework.php:1501
ApplicationFramework\GetFreeMemory
static GetFreeMemory()
Get current amount of free memory.
Definition: ApplicationFramework.php:2581
ApplicationFramework\AddImageDirectories
AddImageDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for image files.
Definition: ApplicationFramework.php:187
ApplicationFramework\HtmlCharset
HtmlCharset($NewSetting=NULL)
Get/set HTTP character encoding value.
Definition: ApplicationFramework.php:853
ApplicationFramework\ORDER_FIRST
const ORDER_FIRST
Run hooked function first (i.e.
Definition: ApplicationFramework.php:1454
ApplicationFramework\GetUncleanUrlForPath
GetUncleanUrlForPath($Path)
Get the unclean URL for mapped for a path.
Definition: ApplicationFramework.php:2299
ApplicationFramework\TemplateLocationCacheExpirationInterval
TemplateLocationCacheExpirationInterval($NewInterval=DB_NOVALUE)
Get/set UI template location cache expiration period in minutes.
Definition: ApplicationFramework.php:303
ApplicationFramework\GetUncleanUrl
GetUncleanUrl()
Get the unclean URL for the current page.
Definition: ApplicationFramework.php:2358
ApplicationFramework\RecordContextInCaseOfCrash
RecordContextInCaseOfCrash($BacktraceOptions=0, $BacktraceLimit=0)
Record the current execution context in case of crash.
Definition: ApplicationFramework.php:331
ApplicationFramework\JumpToPageIsSet
JumpToPageIsSet()
Report whether a page to autoload has been set.
Definition: ApplicationFramework.php:839
ApplicationFramework\ORDER_LAST
const ORDER_LAST
Run hooked function last (i.e.
Definition: ApplicationFramework.php:1458
ApplicationFramework\UseBaseTag
UseBaseTag($NewValue=NULL)
Get/set whether or not to use the "base" tag to ensure relative URL paths are correct.
Definition: ApplicationFramework.php:881
ApplicationFramework\HtaccessSupport
static HtaccessSupport()
Determine if .htaccess files are enabled.
Definition: ApplicationFramework.php:2390
ApplicationFramework\UpdateSetting
UpdateSetting($FieldName, $NewValue=DB_NOVALUE)
Convenience function for getting/setting our settings.
Definition: ApplicationFramework.php:3673
ApplicationFramework\GetTask
GetTask($TaskId)
Retrieve task info from queue (either running or queued tasks).
Definition: ApplicationFramework.php:2015
ApplicationFramework\TaskExecutionEnabled
TaskExecutionEnabled($NewValue=DB_NOVALUE)
Get/set whether automatic task execution is enabled.
Definition: ApplicationFramework.php:2063
ApplicationFramework\GetPhpMemoryLimit
static GetPhpMemoryLimit()
Get PHP memory limit in bytes.
Definition: ApplicationFramework.php:2591
ApplicationFramework\LoadPage
LoadPage($PageName)
Load page PHP and HTML/TPL files.
Definition: ApplicationFramework.php:350
ApplicationFramework\AddEnvInclude
AddEnvInclude($FileName)
Add file to be included to set up environment.
Definition: ApplicationFramework.php:1006
ApplicationFramework\NOVALUE
const NOVALUE
Definition: ApplicationFramework.php:3713
ApplicationFramework\ReQueueOrphanedTask
ReQueueOrphanedTask($TaskId, $NewPriority=NULL)
Move orphaned task back into queue.
Definition: ApplicationFramework.php:1980
ApplicationFramework\GUIFile
GUIFile($FileName)
Search UI directories for specified image or CSS file and return name of correct file.
Definition: ApplicationFramework.php:1017
ApplicationFramework\QueueTask
QueueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue.
Definition: ApplicationFramework.php:1786
ApplicationFramework\GetUserInterfaces
GetUserInterfaces()
Get the list of available user interfaces.
Definition: ApplicationFramework.php:918
ApplicationFramework\PUIFile
PUIFile($FileName)
Search UI directories for specified image or CSS file and print name of correct file.
Definition: ApplicationFramework.php:1091
ApplicationFramework\LogHighMemoryUsage
LogHighMemoryUsage($NewValue=DB_NOVALUE)
Get/set whether logging of high memory usage is enabled.
Definition: ApplicationFramework.php:1224
ApplicationFramework\ActiveUserInterface
ActiveUserInterface($UIName=NULL)
Get/set name of current active user interface.
Definition: ApplicationFramework.php:904
ApplicationFramework\GetPageLocation
GetPageLocation()
Get the URL path to the page without the base path, if present.
Definition: ApplicationFramework.php:782
ApplicationFramework\ObjectLocationCacheExpirationInterval
ObjectLocationCacheExpirationInterval($NewInterval=DB_NOVALUE)
Get/set object file location cache expiration period in minutes.
Definition: ApplicationFramework.php:314
ApplicationFramework\GetElapsedExecutionTime
GetElapsedExecutionTime()
Get time elapsed since constructor was called.
Definition: ApplicationFramework.php:1166
ApplicationFramework\SetBrowserDetectionFunc
SetBrowserDetectionFunc($DetectionFunc)
Specify function to use to detect the web browser type.
Definition: ApplicationFramework.php:278
ApplicationFramework\RootUrl
static RootUrl()
Get portion of current URL through host name, with no trailing slash (e.g.
Definition: ApplicationFramework.php:2403
ApplicationFramework\AddCleanUrl
AddCleanUrl($Pattern, $Page, $GetVars=NULL, $Template=NULL)
Add clean URL mapping.
Definition: ApplicationFramework.php:2135
ApplicationFramework\HighMemoryUsageThreshold
HighMemoryUsageThreshold($NewValue=DB_NOVALUE)
Get/set what percentage of max memory (set via the memory_limit PHP configuration directive) a page l...
Definition: ApplicationFramework.php:1237
ApplicationFramework\PRIORITY_BACKGROUND
const PRIORITY_BACKGROUND
Lowest priority.
Definition: ApplicationFramework.php:1772
ApplicationFramework\LogMessage
LogMessage($Level, $Msg)
Write status message to log.
Definition: ApplicationFramework.php:1296
$Items
$Items
Definition: RSSClient--Test.php:26