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-2013 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 }
76 function __destruct()
77 {
78 # if template location cache is flagged to be saved
79 if ($this->SaveTemplateLocationCache)
80 {
81 # write template location cache out and update cache expiration
82 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
83 ." SET TemplateLocationCache = '"
84 .addslashes(serialize(
85 $this->Settings["TemplateLocationCache"]))."',"
86 ." TemplateLocationCacheExpiration = "
87 ." NOW() + INTERVAL "
88 .$this->Settings["TemplateLocationCacheInterval"]
89 ." MINUTE");
90 }
91
92 # if object location cache is flagged to be saved
93 if (self::$SaveObjectLocationCache)
94 {
95 # write object location cache out and update cache expiration
96 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
97 ." SET ObjectLocationCache = '"
98 .addslashes(serialize(
99 self::$ObjectLocationCache))."',"
100 ." ObjectLocationCacheExpiration = "
101 ." NOW() + INTERVAL "
102 .self::$ObjectLocationCacheInterval
103 ." MINUTE");
104 }
105 }
112 function GlobalExceptionHandler($Exception)
113 {
114 # display exception info
115 $Location = $Exception->getFile()."[".$Exception->getLine()."]";
116 ?><table width="100%" cellpadding="5"
117 style="border: 2px solid #666666; background: #CCCCCC;
118 font-family: Courier New, Courier, monospace;
119 margin-top: 10px;"><tr><td>
120 <div style="color: #666666;">
121 <span style="font-size: 150%;">
122 <b>Uncaught Exception</b></span><br />
123 <b>Message:</b> <i><?PHP print $Exception->getMessage(); ?></i><br />
124 <b>Location:</b> <i><?PHP print $Location; ?></i><br />
125 <b>Trace:</b>
126 <blockquote><pre><?PHP print $Exception->getTraceAsString();
127 ?></pre></blockquote>
128 </div>
129 </td></tr></table><?PHP
130
131 # log exception if possible
132 $LogMsg = "Uncaught exception (".$Exception->getMessage().").";
133 $this->LogError(self::LOGLVL_ERROR, $LogMsg);
134 }
148 static function AddObjectDirectory(
149 $Dir, $Prefix = "", $ClassPattern = NULL, $ClassReplacement = NULL)
150 {
151 # make sure directory has trailing slash
152 $Dir = $Dir.((substr($Dir, -1) != "/") ? "/" : "");
153
154 # add directory to directory list
155 self::$ObjectDirectories = array_merge(
156 array($Dir => array(
157 "Prefix" => $Prefix,
158 "ClassPattern" => $ClassPattern,
159 "ClassReplacement" => $ClassReplacement,
160 )),
161 self::$ObjectDirectories);
162 }
163
183 function AddImageDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
184 {
185 # add directories to existing image directory list
186 $this->ImageDirList = $this->AddToDirList(
187 $this->ImageDirList, $Dir, $SearchLast, $SkipSlashCheck);
188 }
189
210 function AddIncludeDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
211 {
212 # add directories to existing image directory list
213 $this->IncludeDirList = $this->AddToDirList(
214 $this->IncludeDirList, $Dir, $SearchLast, $SkipSlashCheck);
215 }
216
236 function AddInterfaceDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
237 {
238 # add directories to existing image directory list
239 $this->InterfaceDirList = $this->AddToDirList(
240 $this->InterfaceDirList, $Dir, $SearchLast, $SkipSlashCheck);
241 }
242
262 function AddFunctionDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
263 {
264 # add directories to existing image directory list
265 $this->FunctionDirList = $this->AddToDirList(
266 $this->FunctionDirList, $Dir, $SearchLast, $SkipSlashCheck);
267 }
268
274 function SetBrowserDetectionFunc($DetectionFunc)
275 {
276 $this->BrowserDetectFunc = $DetectionFunc;
277 }
278
285 function AddUnbufferedCallback($Callback, $Parameters=array())
286 {
287 if (is_callable($Callback))
288 {
289 $this->UnbufferedCallbacks[] = array($Callback, $Parameters);
290 }
291 }
292
299 function TemplateLocationCacheExpirationInterval($NewInterval = DB_NOVALUE)
300 {
301 return $this->UpdateSetting("TemplateLocationCacheInterval", $NewInterval);
302 }
303
310 function ObjectLocationCacheExpirationInterval($NewInterval = DB_NOVALUE)
311 {
312 return $this->UpdateSetting("ObjectLocationCacheInterval", $NewInterval);
313 }
314
327 function RecordContextInCaseOfCrash(
328 $BacktraceOptions = 0, $BacktraceLimit = 0)
329 {
330 if (version_compare(PHP_VERSION, "5.4.0", ">="))
331 {
332 $this->SavedContext = debug_backtrace(
333 $BacktraceOptions, $BacktraceLimit);
334 }
335 else
336 {
337 $this->SavedContext = debug_backtrace($BacktraceOptions);
338 }
339 array_shift($this->SavedContext);
340 }
341
346 function LoadPage($PageName)
347 {
348 # perform any clean URL rewriting
349 $PageName = $this->RewriteCleanUrls($PageName);
350
351 # sanitize incoming page name and save local copy
352 $PageName = preg_replace("/[^a-zA-Z0-9_.-]/", "", $PageName);
353 $this->PageName = $PageName;
354
355 # buffer any output from includes or PHP file
356 ob_start();
357
358 # include any files needed to set up execution environment
359 foreach ($this->EnvIncludes as $IncludeFile)
360 {
361 include($IncludeFile);
362 }
363
364 # signal page load
365 $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName));
366
367 # signal PHP file load
368 $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array(
369 "PageName" => $PageName));
370
371 # if signal handler returned new page name value
372 $NewPageName = $PageName;
373 if (($SignalResult["PageName"] != $PageName)
374 && strlen($SignalResult["PageName"]))
375 {
376 # if new page name value is page file
377 if (file_exists($SignalResult["PageName"]))
378 {
379 # use new value for PHP file name
380 $PageFile = $SignalResult["PageName"];
381 }
382 else
383 {
384 # use new value for page name
385 $NewPageName = $SignalResult["PageName"];
386 }
387
388 # update local copy of page name
389 $this->PageName = $NewPageName;
390 }
391
392 # if we do not already have a PHP file
393 if (!isset($PageFile))
394 {
395 # look for PHP file for page
396 $OurPageFile = "pages/".$NewPageName.".php";
397 $LocalPageFile = "local/pages/".$NewPageName.".php";
398 $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
399 : (file_exists($OurPageFile) ? $OurPageFile
400 : "pages/".$this->DefaultPage.".php");
401 }
402
403 # load PHP file
404 include($PageFile);
405
406 # save buffered output to be displayed later after HTML file loads
407 $PageOutput = ob_get_contents();
408 ob_end_clean();
409
410 # signal PHP file load is complete
411 ob_start();
412 $Context["Variables"] = get_defined_vars();
413 $this->SignalEvent("EVENT_PHP_FILE_LOAD_COMPLETE",
414 array("PageName" => $PageName, "Context" => $Context));
415 $PageCompleteOutput = ob_get_contents();
416 ob_end_clean();
417
418 # set up for possible TSR (Terminate and Stay Resident :))
419 $ShouldTSR = $this->PrepForTSR();
420
421 # if PHP file indicated we should autorefresh to somewhere else
422 if ($this->JumpToPage)
423 {
424 if (!strlen(trim($PageOutput)))
425 {
426 ?><html>
427 <head>
428 <meta http-equiv="refresh" content="0; URL=<?PHP
429 print($this->JumpToPage); ?>">
430 </head>
431 <body bgcolor="white">
432 </body>
433 </html><?PHP
434 }
435 }
436 # else if HTML loading is not suppressed
437 elseif (!$this->SuppressHTML)
438 {
439 # set content-type to get rid of diacritic errors
440 header("Content-Type: text/html; charset="
441 .$this->HtmlCharset, TRUE);
442
443 # load common HTML file (defines common functions) if available
444 $CommonHtmlFile = $this->FindFile($this->IncludeDirList,
445 "Common", array("tpl", "html"));
446 if ($CommonHtmlFile) { include($CommonHtmlFile); }
447
448 # load UI functions
449 $this->LoadUIFunctions();
450
451 # begin buffering content
452 ob_start();
453
454 # signal HTML file load
455 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array(
456 "PageName" => $PageName));
457
458 # if signal handler returned new page name value
459 $NewPageName = $PageName;
460 $PageContentFile = NULL;
461 if (($SignalResult["PageName"] != $PageName)
462 && strlen($SignalResult["PageName"]))
463 {
464 # if new page name value is HTML file
465 if (file_exists($SignalResult["PageName"]))
466 {
467 # use new value for HTML file name
468 $PageContentFile = $SignalResult["PageName"];
469 }
470 else
471 {
472 # use new value for page name
473 $NewPageName = $SignalResult["PageName"];
474 }
475 }
476
477 # load page content HTML file if available
478 if ($PageContentFile === NULL)
479 {
480 $PageContentFile = $this->FindFile(
481 $this->InterfaceDirList, $NewPageName,
482 array("tpl", "html"));
483 }
484 if ($PageContentFile)
485 {
486 include($PageContentFile);
487 }
488 else
489 {
490 print "<h2>ERROR: No HTML/TPL template found"
491 ." for this page.</h2>";
492 }
493
494 # signal HTML file load complete
495 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE");
496
497 # stop buffering and save output
498 $PageContentOutput = ob_get_contents();
499 ob_end_clean();
500
501 # load page start HTML file if available
502 ob_start();
503 $PageStartFile = $this->FindFile($this->IncludeDirList, "Start",
504 array("tpl", "html"), array("StdPage", "StandardPage"));
505 if ($PageStartFile) { include($PageStartFile); }
506 $PageStartOutput = ob_get_contents();
507 ob_end_clean();
508
509 # load page end HTML file if available
510 ob_start();
511 $PageEndFile = $this->FindFile($this->IncludeDirList, "End",
512 array("tpl", "html"), array("StdPage", "StandardPage"));
513 if ($PageEndFile) { include($PageEndFile); }
514 $PageEndOutput = ob_get_contents();
515 ob_end_clean();
516
517 # get list of any required files not loaded
518 $RequiredFiles = $this->GetRequiredFilesNotYetLoaded($PageContentFile);
519
520 # if a browser detection function has been made available
521 if (is_callable($this->BrowserDetectFunc))
522 {
523 # call function to get browser list
524 $Browsers = call_user_func($this->BrowserDetectFunc);
525
526 # for each required file
527 $NewRequiredFiles = array();
528 foreach ($RequiredFiles as $File)
529 {
530 # if file name includes browser keyword
531 if (preg_match("/%BROWSER%/", $File))
532 {
533 # for each browser
534 foreach ($Browsers as $Browser)
535 {
536 # substitute in browser name and add to new file list
537 $NewRequiredFiles[] = preg_replace(
538 "/%BROWSER%/", $Browser, $File);
539 }
540 }
541 else
542 {
543 # add to new file list
544 $NewRequiredFiles[] = $File;
545 }
546 }
547 $RequiredFiles = $NewRequiredFiles;
548 }
549
550 # for each required file
551 foreach ($RequiredFiles as $File)
552 {
553 # locate specific file to use
554 $FilePath = $this->GUIFile($File);
555
556 # if file was found
557 if ($FilePath)
558 {
559 # determine file type
560 $NamePieces = explode(".", $File);
561 $FileSuffix = strtolower(array_pop($NamePieces));
562
563 # add file to HTML output based on file type
564 $FilePath = htmlspecialchars($FilePath);
565 switch ($FileSuffix)
566 {
567 case "js":
568 $Tag = '<script type="text/javascript" src="'
569 .$FilePath.'"></script>';
570 $PageEndOutput = preg_replace(
571 "#</body>#i", $Tag."\n</body>", $PageEndOutput, 1);
572 break;
573
574 case "css":
575 $Tag = '<link rel="stylesheet" type="text/css"'
576 .' media="all" href="'.$FilePath.'">';
577 $PageStartOutput = preg_replace(
578 "#</head>#i", $Tag."\n</head>", $PageStartOutput, 1);
579 break;
580 }
581 }
582 }
583
584 # assemble full page
585 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
586
587 # perform any regular expression replacements in output
588 $FullPageOutput = preg_replace($this->OutputModificationPatterns,
589 $this->OutputModificationReplacements, $FullPageOutput);
590
591 # perform any callback replacements in output
592 foreach ($this->OutputModificationCallbacks as $Info)
593 {
594 $this->OutputModificationCallbackInfo = $Info;
595 $FullPageOutput = preg_replace_callback($Info["SearchPattern"],
596 array($this, "OutputModificationCallbackShell"),
597 $FullPageOutput);
598 }
599
600 # if relative paths may not work because we were invoked via clean URL
601 if ($this->CleanUrlRewritePerformed || self::WasUrlRewritten())
602 {
603 # if using the <base> tag is okay
604 $BaseUrl = $this->BaseUrl();
605 if ($this->UseBaseTag)
606 {
607 # add <base> tag to header
608 $PageStartOutput = preg_replace("%<head>%",
609 "<head><base href=\"".$BaseUrl."\" />",
610 $PageStartOutput);
611
612 # re-assemble full page with new header
613 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
614
615 # the absolute URL to the current page
616 $FullUrl = $BaseUrl . $this->GetPageLocation();
617
618 # make HREF attribute values with just a fragment ID
619 # absolute since they don't work with the <base> tag because
620 # they are relative to the current page/URL, not the site
621 # root
622 $FullPageOutput = preg_replace(
623 array("%href=\"(#[^:\" ]+)\"%i", "%href='(#[^:' ]+)'%i"),
624 array("href=\"".$FullUrl."$1\"", "href='".$FullUrl."$1'"),
625 $FullPageOutput);
626 }
627 else
628 {
629 # try to fix any relative paths throughout code
630 $FullPageOutput = preg_replace(array(
631 "%src=\"/?([^?*:;{}\\\\\" ]+)\.(js|css|gif|png|jpg)\"%i",
632 "%src='/?([^?*:;{}\\\\' ]+)\.(js|css|gif|png|jpg)'%i",
633 # don't rewrite HREF attributes that are just
634 # fragment IDs because they are relative to the
635 # current page/URL, not the site root
636 "%href=\"/?([^#][^:\" ]*)\"%i",
637 "%href='/?([^#][^:' ]*)'%i",
638 "%action=\"/?([^#][^:\" ]*)\"%i",
639 "%action='/?([^#][^:' ]*)'%i",
640 "%@import\s+url\(\"/?([^:\" ]+)\"\s*\)%i",
641 "%@import\s+url\('/?([^:\" ]+)'\s*\)%i",
642 "%@import\s+\"/?([^:\" ]+)\"\s*%i",
643 "%@import\s+'/?([^:\" ]+)'\s*%i",
644 ),
645 array(
646 "src=\"".$BaseUrl."$1.$2\"",
647 "src=\"".$BaseUrl."$1.$2\"",
648 "href=\"".$BaseUrl."$1\"",
649 "href=\"".$BaseUrl."$1\"",
650 "action=\"".$BaseUrl."$1\"",
651 "action=\"".$BaseUrl."$1\"",
652 "@import url(\"".$BaseUrl."$1\")",
653 "@import url('".$BaseUrl."$1')",
654 "@import \"".$BaseUrl."$1\"",
655 "@import '".$BaseUrl."$1'",
656 ),
657 $FullPageOutput);
658 }
659 }
660
661 # provide the opportunity to modify full page output
662 $SignalResult = $this->SignalEvent("EVENT_PAGE_OUTPUT_FILTER", array(
663 "PageOutput" => $FullPageOutput));
664 if (isset($SignalResult["PageOutput"])
665 && strlen($SignalResult["PageOutput"]))
666 {
667 $FullPageOutput = $SignalResult["PageOutput"];
668 }
669
670 # write out full page
671 print $FullPageOutput;
672 }
673
674 # run any post-processing routines
675 foreach ($this->PostProcessingFuncs as $Func)
676 {
677 call_user_func_array($Func["FunctionName"], $Func["Arguments"]);
678 }
679
680 # write out any output buffered from page code execution
681 if (strlen($PageOutput))
682 {
683 if (!$this->SuppressHTML)
684 {
685 ?><table width="100%" cellpadding="5"
686 style="border: 2px solid #666666; background: #CCCCCC;
687 font-family: Courier New, Courier, monospace;
688 margin-top: 10px;"><tr><td><?PHP
689 }
690 if ($this->JumpToPage)
691 {
692 ?><div style="color: #666666;"><span style="font-size: 150%;">
693 <b>Page Jump Aborted</b></span>
694 (because of error or other unexpected output)<br />
695 <b>Jump Target:</b>
696 <i><?PHP print($this->JumpToPage); ?></i></div><?PHP
697 }
698 print $PageOutput;
699 if (!$this->SuppressHTML)
700 {
701 ?></td></tr></table><?PHP
702 }
703 }
704
705 # write out any output buffered from the page code execution complete signal
706 if (!$this->JumpToPage && !$this->SuppressHTML && strlen($PageCompleteOutput))
707 {
708 print $PageCompleteOutput;
709 }
710
711 # execute callbacks that should not have their output buffered
712 foreach ($this->UnbufferedCallbacks as $Callback)
713 {
714 call_user_func_array($Callback[0], $Callback[1]);
715 }
716
717 # log high memory usage
718 if (function_exists("memory_get_peak_usage"))
719 {
720 $MemoryThreshold = ($this->HighMemoryUsageThreshold()
721 * $this->GetPhpMemoryLimit()) / 100;
722 if ($this->LogHighMemoryUsage()
723 && (memory_get_peak_usage() >= $MemoryThreshold))
724 {
725 $HighMemUsageMsg = "High peak memory usage ("
726 .intval(memory_get_peak_usage()).") for "
727 .$this->FullUrl()." from "
728 .$_SERVER["REMOTE_ADDR"];
729 $this->LogMessage(self::LOGLVL_INFO, $HighMemUsageMsg);
730 }
731 }
732
733 # log slow page loads
734 if ($this->LogSlowPageLoads()
735 && ($this->GetElapsedExecutionTime()
736 >= ($this->SlowPageLoadThreshold())))
737 {
738 $SlowPageLoadMsg = "Slow page load ("
739 .intval($this->GetElapsedExecutionTime())."s) for "
740 .$this->FullUrl()." from "
741 .$_SERVER["REMOTE_ADDR"];
742 $this->LogMessage(self::LOGLVL_INFO, $SlowPageLoadMsg);
743 }
744
745 # terminate and stay resident (TSR!) if indicated and HTML has been output
746 # (only TSR if HTML has been output because otherwise browsers will misbehave)
747 if ($ShouldTSR) { $this->LaunchTSR(); }
748 }
749
755 function GetPageName()
756 {
757 return $this->PageName;
758 }
759
765 function GetPageLocation()
766 {
767 # retrieve current URL
768 $Url = $this->GetScriptUrl();
769
770 # remove the base path if present
771 $BasePath = $this->Settings["BasePath"];
772 if (stripos($Url, $BasePath) === 0)
773 {
774 $Url = substr($Url, strlen($BasePath));
775 }
776
777 return $Url;
778 }
779
785 function GetPageUrl()
786 {
787 return self::BaseUrl() . $this->GetPageLocation();
788 }
789
798 function SetJumpToPage($Page, $IsLiteral = FALSE)
799 {
800 if (!is_null($Page)
801 && (!$IsLiteral)
802 && (strpos($Page, "?") === FALSE)
803 && ((strpos($Page, "=") !== FALSE)
804 || ((stripos($Page, ".php") === FALSE)
805 && (stripos($Page, ".htm") === FALSE)
806 && (strpos($Page, "/") === FALSE)))
807 && (stripos($Page, "http://") !== 0)
808 && (stripos($Page, "https://") !== 0))
809 {
810 $this->JumpToPage = self::BaseUrl() . "index.php?P=".$Page;
811 }
812 else
813 {
814 $this->JumpToPage = $Page;
815 }
816 }
817
822 function JumpToPageIsSet()
823 {
824 return ($this->JumpToPage === NULL) ? FALSE : TRUE;
825 }
826
836 function HtmlCharset($NewSetting = NULL)
837 {
838 if ($NewSetting !== NULL) { $this->HtmlCharset = $NewSetting; }
839 return $this->HtmlCharset;
840 }
841
848 public function UseMinimizedJavascript($NewSetting = NULL)
849 {
850 if ($NewSetting !== NULL) { $this->UseMinimizedJavascript = $NewSetting; }
851 return $this->UseMinimizedJavascript;
852 }
853
864 function UseBaseTag($NewValue = NULL)
865 {
866 if ($NewValue !== NULL) { $this->UseBaseTag = $NewValue ? TRUE : FALSE; }
867 return $this->UseBaseTag;
868 }
869
876 function SuppressHTMLOutput($NewSetting = TRUE)
877 {
878 $this->SuppressHTML = $NewSetting;
879 }
880
887 function ActiveUserInterface($UIName = NULL)
888 {
889 if ($UIName !== NULL)
890 {
891 $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
892 }
893 return $this->ActiveUI;
894 }
895
901 function GetUserInterfaces()
902 {
903 # possible UI directories
904 $InterfaceDirs = array(
905 "interface",
906 "local/interface");
907
908 # start out with an empty list
909 $Interfaces = array();
910
911 # for each possible UI directory
912 foreach ($InterfaceDirs as $InterfaceDir)
913 {
914 $Dir = dir($InterfaceDir);
915
916 # for each file in current directory
917 while (($DirEntry = $Dir->read()) !== FALSE)
918 {
919 $InterfacePath = $InterfaceDir."/".$DirEntry;
920
921 # skip anything that doesn't have a name in the required format
922 if (!preg_match('/^[a-zA-Z0-9]+$/', $DirEntry))
923 {
924 continue;
925 }
926
927 # skip anything that isn't a directory
928 if (!is_dir($InterfacePath))
929 {
930 continue;
931 }
932
933 # read the UI name (if available)
934 $UIName = @file_get_contents($InterfacePath."/NAME");
935
936 # use the directory name if the UI name isn't available
937 if ($UIName === FALSE || !strlen($UIName))
938 {
939 $UIName = $DirEntry;
940 }
941
942 $Interfaces[$InterfacePath] = $UIName;
943 }
944
945 $Dir->close();
946 }
947
948 # return list to caller
949 return $Interfaces;
950 }
951
967 function AddPostProcessingCall($FunctionName,
968 &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
969 &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
970 &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
971 {
972 $FuncIndex = count($this->PostProcessingFuncs);
973 $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
974 $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
975 $Index = 1;
976 while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
977 {
978 $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
979 =& ${"Arg".$Index};
980 $Index++;
981 }
982 }
983
989 function AddEnvInclude($FileName)
990 {
991 $this->EnvIncludes[] = $FileName;
992 }
993
1000 function GUIFile($FileName)
1001 {
1002 # determine if the file is an image or JavaScript file
1003 $FileIsImage = preg_match("/\.(gif|jpg|png)$/", $FileName);
1004 $FileIsJavascript = preg_match("/\.js$/", $FileName);
1005
1006 # determine which location to search based on file suffix
1007 $DirList = $FileIsImage ? $this->ImageDirList : $this->IncludeDirList;
1008
1009 # if directed to get a minimized JavaScript file
1010 if ($FileIsJavascript && $this->UseMinimizedJavascript)
1011 {
1012 # first try to find the minimized JavaScript file
1013 $MinimizedFileName = substr_replace($FileName, ".min", -3, 0);
1014 $FoundFileName = $this->FindFile($DirList, $MinimizedFileName);
1015
1016 # search for the regular file if a minimized file wasn't found
1017 if (is_null($FoundFileName))
1018 {
1019 $FoundFileName = $this->FindFile($DirList, $FileName);
1020 }
1021 }
1022
1023 # otherwise just search for the file
1024 else
1025 {
1026 $FoundFileName = $this->FindFile($DirList, $FileName);
1027 }
1028
1029 # add non-image files to list of found files (used for required files loading)
1030 if (!$FileIsImage) { $this->FoundUIFiles[] = basename($FoundFileName); }
1031
1032 # return file name to caller
1033 return $FoundFileName;
1034 }
1035
1045 function PUIFile($FileName)
1046 {
1047 $FullFileName = $this->GUIFile($FileName);
1048 if ($FullFileName) { print($FullFileName); }
1049 }
1050
1058 function RequireUIFile($FileName)
1059 {
1060 $this->AdditionalRequiredUIFiles[] = $FileName;
1061 }
1062
1071 function LoadFunction($Callback)
1072 {
1073 # if specified function is not currently available
1074 if (!is_callable($Callback))
1075 {
1076 # if function info looks legal
1077 if (is_string($Callback) && strlen($Callback))
1078 {
1079 # start with function directory list
1080 $Locations = $this->FunctionDirList;
1081
1082 # add object directories to list
1083 $Locations = array_merge(
1084 $Locations, array_keys(self::$ObjectDirectories));
1085
1086 # look for function file
1087 $FunctionFileName = $this->FindFile($Locations, "F-".$Callback,
1088 array("php", "html"));
1089
1090 # if function file was found
1091 if ($FunctionFileName)
1092 {
1093 # load function file
1094 include_once($FunctionFileName);
1095 }
1096 else
1097 {
1098 # log error indicating function load failed
1099 $this->LogError(self::LOGLVL_ERROR, "Unable to load function"
1100 ." for callback \"".$Callback."\".");
1101 }
1102 }
1103 else
1104 {
1105 # log error indicating specified function info was bad
1106 $this->LogError(self::LOGLVL_ERROR, "Unloadable callback value"
1107 ." (".$Callback.")"
1108 ." passed to AF::LoadFunction().");
1109 }
1110 }
1111
1112 # report to caller whether function load succeeded
1113 return is_callable($Callback);
1114 }
1115
1120 function GetElapsedExecutionTime()
1121 {
1122 return microtime(TRUE) - $this->ExecutionStartTime;
1123 }
1124
1129 function GetSecondsBeforeTimeout()
1130 {
1131 return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
1132 }
1133
1134 /*@)*/ /* Application Framework */
1135
1136
1137 # ---- Logging -----------------------------------------------------------
1138 /*@(*/
1140
1151 function LogSlowPageLoads($NewValue = DB_NOVALUE)
1152 {
1153 return $this->UpdateSetting("LogSlowPageLoads", $NewValue);
1154 }
1155
1163 function SlowPageLoadThreshold($NewValue = DB_NOVALUE)
1164 {
1165 return $this->UpdateSetting("SlowPageLoadThreshold", $NewValue);
1166 }
1167
1178 function LogHighMemoryUsage($NewValue = DB_NOVALUE)
1179 {
1180 return $this->UpdateSetting("LogHighMemoryUsage", $NewValue);
1181 }
1182
1191 function HighMemoryUsageThreshold($NewValue = DB_NOVALUE)
1192 {
1193 return $this->UpdateSetting("HighMemoryUsageThreshold", $NewValue);
1194 }
1195
1209 function LogError($Level, $Msg)
1210 {
1211 # if error level is at or below current logging level
1212 if ($this->Settings["LoggingLevel"] >= $Level)
1213 {
1214 # attempt to log error message
1215 $Result = $this->LogMessage($Level, $Msg);
1216
1217 # if logging attempt failed and level indicated significant error
1218 if (($Result === FALSE) && ($Level <= self::LOGLVL_ERROR))
1219 {
1220 # throw exception about inability to log error
1221 static $AlreadyThrewException = FALSE;
1222 if (!$AlreadyThrewException)
1223 {
1224 $AlreadyThrewException = TRUE;
1225 throw new Exception("Unable to log error (".$Level.": ".$Msg.").");
1226 }
1227 }
1228
1229 # report to caller whether message was logged
1230 return $Result;
1231 }
1232 else
1233 {
1234 # report to caller that message was not logged
1235 return FALSE;
1236 }
1237 }
1238
1250 function LogMessage($Level, $Msg)
1251 {
1252 # if message level is at or below current logging level
1253 if ($this->Settings["LoggingLevel"] >= $Level)
1254 {
1255 # attempt to open log file
1256 $FHndl = @fopen($this->LogFileName, "a");
1257
1258 # if log file could not be open
1259 if ($FHndl === FALSE)
1260 {
1261 # report to caller that message was not logged
1262 return FALSE;
1263 }
1264 else
1265 {
1266 # format log entry
1267 $ErrorAbbrevs = array(
1268 self::LOGLVL_FATAL => "FTL",
1269 self::LOGLVL_ERROR => "ERR",
1270 self::LOGLVL_WARNING => "WRN",
1271 self::LOGLVL_INFO => "INF",
1272 self::LOGLVL_DEBUG => "DBG",
1273 self::LOGLVL_TRACE => "TRC",
1274 );
1275 $LogEntry = date("Y-m-d H:i:s")
1276 ." ".($this->RunningInBackground ? "B" : "F")
1277 ." ".$ErrorAbbrevs[$Level]
1278 ." ".$Msg;
1279
1280 # write entry to log
1281 $Success = fwrite($FHndl, $LogEntry."\n");
1282
1283 # close log file
1284 fclose($FHndl);
1285
1286 # report to caller whether message was logged
1287 return ($Success === FALSE) ? FALSE : TRUE;
1288 }
1289 }
1290 else
1291 {
1292 # report to caller that message was not logged
1293 return FALSE;
1294 }
1295 }
1296
1318 function LoggingLevel($NewValue = DB_NOVALUE)
1319 {
1320 # constrain new level (if supplied) to within legal bounds
1321 if ($NewValue !== DB_NOVALUE)
1322 {
1323 $NewValue = max(min($NewValue, 6), 1);
1324 }
1325
1326 # set new logging level (if supplied) and return current level to caller
1327 return $this->UpdateSetting("LoggingLevel", $NewValue);
1328 }
1329
1336 function LogFile($NewValue = NULL)
1337 {
1338 if ($NewValue !== NULL) { $this->LogFileName = $NewValue; }
1339 return $this->LogFileName;
1340 }
1341
1346 const LOGLVL_TRACE = 6;
1351 const LOGLVL_DEBUG = 5;
1357 const LOGLVL_INFO = 4;
1362 const LOGLVL_WARNING = 3;
1368 const LOGLVL_ERROR = 2;
1373 const LOGLVL_FATAL = 1;
1374
1375 /*@)*/ /* Logging */
1376
1377
1378 # ---- Event Handling ----------------------------------------------------
1379 /*@(*/
1381
1385 const EVENTTYPE_DEFAULT = 1;
1391 const EVENTTYPE_CHAIN = 2;
1397 const EVENTTYPE_FIRST = 3;
1405 const EVENTTYPE_NAMED = 4;
1406
1408 const ORDER_FIRST = 1;
1410 const ORDER_MIDDLE = 2;
1412 const ORDER_LAST = 3;
1413
1422 function RegisterEvent($EventsOrEventName, $EventType = NULL)
1423 {
1424 # convert parameters to array if not already in that form
1425 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1426 : array($EventsOrEventName => $EventType);
1427
1428 # for each event
1429 foreach ($Events as $Name => $Type)
1430 {
1431 # store event information
1432 $this->RegisteredEvents[$Name]["Type"] = $Type;
1433 $this->RegisteredEvents[$Name]["Hooks"] = array();
1434 }
1435 }
1436
1443 function IsRegisteredEvent($EventName)
1444 {
1445 return array_key_exists($EventName, $this->RegisteredEvents)
1446 ? TRUE : FALSE;
1447 }
1448
1455 function IsHookedEvent($EventName)
1456 {
1457 # the event isn't hooked to if it isn't even registered
1458 if (!$this->IsRegisteredEvent($EventName))
1459 {
1460 return FALSE;
1461 }
1462
1463 # return TRUE if there is at least one callback hooked to the event
1464 return count($this->RegisteredEvents[$EventName]["Hooks"]) > 0;
1465 }
1466
1480 function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
1481 {
1482 # convert parameters to array if not already in that form
1483 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1484 : array($EventsOrEventName => $Callback);
1485
1486 # for each event
1487 $Success = TRUE;
1488 foreach ($Events as $EventName => $EventCallback)
1489 {
1490 # if callback is valid
1491 if (is_callable($EventCallback))
1492 {
1493 # if this is a periodic event we process internally
1494 if (isset($this->PeriodicEvents[$EventName]))
1495 {
1496 # process event now
1497 $this->ProcessPeriodicEvent($EventName, $EventCallback);
1498 }
1499 # if specified event has been registered
1500 elseif (isset($this->RegisteredEvents[$EventName]))
1501 {
1502 # add callback for event
1503 $this->RegisteredEvents[$EventName]["Hooks"][]
1504 = array("Callback" => $EventCallback, "Order" => $Order);
1505
1506 # sort callbacks by order
1507 if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
1508 {
1509 usort($this->RegisteredEvents[$EventName]["Hooks"],
1510 array("ApplicationFramework", "HookEvent_OrderCompare"));
1511 }
1512 }
1513 else
1514 {
1515 $Success = FALSE;
1516 }
1517 }
1518 else
1519 {
1520 $Success = FALSE;
1521 }
1522 }
1523
1524 # report to caller whether all callbacks were hooked
1525 return $Success;
1526 }
1528 private static function HookEvent_OrderCompare($A, $B)
1529 {
1530 if ($A["Order"] == $B["Order"]) { return 0; }
1531 return ($A["Order"] < $B["Order"]) ? -1 : 1;
1532 }
1533
1544 function SignalEvent($EventName, $Parameters = NULL)
1545 {
1546 $ReturnValue = NULL;
1547
1548 # if event has been registered
1549 if (isset($this->RegisteredEvents[$EventName]))
1550 {
1551 # set up default return value (if not NULL)
1552 switch ($this->RegisteredEvents[$EventName]["Type"])
1553 {
1554 case self::EVENTTYPE_CHAIN:
1555 $ReturnValue = $Parameters;
1556 break;
1557
1558 case self::EVENTTYPE_NAMED:
1559 $ReturnValue = array();
1560 break;
1561 }
1562
1563 # for each callback for this event
1564 foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
1565 {
1566 # invoke callback
1567 $Callback = $Hook["Callback"];
1568 $Result = ($Parameters !== NULL)
1569 ? call_user_func_array($Callback, $Parameters)
1570 : call_user_func($Callback);
1571
1572 # process return value based on event type
1573 switch ($this->RegisteredEvents[$EventName]["Type"])
1574 {
1575 case self::EVENTTYPE_CHAIN:
1576 if ($Result !== NULL)
1577 {
1578 foreach ($Parameters as $Index => $Value)
1579 {
1580 if (array_key_exists($Index, $Result))
1581 {
1582 $Parameters[$Index] = $Result[$Index];
1583 }
1584 }
1585 $ReturnValue = $Parameters;
1586 }
1587 break;
1588
1589 case self::EVENTTYPE_FIRST:
1590 if ($Result !== NULL)
1591 {
1592 $ReturnValue = $Result;
1593 break 2;
1594 }
1595 break;
1596
1597 case self::EVENTTYPE_NAMED:
1598 $CallbackName = is_array($Callback)
1599 ? (is_object($Callback[0])
1600 ? get_class($Callback[0])
1601 : $Callback[0])."::".$Callback[1]
1602 : $Callback;
1603 $ReturnValue[$CallbackName] = $Result;
1604 break;
1605
1606 default:
1607 break;
1608 }
1609 }
1610 }
1611 else
1612 {
1613 $this->LogError(self::LOGLVL_WARNING,
1614 "Unregistered event signaled (".$EventName.").");
1615 }
1616
1617 # return value if any to caller
1618 return $ReturnValue;
1619 }
1620
1626 function IsStaticOnlyEvent($EventName)
1627 {
1628 return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
1629 }
1630
1641 function EventWillNextRunAt($EventName, $Callback)
1642 {
1643 # if event is not a periodic event report failure to caller
1644 if (!array_key_exists($EventName, $this->EventPeriods)) { return FALSE; }
1645
1646 # retrieve last execution time for event if available
1647 $Signature = self::GetCallbackSignature($Callback);
1648 $LastRunTime = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
1649 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
1650
1651 # if event was not found report failure to caller
1652 if ($LastRunTime === NULL) { return FALSE; }
1653
1654 # calculate next run time based on event period
1655 $NextRunTime = strtotime($LastRunTime) + $this->EventPeriods[$EventName];
1656
1657 # report next run time to caller
1658 return $NextRunTime;
1659 }
1660
1676 function GetKnownPeriodicEvents()
1677 {
1678 # retrieve last execution times
1679 $this->DB->Query("SELECT * FROM PeriodicEvents");
1680 $LastRunTimes = $this->DB->FetchColumn("LastRunAt", "Signature");
1681
1682 # for each known event
1683 $Events = array();
1684 foreach ($this->KnownPeriodicEvents as $Signature => $Info)
1685 {
1686 # if last run time for event is available
1687 if (array_key_exists($Signature, $LastRunTimes))
1688 {
1689 # calculate next run time for event
1690 $LastRun = strtotime($LastRunTimes[$Signature]);
1691 $NextRun = $LastRun + $this->EventPeriods[$Info["Period"]];
1692 if ($Info["Period"] == "EVENT_PERIODIC") { $LastRun = FALSE; }
1693 }
1694 else
1695 {
1696 # set info to indicate run times are not known
1697 $LastRun = FALSE;
1698 $NextRun = FALSE;
1699 }
1700
1701 # add event info to list
1702 $Events[$Signature] = $Info;
1703 $Events[$Signature]["LastRun"] = $LastRun;
1704 $Events[$Signature]["NextRun"] = $NextRun;
1705 $Events[$Signature]["Parameters"] = NULL;
1706 }
1707
1708 # return list of known events to caller
1709 return $Events;
1710 }
1711
1712 /*@)*/ /* Event Handling */
1713
1714
1715 # ---- Task Management ---------------------------------------------------
1716 /*@(*/
1718
1720 const PRIORITY_HIGH = 1;
1722 const PRIORITY_MEDIUM = 2;
1724 const PRIORITY_LOW = 3;
1726 const PRIORITY_BACKGROUND = 4;
1727
1740 function QueueTask($Callback, $Parameters = NULL,
1741 $Priority = self::PRIORITY_LOW, $Description = "")
1742 {
1743 # pack task info and write to database
1744 if ($Parameters === NULL) { $Parameters = array(); }
1745 $this->DB->Query("INSERT INTO TaskQueue"
1746 ." (Callback, Parameters, Priority, Description)"
1747 ." VALUES ('".addslashes(serialize($Callback))."', '"
1748 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
1749 .addslashes($Description)."')");
1750 }
1751
1769 function QueueUniqueTask($Callback, $Parameters = NULL,
1770 $Priority = self::PRIORITY_LOW, $Description = "")
1771 {
1772 if ($this->TaskIsInQueue($Callback, $Parameters))
1773 {
1774 $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
1775 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
1776 .($Parameters ? " AND Parameters = '"
1777 .addslashes(serialize($Parameters))."'" : ""));
1778 if ($QueryResult !== FALSE)
1779 {
1780 $Record = $this->DB->FetchRow();
1781 if ($Record["Priority"] > $Priority)
1782 {
1783 $this->DB->Query("UPDATE TaskQueue"
1784 ." SET Priority = ".intval($Priority)
1785 ." WHERE TaskId = ".intval($Record["TaskId"]));
1786 }
1787 }
1788 return FALSE;
1789 }
1790 else
1791 {
1792 $this->QueueTask($Callback, $Parameters, $Priority, $Description);
1793 return TRUE;
1794 }
1795 }
1796
1806 function TaskIsInQueue($Callback, $Parameters = NULL)
1807 {
1808 $QueuedCount = $this->DB->Query(
1809 "SELECT COUNT(*) AS FoundCount FROM TaskQueue"
1810 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
1811 .($Parameters ? " AND Parameters = '"
1812 .addslashes(serialize($Parameters))."'" : ""),
1813 "FoundCount");
1814 $RunningCount = $this->DB->Query(
1815 "SELECT COUNT(*) AS FoundCount FROM RunningTasks"
1816 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
1817 .($Parameters ? " AND Parameters = '"
1818 .addslashes(serialize($Parameters))."'" : ""),
1819 "FoundCount");
1820 $FoundCount = $QueuedCount + $RunningCount;
1821 return ($FoundCount ? TRUE : FALSE);
1822 }
1823
1829 function GetTaskQueueSize($Priority = NULL)
1830 {
1831 return $this->GetQueuedTaskCount(NULL, NULL, $Priority);
1832 }
1833
1841 function GetQueuedTaskList($Count = 100, $Offset = 0)
1842 {
1843 return $this->GetTaskList("SELECT * FROM TaskQueue"
1844 ." ORDER BY Priority, TaskId ", $Count, $Offset);
1845 }
1846
1860 function GetQueuedTaskCount($Callback = NULL,
1861 $Parameters = NULL, $Priority = NULL, $Description = NULL)
1862 {
1863 $Query = "SELECT COUNT(*) AS TaskCount FROM TaskQueue";
1864 $Sep = " WHERE";
1865 if ($Callback !== NULL)
1866 {
1867 $Query .= $Sep." Callback = '".addslashes(serialize($Callback))."'";
1868 $Sep = " AND";
1869 }
1870 if ($Parameters !== NULL)
1871 {
1872 $Query .= $Sep." Parameters = '".addslashes(serialize($Parameters))."'";
1873 $Sep = " AND";
1874 }
1875 if ($Priority !== NULL)
1876 {
1877 $Query .= $Sep." Priority = ".intval($Priority);
1878 $Sep = " AND";
1879 }
1880 if ($Description !== NULL)
1881 {
1882 $Query .= $Sep." Description = '".addslashes($Description)."'";
1883 }
1884 return $this->DB->Query($Query, "TaskCount");
1885 }
1886
1894 function GetRunningTaskList($Count = 100, $Offset = 0)
1895 {
1896 return $this->GetTaskList("SELECT * FROM RunningTasks"
1897 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
1898 (time() - ini_get("max_execution_time")))."'"
1899 ." ORDER BY StartedAt", $Count, $Offset);
1900 }
1901
1909 function GetOrphanedTaskList($Count = 100, $Offset = 0)
1910 {
1911 return $this->GetTaskList("SELECT * FROM RunningTasks"
1912 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
1913 (time() - ini_get("max_execution_time")))."'"
1914 ." ORDER BY StartedAt", $Count, $Offset);
1915 }
1916
1921 function GetOrphanedTaskCount()
1922 {
1923 return $this->DB->Query("SELECT COUNT(*) AS Count FROM RunningTasks"
1924 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
1925 (time() - ini_get("max_execution_time")))."'",
1926 "Count");
1927 }
1928
1934 function ReQueueOrphanedTask($TaskId, $NewPriority = NULL)
1935 {
1936 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
1937 $this->DB->Query("INSERT INTO TaskQueue"
1938 ." (Callback,Parameters,Priority,Description) "
1939 ."SELECT Callback, Parameters, Priority, Description"
1940 ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
1941 if ($NewPriority !== NULL)
1942 {
1943 $NewTaskId = $this->DB->LastInsertId();
1944 $this->DB->Query("UPDATE TaskQueue SET Priority = "
1945 .intval($NewPriority)
1946 ." WHERE TaskId = ".intval($NewTaskId));
1947 }
1948 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
1949 $this->DB->Query("UNLOCK TABLES");
1950 }
1951
1956 function DeleteTask($TaskId)
1957 {
1958 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
1959 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
1960 }
1961
1969 function GetTask($TaskId)
1970 {
1971 # assume task will not be found
1972 $Task = NULL;
1973
1974 # look for task in task queue
1975 $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
1976
1977 # if task was not found in queue
1978 if (!$this->DB->NumRowsSelected())
1979 {
1980 # look for task in running task list
1981 $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = "
1982 .intval($TaskId));
1983 }
1984
1985 # if task was found
1986 if ($this->DB->NumRowsSelected())
1987 {
1988 # if task was periodic
1989 $Row = $this->DB->FetchRow();
1990 if ($Row["Callback"] ==
1991 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
1992 {
1993 # unpack periodic task callback
1994 $WrappedCallback = unserialize($Row["Parameters"]);
1995 $Task["Callback"] = $WrappedCallback[1];
1996 $Task["Parameters"] = $WrappedCallback[2];
1997 }
1998 else
1999 {
2000 # unpack task callback and parameters
2001 $Task["Callback"] = unserialize($Row["Callback"]);
2002 $Task["Parameters"] = unserialize($Row["Parameters"]);
2003 }
2004 }
2005
2006 # return task to caller
2007 return $Task;
2008 }
2009
2017 function TaskExecutionEnabled($NewValue = DB_NOVALUE)
2018 {
2019 return $this->UpdateSetting("TaskExecutionEnabled", $NewValue);
2020 }
2021
2027 function MaxTasks($NewValue = DB_NOVALUE)
2028 {
2029 return $this->UpdateSetting("MaxTasksRunning", $NewValue);
2030 }
2031
2039 function MaxExecutionTime($NewValue = NULL)
2040 {
2041 if (func_num_args() && !ini_get("safe_mode"))
2042 {
2043 if ($NewValue != $this->Settings["MaxExecTime"])
2044 {
2045 $this->Settings["MaxExecTime"] = max($NewValue, 5);
2046 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2047 ." SET MaxExecTime = '"
2048 .intval($this->Settings["MaxExecTime"])."'");
2049 }
2050 ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
2051 set_time_limit($this->Settings["MaxExecTime"]);
2052 }
2053 return ini_get("max_execution_time");
2054 }
2055
2056 /*@)*/ /* Task Management */
2057
2058
2059 # ---- Clean URL Support -------------------------------------------------
2060 /*@(*/
2062
2089 function AddCleanUrl($Pattern, $Page, $GetVars = NULL, $Template = NULL)
2090 {
2091 # save clean URL mapping parameters
2092 $this->CleanUrlMappings[] = array(
2093 "Pattern" => $Pattern,
2094 "Page" => $Page,
2095 "GetVars" => $GetVars,
2096 );
2097
2098 # if replacement template specified
2099 if ($Template !== NULL)
2100 {
2101 # if GET parameters specified
2102 if (count($GetVars))
2103 {
2104 # retrieve all possible permutations of GET parameters
2105 $GetPerms = $this->ArrayPermutations(array_keys($GetVars));
2106
2107 # for each permutation of GET parameters
2108 foreach ($GetPerms as $VarPermutation)
2109 {
2110 # construct search pattern for permutation
2111 $SearchPattern = "/href=([\"'])index\\.php\\?P=".$Page;
2112 $GetVarSegment = "";
2113 foreach ($VarPermutation as $GetVar)
2114 {
2115 if (preg_match("%\\\$[0-9]+%", $GetVars[$GetVar]))
2116 {
2117 $GetVarSegment .= "&amp;".$GetVar."=((?:(?!\\1)[^&])+)";
2118 }
2119 else
2120 {
2121 $GetVarSegment .= "&amp;".$GetVar."=".$GetVars[$GetVar];
2122 }
2123 }
2124 $SearchPattern .= $GetVarSegment."\\1/i";
2125
2126 # if template is actually a callback
2127 if (is_callable($Template))
2128 {
2129 # add pattern to HTML output mod callbacks list
2130 $this->OutputModificationCallbacks[] = array(
2131 "Pattern" => $Pattern,
2132 "Page" => $Page,
2133 "SearchPattern" => $SearchPattern,
2134 "Callback" => $Template,
2135 );
2136 }
2137 else
2138 {
2139 # construct replacement string for permutation
2140 $Replacement = $Template;
2141 $Index = 2;
2142 foreach ($VarPermutation as $GetVar)
2143 {
2144 $Replacement = str_replace(
2145 "\$".$GetVar, "\$".$Index, $Replacement);
2146 $Index++;
2147 }
2148 $Replacement = "href=\"".$Replacement."\"";
2149
2150 # add pattern to HTML output modifications list
2151 $this->OutputModificationPatterns[] = $SearchPattern;
2152 $this->OutputModificationReplacements[] = $Replacement;
2153 }
2154 }
2155 }
2156 else
2157 {
2158 # construct search pattern
2159 $SearchPattern = "/href=\"index\\.php\\?P=".$Page."\"/i";
2160
2161 # if template is actually a callback
2162 if (is_callable($Template))
2163 {
2164 # add pattern to HTML output mod callbacks list
2165 $this->OutputModificationCallbacks[] = array(
2166 "Pattern" => $Pattern,
2167 "Page" => $Page,
2168 "SearchPattern" => $SearchPattern,
2169 "Callback" => $Template,
2170 );
2171 }
2172 else
2173 {
2174 # add simple pattern to HTML output modifications list
2175 $this->OutputModificationPatterns[] = $SearchPattern;
2176 $this->OutputModificationReplacements[] = "href=\"".$Template."\"";
2177 }
2178 }
2179 }
2180 }
2181
2187 function CleanUrlIsMapped($Path)
2188 {
2189 foreach ($this->CleanUrlMappings as $Info)
2190 {
2191 if (preg_match($Info["Pattern"], $Path))
2192 {
2193 return TRUE;
2194 }
2195 }
2196 return FALSE;
2197 }
2198
2205 function GetCleanUrlForPath($Path)
2206 {
2207 # the search patterns and callbacks require a specific format
2208 $Format = "href=\"".str_replace("&", "&amp;", $Path)."\"";
2209 $Search = $Format;
2210
2211 # perform any regular expression replacements on the search string
2212 $Search = preg_replace(
2213 $this->OutputModificationPatterns,
2214 $this->OutputModificationReplacements,
2215 $Search);
2216
2217 # only run the callbacks if a replacement hasn't already been performed
2218 if ($Search == $Format)
2219 {
2220 # perform any callback replacements on the search string
2221 foreach ($this->OutputModificationCallbacks as $Info)
2222 {
2223 # make the information available to the callback
2224 $this->OutputModificationCallbackInfo = $Info;
2225
2226 # execute the callback
2227 $Search = preg_replace_callback(
2228 $Info["SearchPattern"],
2229 array($this, "OutputModificationCallbackShell"),
2230 $Search);
2231 }
2232 }
2233
2234 # return the path untouched if no replacements were performed
2235 if ($Search == $Format)
2236 {
2237 return $Path;
2238 }
2239
2240 # remove the bits added to the search string to get it recognized by
2241 # the replacement expressions and callbacks
2242 $Result = substr($Search, 6, -1);
2243
2244 return $Result;
2245 }
2246
2253 public function GetUncleanUrlForPath($Path)
2254 {
2255 # for each clean URL mapping
2256 foreach ($this->CleanUrlMappings as $Info)
2257 {
2258 # if current path matches the clean URL pattern
2259 if (preg_match($Info["Pattern"], $Path, $Matches))
2260 {
2261 # the GET parameters for the URL, starting with the page name
2262 $GetVars = array("P" => $Info["Page"]);
2263
2264 # if additional $_GET variables specified for clean URL
2265 if ($Info["GetVars"] !== NULL)
2266 {
2267 # for each $_GET variable specified for clean URL
2268 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
2269 {
2270 # start with template for variable value
2271 $Value = $VarTemplate;
2272
2273 # for each subpattern matched in current URL
2274 foreach ($Matches as $Index => $Match)
2275 {
2276 # if not first (whole) match
2277 if ($Index > 0)
2278 {
2279 # make any substitutions in template
2280 $Value = str_replace("$".$Index, $Match, $Value);
2281 }
2282 }
2283
2284 # add the GET variable
2285 $GetVars[$VarName] = $Value;
2286 }
2287 }
2288
2289 # return the unclean URL
2290 return "index.php?" . http_build_query($GetVars);
2291 }
2292 }
2293
2294 # return the path unchanged
2295 return $Path;
2296 }
2297
2303 function GetCleanUrl()
2304 {
2305 return $this->GetCleanUrlForPath($this->GetUncleanUrl());
2306 }
2307
2312 function GetUncleanUrl()
2313 {
2314 $GetVars = array("P" => $this->GetPageName()) + $_GET;
2315 return "index.php?" . http_build_query($GetVars);
2316 }
2317
2318 /*@)*/ /* Clean URL Support */
2319
2320
2321 # ---- Server Environment ------------------------------------------------
2322 /*@(*/
2324
2330 static function SessionLifetime($NewValue = NULL)
2331 {
2332 if ($NewValue !== NULL)
2333 {
2334 self::$SessionLifetime = $NewValue;
2335 }
2336 return self::$SessionLifetime;
2337 }
2338
2344 static function HtaccessSupport()
2345 {
2346 # HTACCESS_SUPPORT is set in the .htaccess file
2347 return isset($_SERVER["HTACCESS_SUPPORT"]);
2348 }
2349
2357 static function RootUrl()
2358 {
2359 # return override value if one is set
2360 if (self::$RootUrlOverride !== NULL)
2361 {
2362 return self::$RootUrlOverride;
2363 }
2364
2365 # determine scheme name
2366 $Protocol = (isset($_SERVER["HTTPS"]) ? "https" : "http");
2367
2368 # if HTTP_HOST is preferred or SERVER_NAME points to localhost
2369 # and HTTP_HOST is set
2370 if ((self::$PreferHttpHost || ($_SERVER["SERVER_NAME"] == "127.0.0.1"))
2371 && isset($_SERVER["HTTP_HOST"]))
2372 {
2373 # use HTTP_HOST for domain name
2374 $DomainName = $_SERVER["HTTP_HOST"];
2375 }
2376 else
2377 {
2378 # use SERVER_NAME for domain name
2379 $DomainName = $_SERVER["HTTP_HOST"];
2380 }
2381
2382 # build URL root and return to caller
2383 return $Protocol."://".$DomainName;
2384 }
2385
2400 static function RootUrlOverride($NewValue = self::NOVALUE)
2401 {
2402 if ($NewValue !== self::NOVALUE)
2403 {
2404 self::$RootUrlOverride = strlen(trim($NewValue)) ? $NewValue : NULL;
2405 }
2406 return self::$RootUrlOverride;
2407 }
2408
2418 static function BaseUrl()
2419 {
2420 $BaseUrl = self::RootUrl().dirname($_SERVER["SCRIPT_NAME"]);
2421 if (substr($BaseUrl, -1) != "/") { $BaseUrl .= "/"; }
2422 return $BaseUrl;
2423 }
2424
2432 static function FullUrl()
2433 {
2434 return self::RootUrl().$_SERVER["REQUEST_URI"];
2435 }
2436
2447 static function PreferHttpHost($NewValue = NULL)
2448 {
2449 if ($NewValue !== NULL)
2450 {
2451 self::$PreferHttpHost = ($NewValue ? TRUE : FALSE);
2452 }
2453 return self::$PreferHttpHost;
2454 }
2455
2460 static function BasePath()
2461 {
2462 $BasePath = dirname($_SERVER["SCRIPT_NAME"]);
2463
2464 if (substr($BasePath, -1) != "/")
2465 {
2466 $BasePath .= "/";
2467 }
2468
2469 return $BasePath;
2470 }
2471
2477 static function GetScriptUrl()
2478 {
2479 if (array_key_exists("SCRIPT_URL", $_SERVER))
2480 {
2481 return $_SERVER["SCRIPT_URL"];
2482 }
2483 elseif (array_key_exists("REDIRECT_URL", $_SERVER))
2484 {
2485 return $_SERVER["REDIRECT_URL"];
2486 }
2487 elseif (array_key_exists("REQUEST_URI", $_SERVER))
2488 {
2489 $Pieces = parse_url($_SERVER["REQUEST_URI"]);
2490 return $Pieces["path"];
2491 }
2492 else
2493 {
2494 return NULL;
2495 }
2496 }
2497
2506 static function WasUrlRewritten($ScriptName="index.php")
2507 {
2508 # needed to get the path of the URL minus the query and fragment pieces
2509 $Components = parse_url(self::GetScriptUrl());
2510
2511 # if parsing was successful and a path is set
2512 if (is_array($Components) && isset($Components["path"]))
2513 {
2514 $BasePath = self::BasePath();
2515 $Path = $Components["path"];
2516
2517 # the URL was rewritten if the path isn't the base path, i.e., the
2518 # home page, and the file in the URL isn't the script generating the
2519 # page
2520 if ($BasePath != $Path && basename($Path) != $ScriptName)
2521 {
2522 return TRUE;
2523 }
2524 }
2525
2526 # the URL wasn't rewritten
2527 return FALSE;
2528 }
2529
2535 static function GetFreeMemory()
2536 {
2537 return self::GetPhpMemoryLimit() - memory_get_usage();
2538 }
2539
2545 static function GetPhpMemoryLimit()
2546 {
2547 $Str = strtoupper(ini_get("memory_limit"));
2548 if (substr($Str, -1) == "B") { $Str = substr($Str, 0, strlen($Str) - 1); }
2549 switch (substr($Str, -1))
2550 {
2551 case "K": $MemoryLimit = (int)$Str * 1024; break;
2552 case "M": $MemoryLimit = (int)$Str * 1048576; break;
2553 case "G": $MemoryLimit = (int)$Str * 1073741824; break;
2554 default: $MemoryLimit = (int)$Str; break;
2555 }
2556 return $MemoryLimit;
2557 }
2558
2559 /*@)*/ /* Server Environment */
2560
2561
2562 # ---- Backward Compatibility --------------------------------------------
2563 /*@(*/
2565
2570 function FindCommonTemplate($BaseName)
2571 {
2572 return $this->FindFile(
2573 $this->IncludeDirList, $BaseName, array("tpl", "html"));
2574 }
2575
2576 /*@)*/ /* Backward Compatibility */
2577
2578
2579 # ---- PRIVATE INTERFACE -------------------------------------------------
2580
2581 private $ActiveUI = "default";
2582 private $BrowserDetectFunc;
2583 private $CleanUrlMappings = array();
2584 private $CleanUrlRewritePerformed = FALSE;
2585 private $DB;
2586 private $DefaultPage = "Home";
2587 private $EnvIncludes = array();
2588 private $ExecutionStartTime;
2589 private $FoundUIFiles = array();
2590 private $AdditionalRequiredUIFiles = array();
2591 private $HtmlCharset = "UTF-8";
2592 private $JumpToPage = NULL;
2593 private $LogFileName = "local/logs/site.log";
2594 private $MaxRunningTasksToTrack = 250;
2595 private $OutputModificationPatterns = array();
2596 private $OutputModificationReplacements = array();
2597 private $OutputModificationCallbacks = array();
2598 private $OutputModificationCallbackInfo;
2599 private $PageName;
2600 private $PostProcessingFuncs = array();
2601 private $RunningInBackground = FALSE;
2602 private $RunningTask;
2603 private $SavedContext;
2604 private $Settings;
2605 private $SuppressHTML = FALSE;
2606 private $SaveTemplateLocationCache = FALSE;
2607 private $UnbufferedCallbacks = array();
2608 private $UseBaseTag = FALSE;
2609 private $UseMinimizedJavascript = FALSE;
2610
2611 private static $AppName = "ScoutAF";
2612 private static $ObjectDirectories = array();
2613 private static $ObjectLocationCache;
2614 private static $ObjectLocationCacheInterval = 60;
2615 private static $ObjectLocationCacheExpiration;
2616 private static $PreferHttpHost = FALSE;
2617 private static $RootUrlOverride = NULL;
2618 private static $SaveObjectLocationCache = FALSE;
2619 private static $SessionLifetime = 1440;
2620
2625 private $NoTSR = FALSE;
2626
2627 private $KnownPeriodicEvents = array();
2628 private $PeriodicEvents = array(
2629 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
2630 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
2631 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
2632 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
2633 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
2634 );
2635 private $EventPeriods = array(
2636 "EVENT_HOURLY" => 3600,
2637 "EVENT_DAILY" => 86400,
2638 "EVENT_WEEKLY" => 604800,
2639 "EVENT_MONTHLY" => 2592000,
2640 "EVENT_PERIODIC" => 0,
2641 );
2642 private $UIEvents = array(
2643 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
2644 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2645 "EVENT_PHP_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2646 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2647 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2648 "EVENT_PAGE_OUTPUT_FILTER" => self::EVENTTYPE_CHAIN,
2649 );
2650
2654 private function LoadSettings()
2655 {
2656 # read settings in from database
2657 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2658 $this->Settings = $this->DB->FetchRow();
2659
2660 # if settings were not previously initialized
2661 if (!$this->Settings)
2662 {
2663 # initialize settings in database
2664 $this->DB->Query("INSERT INTO ApplicationFrameworkSettings"
2665 ." (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')");
2666
2667 # read new settings in from database
2668 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2669 $this->Settings = $this->DB->FetchRow();
2670 }
2671
2672 # if base path was not previously set or we appear to have moved
2673 if (!array_key_exists("BasePath", $this->Settings)
2674 || (!strlen($this->Settings["BasePath"]))
2675 || (!array_key_exists("BasePathCheck", $this->Settings))
2676 || (__FILE__ != $this->Settings["BasePathCheck"]))
2677 {
2678 # attempt to extract base path from Apache .htaccess file
2679 if (is_readable(".htaccess"))
2680 {
2681 $Lines = file(".htaccess");
2682 foreach ($Lines as $Line)
2683 {
2684 if (preg_match("/\\s*RewriteBase\\s+/", $Line))
2685 {
2686 $Pieces = preg_split(
2687 "/\\s+/", $Line, NULL, PREG_SPLIT_NO_EMPTY);
2688 $BasePath = $Pieces[1];
2689 }
2690 }
2691 }
2692
2693 # if base path was found
2694 if (isset($BasePath))
2695 {
2696 # save base path locally
2697 $this->Settings["BasePath"] = $BasePath;
2698
2699 # save base path to database
2700 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2701 ." SET BasePath = '".addslashes($BasePath)."'"
2702 .", BasePathCheck = '".addslashes(__FILE__)."'");
2703 }
2704 }
2705
2706 # if template location cache has been saved to database
2707 if (isset($this->Settings["TemplateLocationCache"]))
2708 {
2709 # unserialize cache values into array and use if valid
2710 $Cache = unserialize($this->Settings["TemplateLocationCache"]);
2711 $this->Settings["TemplateLocationCache"] =
2712 count($Cache) ? $Cache : array();
2713 }
2714 else
2715 {
2716 # start with empty cache
2717 $this->Settings["TemplateLocationCache"] = array();
2718 }
2719
2720 # if object location cache has been saved to database
2721 if (isset($this->Settings["ObjectLocationCache"]))
2722 {
2723 # unserialize cache values into array and use if valid
2724 $Cache = unserialize($this->Settings["ObjectLocationCache"]);
2725 $this->Settings["ObjectLocationCache"] =
2726 count($Cache) ? $Cache : array();
2727
2728 # store static versions for use when autoloading objects
2729 self::$ObjectLocationCache =
2730 $this->Settings["ObjectLocationCache"];
2731 self::$ObjectLocationCacheInterval =
2732 $this->Settings["ObjectLocationCacheInterval"];
2733 self::$ObjectLocationCacheExpiration =
2734 $this->Settings["ObjectLocationCacheExpiration"];
2735 }
2736 else
2737 {
2738 # start with empty cache
2739 $this->Settings["ObjectLocationCache"] = array();
2740 }
2741 }
2742
2749 private function RewriteCleanUrls($PageName)
2750 {
2751 # if URL rewriting is supported by the server
2752 if ($this->HtaccessSupport())
2753 {
2754 # retrieve current URL and remove base path if present
2755 $Url = $this->GetPageLocation();
2756
2757 # for each clean URL mapping
2758 foreach ($this->CleanUrlMappings as $Info)
2759 {
2760 # if current URL matches clean URL pattern
2761 if (preg_match($Info["Pattern"], $Url, $Matches))
2762 {
2763 # set new page
2764 $PageName = $Info["Page"];
2765
2766 # if $_GET variables specified for clean URL
2767 if ($Info["GetVars"] !== NULL)
2768 {
2769 # for each $_GET variable specified for clean URL
2770 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
2771 {
2772 # start with template for variable value
2773 $Value = $VarTemplate;
2774
2775 # for each subpattern matched in current URL
2776 foreach ($Matches as $Index => $Match)
2777 {
2778 # if not first (whole) match
2779 if ($Index > 0)
2780 {
2781 # make any substitutions in template
2782 $Value = str_replace("$".$Index, $Match, $Value);
2783 }
2784 }
2785
2786 # set $_GET variable
2787 $_GET[$VarName] = $Value;
2788 }
2789 }
2790
2791 # set flag indicating clean URL mapped
2792 $this->CleanUrlRewritePerformed = TRUE;
2793
2794 # stop looking for a mapping
2795 break;
2796 }
2797 }
2798 }
2799
2800 # return (possibly) updated page name to caller
2801 return $PageName;
2802 }
2803
2820 private function FindFile($DirectoryList, $BaseName,
2821 $PossibleSuffixes = NULL, $PossiblePrefixes = NULL)
2822 {
2823 # generate template cache index for this page
2824 $CacheIndex = md5(serialize($DirectoryList))
2825 .":".$this->ActiveUI.":".$BaseName;
2826
2827 # if we have cached location and cache expiration time has not elapsed
2828 if (($this->Settings["TemplateLocationCacheInterval"] > 0)
2829 && count($this->Settings["TemplateLocationCache"])
2830 && array_key_exists($CacheIndex,
2831 $this->Settings["TemplateLocationCache"])
2832 && (time() < strtotime(
2833 $this->Settings["TemplateLocationCacheExpiration"])))
2834 {
2835 # use template location from cache
2836 $FoundFileName = $this->Settings[
2837 "TemplateLocationCache"][$CacheIndex];
2838 }
2839 else
2840 {
2841 # if suffixes specified and base name does not include suffix
2842 if (count($PossibleSuffixes)
2843 && !preg_match("/\.[a-zA-Z0-9]+$/", $BaseName))
2844 {
2845 # add versions of file names with suffixes to file name list
2846 $FileNames = array();
2847 foreach ($PossibleSuffixes as $Suffix)
2848 {
2849 $FileNames[] = $BaseName.".".$Suffix;
2850 }
2851 }
2852 else
2853 {
2854 # use base name as file name
2855 $FileNames = array($BaseName);
2856 }
2857
2858 # if prefixes specified
2859 if (count($PossiblePrefixes))
2860 {
2861 # add versions of file names with prefixes to file name list
2862 $NewFileNames = array();
2863 foreach ($FileNames as $FileName)
2864 {
2865 foreach ($PossiblePrefixes as $Prefix)
2866 {
2867 $NewFileNames[] = $Prefix.$FileName;
2868 }
2869 }
2870 $FileNames = $NewFileNames;
2871 }
2872
2873 # for each possible location
2874 $FoundFileName = NULL;
2875 foreach ($DirectoryList as $Dir)
2876 {
2877 # substitute active UI name into path
2878 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
2879
2880 # for each possible file name
2881 foreach ($FileNames as $File)
2882 {
2883 # if template is found at location
2884 if (file_exists($Dir.$File))
2885 {
2886 # save full template file name and stop looking
2887 $FoundFileName = $Dir.$File;
2888 break 2;
2889 }
2890 }
2891 }
2892
2893 # save location in cache
2894 $this->Settings["TemplateLocationCache"][$CacheIndex]
2895 = $FoundFileName;
2896
2897 # set flag indicating that cache should be saved
2898 $this->SaveTemplateLocationCache = TRUE;
2899 }
2900
2901 # return full template file name to caller
2902 return $FoundFileName;
2903 }
2904
2911 private function GetRequiredFilesNotYetLoaded($PageContentFile)
2912 {
2913 # start out assuming no files required
2914 $RequiredFiles = array();
2915
2916 # if page content file supplied
2917 if ($PageContentFile)
2918 {
2919 # if file containing list of required files is available
2920 $Path = dirname($PageContentFile);
2921 $RequireListFile = $Path."/REQUIRES";
2922 if (file_exists($RequireListFile))
2923 {
2924 # read in list of required files
2925 $RequestedFiles = file($RequireListFile);
2926
2927 # for each line in required file list
2928 foreach ($RequestedFiles as $Line)
2929 {
2930 # if line is not a comment
2931 $Line = trim($Line);
2932 if (!preg_match("/^#/", $Line))
2933 {
2934 # if file has not already been loaded
2935 if (!in_array($Line, $this->FoundUIFiles))
2936 {
2937 # add to list of required files
2938 $RequiredFiles[] = $Line;
2939 }
2940 }
2941 }
2942 }
2943 }
2944
2945 # add in additional required files if any
2946 if (count($this->AdditionalRequiredUIFiles))
2947 {
2948 # make sure there are no duplicates
2949 $AdditionalRequiredUIFiles = array_unique(
2950 $this->AdditionalRequiredUIFiles);
2951
2952 $RequiredFiles = array_merge(
2953 $RequiredFiles, $AdditionalRequiredUIFiles);
2954 }
2955
2956 # return list of required files to caller
2957 return $RequiredFiles;
2958 }
2959
2963 private function SetUpObjectAutoloading()
2964 {
2966 function __autoload($ClassName)
2967 {
2968 ApplicationFramework::AutoloadObjects($ClassName);
2969 }
2970 }
2971
2977 static function AutoloadObjects($ClassName)
2978 {
2979 # if caching is not turned off
2980 # and we have a cached location for class
2981 # and cache expiration has not elapsed
2982 # and file at cached location is readable
2983 if ((self::$ObjectLocationCacheInterval > 0)
2984 && count(self::$ObjectLocationCache)
2985 && array_key_exists($ClassName,
2986 self::$ObjectLocationCache)
2987 && (time() < strtotime(
2988 self::$ObjectLocationCacheExpiration))
2989 && is_readable(self::$ObjectLocationCache[$ClassName]))
2990 {
2991 # use object location from cache
2992 require_once(self::$ObjectLocationCache[$ClassName]);
2993 }
2994 else
2995 {
2996 # for each possible object file directory
2997 static $FileLists;
2998 foreach (self::$ObjectDirectories as $Location => $Info)
2999 {
3000 # if directory looks valid
3001 if (is_dir($Location))
3002 {
3003 # build class file name
3004 $NewClassName = ($Info["ClassPattern"] && $Info["ClassReplacement"])
3005 ? preg_replace($Info["ClassPattern"],
3006 $Info["ClassReplacement"], $ClassName)
3007 : $ClassName;
3008
3009 # read in directory contents if not already retrieved
3010 if (!isset($FileLists[$Location]))
3011 {
3012 $FileLists[$Location] = self::ReadDirectoryTree(
3013 $Location, '/^.+\.php$/i');
3014 }
3015
3016 # for each file in target directory
3017 $FileNames = $FileLists[$Location];
3018 $TargetName = strtolower($Info["Prefix"].$NewClassName.".php");
3019 foreach ($FileNames as $FileName)
3020 {
3021 # if file matches our target object file name
3022 if (strtolower($FileName) == $TargetName)
3023 {
3024 # include object file
3025 require_once($Location.$FileName);
3026
3027 # save location to cache
3028 self::$ObjectLocationCache[$ClassName]
3029 = $Location.$FileName;
3030
3031 # set flag indicating that cache should be saved
3032 self::$SaveObjectLocationCache = TRUE;
3033
3034 # stop looking
3035 break 2;
3036 }
3037 }
3038 }
3039 }
3040 }
3041 }
3051 private static function ReadDirectoryTree($Directory, $Pattern)
3052 {
3053 $CurrentDir = getcwd();
3054 chdir($Directory);
3055 $DirIter = new RecursiveDirectoryIterator(".");
3056 $IterIter = new RecursiveIteratorIterator($DirIter);
3057 $RegexResults = new RegexIterator($IterIter, $Pattern,
3058 RecursiveRegexIterator::GET_MATCH);
3059 $FileList = array();
3060 foreach ($RegexResults as $Result)
3061 {
3062 $FileList[] = substr($Result[0], 2);
3063 }
3064 chdir($CurrentDir);
3065 return $FileList;
3066 }
3067
3071 private function UndoMagicQuotes()
3072 {
3073 # if this PHP version has magic quotes support
3074 if (version_compare(PHP_VERSION, "5.4.0", "<"))
3075 {
3076 # turn off runtime magic quotes if on
3077 if (get_magic_quotes_runtime())
3078 {
3079 // @codingStandardsIgnoreStart
3080 set_magic_quotes_runtime(FALSE);
3081 // @codingStandardsIgnoreEnd
3082 }
3083
3084 # if magic quotes GPC is on
3085 if (get_magic_quotes_gpc())
3086 {
3087 # strip added slashes from incoming variables
3088 $GPC = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
3089 array_walk_recursive($GPC,
3090 array($this, "UndoMagicQuotes_StripCallback"));
3091 }
3092 }
3093 }
3094 private function UndoMagicQuotes_StripCallback(&$Value)
3095 {
3096 $Value = stripslashes($Value);
3097 }
3098
3103 private function LoadUIFunctions()
3104 {
3105 $Dirs = array(
3106 "local/interface/%ACTIVEUI%/include",
3107 "interface/%ACTIVEUI%/include",
3108 "local/interface/default/include",
3109 "interface/default/include",
3110 );
3111 foreach ($Dirs as $Dir)
3112 {
3113 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
3114 if (is_dir($Dir))
3115 {
3116 $FileNames = scandir($Dir);
3117 foreach ($FileNames as $FileName)
3118 {
3119 if (preg_match("/^F-([A-Za-z0-9_]+)\.php/", $FileName, $Matches)
3120 || preg_match("/^F-([A-Za-z0-9_]+)\.html/", $FileName, $Matches))
3121 {
3122 if (!function_exists($Matches[1]))
3123 {
3124 include_once($Dir."/".$FileName);
3125 }
3126 }
3127 }
3128 }
3129 }
3130 }
3131
3137 private function ProcessPeriodicEvent($EventName, $Callback)
3138 {
3139 # retrieve last execution time for event if available
3140 $Signature = self::GetCallbackSignature($Callback);
3141 $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
3142 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
3143
3144 # determine whether enough time has passed for event to execute
3145 $ShouldExecute = (($LastRun === NULL)
3146 || (time() > (strtotime($LastRun) + $this->EventPeriods[$EventName])))
3147 ? TRUE : FALSE;
3148
3149 # if event should run
3150 if ($ShouldExecute)
3151 {
3152 # add event to task queue
3153 $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
3154 $WrapperParameters = array(
3155 $EventName, $Callback, array("LastRunAt" => $LastRun));
3156 $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
3157 }
3158
3159 # add event to list of periodic events
3160 $this->KnownPeriodicEvents[$Signature] = array(
3161 "Period" => $EventName,
3162 "Callback" => $Callback,
3163 "Queued" => $ShouldExecute);
3164 }
3165
3173 private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
3174 {
3175 static $DB;
3176 if (!isset($DB)) { $DB = new Database(); }
3177
3178 # run event
3179 $ReturnVal = call_user_func_array($Callback, $Parameters);
3180
3181 # if event is already in database
3182 $Signature = self::GetCallbackSignature($Callback);
3183 if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
3184 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
3185 {
3186 # update last run time for event
3187 $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
3188 .(($EventName == "EVENT_PERIODIC")
3189 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
3190 : "NOW()")
3191 ." WHERE Signature = '".addslashes($Signature)."'");
3192 }
3193 else
3194 {
3195 # add last run time for event to database
3196 $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
3197 ."('".addslashes($Signature)."', "
3198 .(($EventName == "EVENT_PERIODIC")
3199 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
3200 : "NOW()").")");
3201 }
3202 }
3203
3209 private static function GetCallbackSignature($Callback)
3210 {
3211 return !is_array($Callback) ? $Callback
3212 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
3213 ."::".$Callback[1];
3214 }
3215
3220 private function PrepForTSR()
3221 {
3222 # if HTML has been output and it's time to launch another task
3223 # (only TSR if HTML has been output because otherwise browsers
3224 # may misbehave after connection is closed)
3225 if (($this->JumpToPage || !$this->SuppressHTML)
3226 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
3227 + (ini_get("max_execution_time")
3228 / $this->Settings["MaxTasksRunning"]) + 5))
3229 && $this->GetTaskQueueSize()
3230 && $this->Settings["TaskExecutionEnabled"])
3231 {
3232 # begin buffering output for TSR
3233 ob_start();
3234
3235 # let caller know it is time to launch another task
3236 return TRUE;
3237 }
3238 else
3239 {
3240 # let caller know it is not time to launch another task
3241 return FALSE;
3242 }
3243 }
3244
3249 private function LaunchTSR()
3250 {
3251 # set headers to close out connection to browser
3252 if (!$this->NoTSR)
3253 {
3254 ignore_user_abort(TRUE);
3255 header("Connection: close");
3256 header("Content-Length: ".ob_get_length());
3257 }
3258
3259 # output buffered content
3260 while (ob_get_level()) { ob_end_flush(); }
3261 flush();
3262
3263 # write out any outstanding data and end HTTP session
3264 session_write_close();
3265
3266 # set flag indicating that we are now running in background
3267 $this->RunningInBackground = TRUE;
3268
3269 # if there is still a task in the queue
3270 if ($this->GetTaskQueueSize())
3271 {
3272 # turn on output buffering to (hopefully) record any crash output
3273 ob_start();
3274
3275 # lock tables and grab last task run time to double check
3276 $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
3277 $this->LoadSettings();
3278
3279 # if still time to launch another task
3280 if (time() > (strtotime($this->Settings["LastTaskRunAt"])
3281 + (ini_get("max_execution_time")
3282 / $this->Settings["MaxTasksRunning"]) + 5))
3283 {
3284 # update the "last run" time and release tables
3285 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
3286 ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
3287 $this->DB->Query("UNLOCK TABLES");
3288
3289 # run tasks while there is a task in the queue and enough time left
3290 do
3291 {
3292 # run the next task
3293 $this->RunNextTask();
3294 }
3295 while ($this->GetTaskQueueSize()
3296 && ($this->GetSecondsBeforeTimeout() > 65));
3297 }
3298 else
3299 {
3300 # release tables
3301 $this->DB->Query("UNLOCK TABLES");
3302 }
3303 }
3304 }
3305
3313 private function GetTaskList($DBQuery, $Count, $Offset)
3314 {
3315 $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
3316 $Tasks = array();
3317 while ($Row = $this->DB->FetchRow())
3318 {
3319 $Tasks[$Row["TaskId"]] = $Row;
3320 if ($Row["Callback"] ==
3321 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
3322 {
3323 $WrappedCallback = unserialize($Row["Parameters"]);
3324 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
3325 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
3326 }
3327 else
3328 {
3329 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
3330 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
3331 }
3332 }
3333 return $Tasks;
3334 }
3335
3339 private function RunNextTask()
3340 {
3341 # lock tables to prevent same task from being run by multiple sessions
3342 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
3343
3344 # look for task at head of queue
3345 $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
3346 $Task = $this->DB->FetchRow();
3347
3348 # if there was a task available
3349 if ($Task)
3350 {
3351 # move task from queue to running tasks list
3352 $this->DB->Query("INSERT INTO RunningTasks "
3353 ."(TaskId,Callback,Parameters,Priority,Description) "
3354 ."SELECT * FROM TaskQueue WHERE TaskId = "
3355 .intval($Task["TaskId"]));
3356 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
3357 .intval($Task["TaskId"]));
3358
3359 # release table locks to again allow other sessions to run tasks
3360 $this->DB->Query("UNLOCK TABLES");
3361
3362 # unpack stored task info
3363 $Callback = unserialize($Task["Callback"]);
3364 $Parameters = unserialize($Task["Parameters"]);
3365
3366 # attempt to load task callback if not already available
3367 $this->LoadFunction($Callback);
3368
3369 # run task
3370 $this->RunningTask = $Task;
3371 if ($Parameters)
3372 {
3373 call_user_func_array($Callback, $Parameters);
3374 }
3375 else
3376 {
3377 call_user_func($Callback);
3378 }
3379 unset($this->RunningTask);
3380
3381 # remove task from running tasks list
3382 $this->DB->Query("DELETE FROM RunningTasks"
3383 ." WHERE TaskId = ".intval($Task["TaskId"]));
3384
3385 # prune running tasks list if necessary
3386 $RunningTasksCount = $this->DB->Query(
3387 "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
3388 if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
3389 {
3390 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
3391 ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
3392 }
3393 }
3394 else
3395 {
3396 # release table locks to again allow other sessions to run tasks
3397 $this->DB->Query("UNLOCK TABLES");
3398 }
3399 }
3400
3406 function OnCrash()
3407 {
3408 # attempt to remove any memory limits
3409 ini_set("memory_limit", -1);
3410
3411 # if there is a background task currently running
3412 if (isset($this->RunningTask))
3413 {
3414 # add info about error that caused crash (if available)
3415 if (function_exists("error_get_last"))
3416 {
3417 $CrashInfo["LastError"] = error_get_last();
3418 }
3419
3420 # add info about current output buffer contents (if available)
3421 if (ob_get_length() !== FALSE)
3422 {
3423 $CrashInfo["OutputBuffer"] = ob_get_contents();
3424 }
3425
3426 # if backtrace info is available for the crash
3427 $Backtrace = debug_backtrace();
3428 if (count($Backtrace) > 1)
3429 {
3430 # discard the current context from the backtrace
3431 array_shift($Backtrace);
3432
3433 # add the backtrace to the crash info
3434 $CrashInfo["Backtrace"] = $Backtrace;
3435 }
3436 # else if saved backtrace info is available
3437 elseif (isset($this->SavedContext))
3438 {
3439 # add the saved backtrace to the crash info
3440 $CrashInfo["Backtrace"] = $this->SavedContext;
3441 }
3442
3443 # if we have crash info to recod
3444 if (isset($CrashInfo))
3445 {
3446 # save crash info for currently running task
3447 $DB = new Database();
3448 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
3449 .addslashes(serialize($CrashInfo))
3450 ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
3451 }
3452 }
3453
3454 print("\n");
3455 return;
3456 }
3457
3474 private function AddToDirList($DirList, $Dir, $SearchLast, $SkipSlashCheck)
3475 {
3476 # convert incoming directory to array of directories (if needed)
3477 $Dirs = is_array($Dir) ? $Dir : array($Dir);
3478
3479 # reverse array so directories are searched in specified order
3480 $Dirs = array_reverse($Dirs);
3481
3482 # for each directory
3483 foreach ($Dirs as $Location)
3484 {
3485 # make sure directory includes trailing slash
3486 if (!$SkipSlashCheck)
3487 {
3488 $Location = $Location
3489 .((substr($Location, -1) != "/") ? "/" : "");
3490 }
3491
3492 # remove directory from list if already present
3493 if (in_array($Location, $DirList))
3494 {
3495 $DirList = array_diff(
3496 $DirList, array($Location));
3497 }
3498
3499 # add directory to list of directories
3500 if ($SearchLast)
3501 {
3502 array_push($DirList, $Location);
3503 }
3504 else
3505 {
3506 array_unshift($DirList, $Location);
3507 }
3508 }
3509
3510 # return updated directory list to caller
3511 return $DirList;
3512 }
3513
3521 private function ArrayPermutations($Items, $Perms = array())
3522 {
3523 if (empty($Items))
3524 {
3525 $Result = array($Perms);
3526 }
3527 else
3528 {
3529 $Result = array();
3530 for ($Index = count($Items) - 1; $Index >= 0; --$Index)
3531 {
3532 $NewItems = $Items;
3533 $NewPerms = $Perms;
3534 list($Segment) = array_splice($NewItems, $Index, 1);
3535 array_unshift($NewPerms, $Segment);
3536 $Result = array_merge($Result,
3537 $this->ArrayPermutations($NewItems, $NewPerms));
3538 }
3539 }
3540 return $Result;
3541 }
3542
3549 private function OutputModificationCallbackShell($Matches)
3550 {
3551 # call previously-stored external function
3552 return call_user_func($this->OutputModificationCallbackInfo["Callback"],
3553 $Matches,
3554 $this->OutputModificationCallbackInfo["Pattern"],
3555 $this->OutputModificationCallbackInfo["Page"],
3556 $this->OutputModificationCallbackInfo["SearchPattern"]);
3557 }
3558
3565 function UpdateSetting($FieldName, $NewValue = DB_NOVALUE)
3566 {
3567 return $this->DB->UpdateValue("ApplicationFrameworkSettings",
3568 $FieldName, $NewValue, NULL, $this->Settings);
3569 }
3570
3572 private $InterfaceDirList = array(
3573 "local/interface/%ACTIVEUI%/",
3574 "interface/%ACTIVEUI%/",
3575 "local/interface/default/",
3576 "interface/default/",
3577 );
3582 private $IncludeDirList = array(
3583 "local/interface/%ACTIVEUI%/include/",
3584 "interface/%ACTIVEUI%/include/",
3585 "local/interface/default/include/",
3586 "interface/default/include/",
3587 );
3589 private $ImageDirList = array(
3590 "local/interface/%ACTIVEUI%/images/",
3591 "interface/%ACTIVEUI%/images/",
3592 "local/interface/default/images/",
3593 "interface/default/images/",
3594 );
3596 private $FunctionDirList = array(
3597 "local/interface/%ACTIVEUI%/include/",
3598 "interface/%ACTIVEUI%/include/",
3599 "local/interface/default/include/",
3600 "interface/default/include/",
3601 "local/include/",
3602 "include/",
3603 );
3604
3605 const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
3606 }
3607
3608
ApplicationFramework\MaxTasks
MaxTasks($NewValue=DB_NOVALUE)
Get/set maximum number of tasks to have running simultaneously.
Definition: ApplicationFramework.php:2027
ApplicationFramework\LOGLVL_ERROR
const LOGLVL_ERROR
ERROR error logging level.
Definition: ApplicationFramework.php:1368
ApplicationFramework\GetOrphanedTaskList
GetOrphanedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:1909
ApplicationFramework\SuppressHTMLOutput
SuppressHTMLOutput($NewSetting=TRUE)
Suppress loading of HTML files.
Definition: ApplicationFramework.php:876
ApplicationFramework\AddInterfaceDirectories
AddInterfaceDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for user interface (HTML/TPL) files.
Definition: ApplicationFramework.php:236
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:210
ApplicationFramework\GetScriptUrl
static GetScriptUrl()
Retrieve SCRIPT_URL server value, pulling it from elsewhere if that variable isn't set...
Definition: ApplicationFramework.php:2477
ApplicationFramework\LOGLVL_INFO
const LOGLVL_INFO
INFO error logging level.
Definition: ApplicationFramework.php:1357
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:285
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:1769
ApplicationFramework\LOGLVL_FATAL
const LOGLVL_FATAL
FATAL error logging level.
Definition: ApplicationFramework.php:1373
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:848
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:967
ApplicationFramework\GetCleanUrlForPath
GetCleanUrlForPath($Path)
Get the clean URL mapped for a path.
Definition: ApplicationFramework.php:2205
ApplicationFramework\PRIORITY_LOW
const PRIORITY_LOW
Lower priority.
Definition: ApplicationFramework.php:1724
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:1841
ApplicationFramework\LogFile
LogFile($NewValue=NULL)
Get/set log file name.
Definition: ApplicationFramework.php:1336
ApplicationFramework\GetCleanUrl
GetCleanUrl()
Get the clean URL for the current page if one is available.
Definition: ApplicationFramework.php:2303
ApplicationFramework\MaxExecutionTime
MaxExecutionTime($NewValue=NULL)
Get/set maximum PHP execution time.
Definition: ApplicationFramework.php:2039
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:2447
ApplicationFramework\RequireUIFile
RequireUIFile($FileName)
Add file to list of required UI files.
Definition: ApplicationFramework.php:1058
ApplicationFramework\FullUrl
static FullUrl()
Get current full URL, before any clean URL remapping and with any query string (e.g.
Definition: ApplicationFramework.php:2432
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:2418
ApplicationFramework\GetOrphanedTaskCount
GetOrphanedTaskCount()
Retrieve current number of orphaned tasks.
Definition: ApplicationFramework.php:1921
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:1151
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:1163
ApplicationFramework\GetTaskQueueSize
GetTaskQueueSize($Priority=NULL)
Retrieve current number of tasks in queue.
Definition: ApplicationFramework.php:1829
DB_NOVALUE
const DB_NOVALUE
Definition: Axis--Database.php:1267
ApplicationFramework\RootUrlOverride
static RootUrlOverride($NewValue=self::NOVALUE)
Get/set root URL override.
Definition: ApplicationFramework.php:2400
ApplicationFramework\GetQueuedTaskCount
GetQueuedTaskCount($Callback=NULL, $Parameters=NULL, $Priority=NULL, $Description=NULL)
Get number of queued tasks that match supplied values.
Definition: ApplicationFramework.php:1860
ApplicationFramework\AutoloadObjects
static AutoloadObjects($ClassName)
Definition: ApplicationFramework.php:2977
ApplicationFramework\DeleteTask
DeleteTask($TaskId)
Remove task from task queues.
Definition: ApplicationFramework.php:1956
ApplicationFramework\LOGLVL_DEBUG
const LOGLVL_DEBUG
DEBUG error logging leve.
Definition: ApplicationFramework.php:1351
ApplicationFramework\EVENTTYPE_NAMED
const EVENTTYPE_NAMED
Named result event type.
Definition: ApplicationFramework.php:1405
ApplicationFramework\EVENTTYPE_FIRST
const EVENTTYPE_FIRST
First response event type.
Definition: ApplicationFramework.php:1397
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:2506
ApplicationFramework\EVENTTYPE_DEFAULT
const EVENTTYPE_DEFAULT
Default event type.
Definition: ApplicationFramework.php:1385
ApplicationFramework\GetPageUrl
GetPageUrl()
Get the full URL to the page.
Definition: ApplicationFramework.php:785
ApplicationFramework\IsStaticOnlyEvent
IsStaticOnlyEvent($EventName)
Report whether specified event only allows static callbacks.
Definition: ApplicationFramework.php:1626
ApplicationFramework\IsRegisteredEvent
IsRegisteredEvent($EventName)
Check if event has been registered (is available to be signaled).
Definition: ApplicationFramework.php:1443
ApplicationFramework\AddObjectDirectory
static AddObjectDirectory($Dir, $Prefix="", $ClassPattern=NULL, $ClassReplacement=NULL)
Add directory to be searched for object files when autoloading.
Definition: ApplicationFramework.php:148
ApplicationFramework\SignalEvent
SignalEvent($EventName, $Parameters=NULL)
Signal that an event has occured.
Definition: ApplicationFramework.php:1544
ApplicationFramework\BasePath
static BasePath()
Get current base path (usually the part after the host name).
Definition: ApplicationFramework.php:2460
ApplicationFramework\LOGLVL_TRACE
const LOGLVL_TRACE
TRACE error logging level.
Definition: ApplicationFramework.php:1346
ApplicationFramework\LOGLVL_WARNING
const LOGLVL_WARNING
WARNING error logging level.
Definition: ApplicationFramework.php:1362
ApplicationFramework\PRIORITY_MEDIUM
const PRIORITY_MEDIUM
Medium (default) priority.
Definition: ApplicationFramework.php:1722
ApplicationFramework\LogError
LogError($Level, $Msg)
Write error message to log.
Definition: ApplicationFramework.php:1209
ApplicationFramework\OnCrash
OnCrash()
Called automatically at program termination to ensure output is written out.
Definition: ApplicationFramework.php:3406
ApplicationFramework\GetKnownPeriodicEvents
GetKnownPeriodicEvents()
Get list of known periodic events.
Definition: ApplicationFramework.php:1676
ApplicationFramework\EVENTTYPE_CHAIN
const EVENTTYPE_CHAIN
Result chaining event type.
Definition: ApplicationFramework.php:1391
ApplicationFramework\GetSecondsBeforeTimeout
GetSecondsBeforeTimeout()
Get remaining available (PHP) execution time.
Definition: ApplicationFramework.php:1129
ApplicationFramework\TaskIsInQueue
TaskIsInQueue($Callback, $Parameters=NULL)
Check if task is already in queue or currently running.
Definition: ApplicationFramework.php:1806
ApplicationFramework\AddFunctionDirectories
AddFunctionDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for function ("F-") files.
Definition: ApplicationFramework.php:262
ApplicationFramework\LoggingLevel
LoggingLevel($NewValue=DB_NOVALUE)
Get/set logging level.
Definition: ApplicationFramework.php:1318
ApplicationFramework\ORDER_MIDDLE
const ORDER_MIDDLE
Run hooked function after ORDER_FIRST and before ORDER_LAST events.
Definition: ApplicationFramework.php:1410
PHP
PHP
Definition: OAIClient.php:39
ApplicationFramework\RegisterEvent
RegisterEvent($EventsOrEventName, $EventType=NULL)
Register one or more events that may be signaled.
Definition: ApplicationFramework.php:1422
ApplicationFramework\SetJumpToPage
SetJumpToPage($Page, $IsLiteral=FALSE)
Set URL of page to autoload after PHP page file is executed.
Definition: ApplicationFramework.php:798
ApplicationFramework\GetPageName
GetPageName()
Get name of page being loaded.
Definition: ApplicationFramework.php:755
ApplicationFramework\CleanUrlIsMapped
CleanUrlIsMapped($Path)
Report whether clean URL has already been mapped.
Definition: ApplicationFramework.php:2187
ApplicationFramework\PRIORITY_HIGH
const PRIORITY_HIGH
Highest priority.
Definition: ApplicationFramework.php:1720
ApplicationFramework\LoadFunction
LoadFunction($Callback)
Attempt to load code for function or method if not currently available.
Definition: ApplicationFramework.php:1071
ApplicationFramework\GetRunningTaskList
GetRunningTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:1894
ApplicationFramework\FindCommonTemplate
FindCommonTemplate($BaseName)
Preserved for backward compatibility for use with code written prior to October 2012.
Definition: ApplicationFramework.php:2570
ApplicationFramework\EventWillNextRunAt
EventWillNextRunAt($EventName, $Callback)
Get date/time a periodic event will next run.
Definition: ApplicationFramework.php:1641
ApplicationFramework\SessionLifetime
static SessionLifetime($NewValue=NULL)
Get/set session timeout in seconds.
Definition: ApplicationFramework.php:2330
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:1480
ApplicationFramework\IsHookedEvent
IsHookedEvent($EventName)
Check if an event is registered and is hooked to.
Definition: ApplicationFramework.php:1455
ApplicationFramework\GetFreeMemory
static GetFreeMemory()
Get current amount of free memory.
Definition: ApplicationFramework.php:2535
ApplicationFramework\AddImageDirectories
AddImageDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for image files.
Definition: ApplicationFramework.php:183
ApplicationFramework\HtmlCharset
HtmlCharset($NewSetting=NULL)
Get/set HTTP character encoding value.
Definition: ApplicationFramework.php:836
ApplicationFramework\ORDER_FIRST
const ORDER_FIRST
Run hooked function first (i.e.
Definition: ApplicationFramework.php:1408
ApplicationFramework\GetUncleanUrlForPath
GetUncleanUrlForPath($Path)
Get the unclean URL for mapped for a path.
Definition: ApplicationFramework.php:2253
ApplicationFramework\TemplateLocationCacheExpirationInterval
TemplateLocationCacheExpirationInterval($NewInterval=DB_NOVALUE)
Get/set UI template location cache expiration period in minutes.
Definition: ApplicationFramework.php:299
ApplicationFramework\GetUncleanUrl
GetUncleanUrl()
Get the unclean URL for the current page.
Definition: ApplicationFramework.php:2312
ApplicationFramework\RecordContextInCaseOfCrash
RecordContextInCaseOfCrash($BacktraceOptions=0, $BacktraceLimit=0)
Record the current execution context in case of crash.
Definition: ApplicationFramework.php:327
ApplicationFramework\JumpToPageIsSet
JumpToPageIsSet()
Report whether a page to autoload has been set.
Definition: ApplicationFramework.php:822
ApplicationFramework\ORDER_LAST
const ORDER_LAST
Run hooked function last (i.e.
Definition: ApplicationFramework.php:1412
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:864
ApplicationFramework\HtaccessSupport
static HtaccessSupport()
Determine if .htaccess files are enabled.
Definition: ApplicationFramework.php:2344
ApplicationFramework\UpdateSetting
UpdateSetting($FieldName, $NewValue=DB_NOVALUE)
Convenience function for getting/setting our settings.
Definition: ApplicationFramework.php:3565
ApplicationFramework\GetTask
GetTask($TaskId)
Retrieve task info from queue (either running or queued tasks).
Definition: ApplicationFramework.php:1969
ApplicationFramework\TaskExecutionEnabled
TaskExecutionEnabled($NewValue=DB_NOVALUE)
Get/set whether automatic task execution is enabled.
Definition: ApplicationFramework.php:2017
ApplicationFramework\GetPhpMemoryLimit
static GetPhpMemoryLimit()
Get PHP memory limit in bytes.
Definition: ApplicationFramework.php:2545
ApplicationFramework\LoadPage
LoadPage($PageName)
Load page PHP and HTML/TPL files.
Definition: ApplicationFramework.php:346
ApplicationFramework\AddEnvInclude
AddEnvInclude($FileName)
Add file to be included to set up environment.
Definition: ApplicationFramework.php:989
ApplicationFramework\NOVALUE
const NOVALUE
Definition: ApplicationFramework.php:3605
ApplicationFramework\ReQueueOrphanedTask
ReQueueOrphanedTask($TaskId, $NewPriority=NULL)
Move orphaned task back into queue.
Definition: ApplicationFramework.php:1934
ApplicationFramework\GUIFile
GUIFile($FileName)
Search UI directories for specified image or CSS file and return name of correct file.
Definition: ApplicationFramework.php:1000
ApplicationFramework\QueueTask
QueueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue.
Definition: ApplicationFramework.php:1740
ApplicationFramework\GetUserInterfaces
GetUserInterfaces()
Get the list of available user interfaces.
Definition: ApplicationFramework.php:901
ApplicationFramework\PUIFile
PUIFile($FileName)
Search UI directories for specified image or CSS file and print name of correct file.
Definition: ApplicationFramework.php:1045
ApplicationFramework\LogHighMemoryUsage
LogHighMemoryUsage($NewValue=DB_NOVALUE)
Get/set whether logging of high memory usage is enabled.
Definition: ApplicationFramework.php:1178
ApplicationFramework\ActiveUserInterface
ActiveUserInterface($UIName=NULL)
Get/set name of current active user interface.
Definition: ApplicationFramework.php:887
ApplicationFramework\GetPageLocation
GetPageLocation()
Get the URL path to the page without the base path, if present.
Definition: ApplicationFramework.php:765
ApplicationFramework\ObjectLocationCacheExpirationInterval
ObjectLocationCacheExpirationInterval($NewInterval=DB_NOVALUE)
Get/set object file location cache expiration period in minutes.
Definition: ApplicationFramework.php:310
ApplicationFramework\GetElapsedExecutionTime
GetElapsedExecutionTime()
Get time elapsed since constructor was called.
Definition: ApplicationFramework.php:1120
ApplicationFramework\SetBrowserDetectionFunc
SetBrowserDetectionFunc($DetectionFunc)
Specify function to use to detect the web browser type.
Definition: ApplicationFramework.php:274
ApplicationFramework\RootUrl
static RootUrl()
Get portion of current URL through host name, with no trailing slash (e.g.
Definition: ApplicationFramework.php:2357
ApplicationFramework\AddCleanUrl
AddCleanUrl($Pattern, $Page, $GetVars=NULL, $Template=NULL)
Add clean URL mapping.
Definition: ApplicationFramework.php:2089
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:1191
ApplicationFramework\PRIORITY_BACKGROUND
const PRIORITY_BACKGROUND
Lowest priority.
Definition: ApplicationFramework.php:1726
ApplicationFramework\LogMessage
LogMessage($Level, $Msg)
Write status message to log.
Definition: ApplicationFramework.php:1250
$Items
$Items
Definition: RSSClient--Test.php:26