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
320 static function SessionLifetime($NewValue = NULL)
321 {
322 if ($NewValue !== NULL)
323 {
324 self::$SessionLifetime = $NewValue;
325 }
326 return self::$SessionLifetime;
327 }
328
355 function AddCleanUrl($Pattern, $Page, $GetVars = NULL, $Template = NULL)
356 {
357 # save clean URL mapping parameters
358 $this->CleanUrlMappings[] = array(
359 "Pattern" => $Pattern,
360 "Page" => $Page,
361 "GetVars" => $GetVars,
362 );
363
364 # if replacement template specified
365 if ($Template !== NULL)
366 {
367 # if GET parameters specified
368 if (count($GetVars))
369 {
370 # retrieve all possible permutations of GET parameters
371 $GetPerms = $this->ArrayPermutations(array_keys($GetVars));
372
373 # for each permutation of GET parameters
374 foreach ($GetPerms as $VarPermutation)
375 {
376 # construct search pattern for permutation
377 $SearchPattern = "/href=([\"'])index\\.php\\?P=".$Page;
378 $GetVarSegment = "";
379 foreach ($VarPermutation as $GetVar)
380 {
381 if (preg_match("%\\\$[0-9]+%", $GetVars[$GetVar]))
382 {
383 $GetVarSegment .= "&amp;".$GetVar."=((?:(?!\\1)[^&])+)";
384 }
385 else
386 {
387 $GetVarSegment .= "&amp;".$GetVar."=".$GetVars[$GetVar];
388 }
389 }
390 $SearchPattern .= $GetVarSegment."\\1/i";
391
392 # if template is actually a callback
393 if (is_callable($Template))
394 {
395 # add pattern to HTML output mod callbacks list
396 $this->OutputModificationCallbacks[] = array(
397 "Pattern" => $Pattern,
398 "Page" => $Page,
399 "SearchPattern" => $SearchPattern,
400 "Callback" => $Template,
401 );
402 }
403 else
404 {
405 # construct replacement string for permutation
406 $Replacement = $Template;
407 $Index = 2;
408 foreach ($VarPermutation as $GetVar)
409 {
410 $Replacement = str_replace(
411 "\$".$GetVar, "\$".$Index, $Replacement);
412 $Index++;
413 }
414 $Replacement = "href=\"".$Replacement."\"";
415
416 # add pattern to HTML output modifications list
417 $this->OutputModificationPatterns[] = $SearchPattern;
418 $this->OutputModificationReplacements[] = $Replacement;
419 }
420 }
421 }
422 else
423 {
424 # construct search pattern
425 $SearchPattern = "/href=\"index\\.php\\?P=".$Page."\"/i";
426
427 # if template is actually a callback
428 if (is_callable($Template))
429 {
430 # add pattern to HTML output mod callbacks list
431 $this->OutputModificationCallbacks[] = array(
432 "Pattern" => $Pattern,
433 "Page" => $Page,
434 "SearchPattern" => $SearchPattern,
435 "Callback" => $Template,
436 );
437 }
438 else
439 {
440 # add simple pattern to HTML output modifications list
441 $this->OutputModificationPatterns[] = $SearchPattern;
442 $this->OutputModificationReplacements[] = "href=\"".$Template."\"";
443 }
444 }
445 }
446 }
447
453 function CleanUrlIsMapped($Path)
454 {
455 foreach ($this->CleanUrlMappings as $Info)
456 {
457 if (preg_match($Info["Pattern"], $Path))
458 {
459 return TRUE;
460 }
461 }
462 return FALSE;
463 }
464
471 function GetCleanUrlForPath($Path)
472 {
473 # the search patterns and callbacks require a specific format
474 $Format = "href=\"".str_replace("&", "&amp;", $Path)."\"";
475 $Search = $Format;
476
477 # perform any regular expression replacements on the search string
478 $Search = preg_replace(
479 $this->OutputModificationPatterns,
480 $this->OutputModificationReplacements,
481 $Search);
482
483 # only run the callbacks if a replacement hasn't already been performed
484 if ($Search == $Format)
485 {
486 # perform any callback replacements on the search string
487 foreach ($this->OutputModificationCallbacks as $Info)
488 {
489 # make the information available to the callback
490 $this->OutputModificationCallbackInfo = $Info;
491
492 # execute the callback
493 $Search = preg_replace_callback(
494 $Info["SearchPattern"],
495 array($this, "OutputModificationCallbackShell"),
496 $Search);
497 }
498 }
499
500 # return the path untouched if no replacements were performed
501 if ($Search == $Format)
502 {
503 return $Path;
504 }
505
506 # remove the bits added to the search string to get it recognized by
507 # the replacement expressions and callbacks
508 $Result = substr($Search, 6, -1);
509
510 return $Result;
511 }
512
519 public function GetUncleanUrlForPath($Path)
520 {
521 # for each clean URL mapping
522 foreach ($this->CleanUrlMappings as $Info)
523 {
524 # if current path matches the clean URL pattern
525 if (preg_match($Info["Pattern"], $Path, $Matches))
526 {
527 # the GET parameters for the URL, starting with the page name
528 $GetVars = array("P" => $Info["Page"]);
529
530 # if additional $_GET variables specified for clean URL
531 if ($Info["GetVars"] !== NULL)
532 {
533 # for each $_GET variable specified for clean URL
534 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
535 {
536 # start with template for variable value
537 $Value = $VarTemplate;
538
539 # for each subpattern matched in current URL
540 foreach ($Matches as $Index => $Match)
541 {
542 # if not first (whole) match
543 if ($Index > 0)
544 {
545 # make any substitutions in template
546 $Value = str_replace("$".$Index, $Match, $Value);
547 }
548 }
549
550 # add the GET variable
551 $GetVars[$VarName] = $Value;
552 }
553 }
554
555 # return the unclean URL
556 return "index.php?" . http_build_query($GetVars);
557 }
558 }
559
560 # return the path unchanged
561 return $Path;
562 }
563
569 function GetCleanUrl()
570 {
571 return $this->GetCleanUrlForPath($this->GetUncleanUrl());
572 }
573
578 function GetUncleanUrl()
579 {
580 $GetVars = array("P" => $this->GetPageName()) + $_GET;
581 return "index.php?" . http_build_query($GetVars);
582 }
583
588 function LoadPage($PageName)
589 {
590 # perform any clean URL rewriting
591 $PageName = $this->RewriteCleanUrls($PageName);
592
593 # sanitize incoming page name and save local copy
594 $PageName = preg_replace("/[^a-zA-Z0-9_.-]/", "", $PageName);
595 $this->PageName = $PageName;
596
597 # buffer any output from includes or PHP file
598 ob_start();
599
600 # include any files needed to set up execution environment
601 foreach ($this->EnvIncludes as $IncludeFile)
602 {
603 include($IncludeFile);
604 }
605
606 # signal page load
607 $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName));
608
609 # signal PHP file load
610 $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array(
611 "PageName" => $PageName));
612
613 # if signal handler returned new page name value
614 $NewPageName = $PageName;
615 if (($SignalResult["PageName"] != $PageName)
616 && strlen($SignalResult["PageName"]))
617 {
618 # if new page name value is page file
619 if (file_exists($SignalResult["PageName"]))
620 {
621 # use new value for PHP file name
622 $PageFile = $SignalResult["PageName"];
623 }
624 else
625 {
626 # use new value for page name
627 $NewPageName = $SignalResult["PageName"];
628 }
629
630 # update local copy of page name
631 $this->PageName = $NewPageName;
632 }
633
634 # if we do not already have a PHP file
635 if (!isset($PageFile))
636 {
637 # look for PHP file for page
638 $OurPageFile = "pages/".$NewPageName.".php";
639 $LocalPageFile = "local/pages/".$NewPageName.".php";
640 $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
641 : (file_exists($OurPageFile) ? $OurPageFile
642 : "pages/".$this->DefaultPage.".php");
643 }
644
645 # load PHP file
646 include($PageFile);
647
648 # save buffered output to be displayed later after HTML file loads
649 $PageOutput = ob_get_contents();
650 ob_end_clean();
651
652 # signal PHP file load is complete
653 ob_start();
654 $Context["Variables"] = get_defined_vars();
655 $this->SignalEvent("EVENT_PHP_FILE_LOAD_COMPLETE",
656 array("PageName" => $PageName, "Context" => $Context));
657 $PageCompleteOutput = ob_get_contents();
658 ob_end_clean();
659
660 # set up for possible TSR (Terminate and Stay Resident :))
661 $ShouldTSR = $this->PrepForTSR();
662
663 # if PHP file indicated we should autorefresh to somewhere else
664 if ($this->JumpToPage)
665 {
666 if (!strlen(trim($PageOutput)))
667 {
668 ?><html>
669 <head>
670 <meta http-equiv="refresh" content="0; URL=<?PHP
671 print($this->JumpToPage); ?>">
672 </head>
673 <body bgcolor="white">
674 </body>
675 </html><?PHP
676 }
677 }
678 # else if HTML loading is not suppressed
679 elseif (!$this->SuppressHTML)
680 {
681 # set content-type to get rid of diacritic errors
682 header("Content-Type: text/html; charset="
683 .$this->HtmlCharset, TRUE);
684
685 # load common HTML file (defines common functions) if available
686 $CommonHtmlFile = $this->FindFile($this->IncludeDirList,
687 "Common", array("tpl", "html"));
688 if ($CommonHtmlFile) { include($CommonHtmlFile); }
689
690 # load UI functions
691 $this->LoadUIFunctions();
692
693 # begin buffering content
694 ob_start();
695
696 # signal HTML file load
697 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array(
698 "PageName" => $PageName));
699
700 # if signal handler returned new page name value
701 $NewPageName = $PageName;
702 $PageContentFile = NULL;
703 if (($SignalResult["PageName"] != $PageName)
704 && strlen($SignalResult["PageName"]))
705 {
706 # if new page name value is HTML file
707 if (file_exists($SignalResult["PageName"]))
708 {
709 # use new value for HTML file name
710 $PageContentFile = $SignalResult["PageName"];
711 }
712 else
713 {
714 # use new value for page name
715 $NewPageName = $SignalResult["PageName"];
716 }
717 }
718
719 # load page content HTML file if available
720 if ($PageContentFile === NULL)
721 {
722 $PageContentFile = $this->FindFile(
723 $this->InterfaceDirList, $NewPageName,
724 array("tpl", "html"));
725 }
726 if ($PageContentFile)
727 {
728 include($PageContentFile);
729 }
730 else
731 {
732 print "<h2>ERROR: No HTML/TPL template found"
733 ." for this page.</h2>";
734 }
735
736 # signal HTML file load complete
737 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE");
738
739 # stop buffering and save output
740 $PageContentOutput = ob_get_contents();
741 ob_end_clean();
742
743 # load page start HTML file if available
744 ob_start();
745 $PageStartFile = $this->FindFile($this->IncludeDirList, "Start",
746 array("tpl", "html"), array("StdPage", "StandardPage"));
747 if ($PageStartFile) { include($PageStartFile); }
748 $PageStartOutput = ob_get_contents();
749 ob_end_clean();
750
751 # load page end HTML file if available
752 ob_start();
753 $PageEndFile = $this->FindFile($this->IncludeDirList, "End",
754 array("tpl", "html"), array("StdPage", "StandardPage"));
755 if ($PageEndFile) { include($PageEndFile); }
756 $PageEndOutput = ob_get_contents();
757 ob_end_clean();
758
759 # get list of any required files not loaded
760 $RequiredFiles = $this->GetRequiredFilesNotYetLoaded($PageContentFile);
761
762 # if a browser detection function has been made available
763 if (is_callable($this->BrowserDetectFunc))
764 {
765 # call function to get browser list
766 $Browsers = call_user_func($this->BrowserDetectFunc);
767
768 # for each required file
769 $NewRequiredFiles = array();
770 foreach ($RequiredFiles as $File)
771 {
772 # if file name includes browser keyword
773 if (preg_match("/%BROWSER%/", $File))
774 {
775 # for each browser
776 foreach ($Browsers as $Browser)
777 {
778 # substitute in browser name and add to new file list
779 $NewRequiredFiles[] = preg_replace(
780 "/%BROWSER%/", $Browser, $File);
781 }
782 }
783 else
784 {
785 # add to new file list
786 $NewRequiredFiles[] = $File;
787 }
788 }
789 $RequiredFiles = $NewRequiredFiles;
790 }
791
792 # for each required file
793 foreach ($RequiredFiles as $File)
794 {
795 # locate specific file to use
796 $FilePath = $this->GUIFile($File);
797
798 # if file was found
799 if ($FilePath)
800 {
801 # determine file type
802 $NamePieces = explode(".", $File);
803 $FileSuffix = strtolower(array_pop($NamePieces));
804
805 # add file to HTML output based on file type
806 $FilePath = htmlspecialchars($FilePath);
807 switch ($FileSuffix)
808 {
809 case "js":
810 $Tag = '<script type="text/javascript" src="'
811 .$FilePath.'"></script>';
812 $PageEndOutput = preg_replace(
813 "#</body>#i", $Tag."\n</body>", $PageEndOutput, 1);
814 break;
815
816 case "css":
817 $Tag = '<link rel="stylesheet" type="text/css"'
818 .' media="all" href="'.$FilePath.'">';
819 $PageStartOutput = preg_replace(
820 "#</head>#i", $Tag."\n</head>", $PageStartOutput, 1);
821 break;
822 }
823 }
824 }
825
826 # assemble full page
827 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
828
829 # perform any regular expression replacements in output
830 $FullPageOutput = preg_replace($this->OutputModificationPatterns,
831 $this->OutputModificationReplacements, $FullPageOutput);
832
833 # perform any callback replacements in output
834 foreach ($this->OutputModificationCallbacks as $Info)
835 {
836 $this->OutputModificationCallbackInfo = $Info;
837 $FullPageOutput = preg_replace_callback($Info["SearchPattern"],
838 array($this, "OutputModificationCallbackShell"),
839 $FullPageOutput);
840 }
841
842 # if relative paths may not work because we were invoked via clean URL
843 if ($this->CleanUrlRewritePerformed || self::WasUrlRewritten())
844 {
845 # if using the <base> tag is okay
846 $BaseUrl = $this->BaseUrl();
847 if ($this->UseBaseTag)
848 {
849 # add <base> tag to header
850 $PageStartOutput = preg_replace("%<head>%",
851 "<head><base href=\"".$BaseUrl."\" />",
852 $PageStartOutput);
853
854 # re-assemble full page with new header
855 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
856
857 # the absolute URL to the current page
858 $FullUrl = $BaseUrl . $this->GetPageLocation();
859
860 # make HREF attribute values with just a fragment ID
861 # absolute since they don't work with the <base> tag because
862 # they are relative to the current page/URL, not the site
863 # root
864 $FullPageOutput = preg_replace(
865 array("%href=\"(#[^:\" ]+)\"%i", "%href='(#[^:' ]+)'%i"),
866 array("href=\"".$FullUrl."$1\"", "href='".$FullUrl."$1'"),
867 $FullPageOutput);
868 }
869 else
870 {
871 # try to fix any relative paths throughout code
872 $FullPageOutput = preg_replace(array(
873 "%src=\"([^?*:;{}\\\\\" ]+)\.(js|css|gif|png|jpg)\"%i",
874 "%src='([^?*:;{}\\\\' ]+)\.(js|css|gif|png|jpg)'%i",
875 # don't rewrite HREF attributes that are just
876 # fragment IDs because they are relative to the
877 # current page/URL, not the site root
878 "%href=\"([^#][^:\" ]*)\"%i",
879 "%href='([^#][^:' ]*)'%i",
880 "%action=\"([^#][^:\" ]*)\"%i",
881 "%action='([^#][^:' ]*)'%i",
882 "%@import\s+url\(\"([^:\" ]+)\"\s*\)%i",
883 "%@import\s+url\('([^:\" ]+)'\s*\)%i",
884 "%@import\s+\"([^:\" ]+)\"\s*%i",
885 "%@import\s+'([^:\" ]+)'\s*%i",
886 ),
887 array(
888 "src=\"".$BaseUrl."$1.$2\"",
889 "src=\"".$BaseUrl."$1.$2\"",
890 "href=\"".$BaseUrl."$1\"",
891 "href=\"".$BaseUrl."$1\"",
892 "action=\"".$BaseUrl."$1\"",
893 "action=\"".$BaseUrl."$1\"",
894 "@import url(\"".$BaseUrl."$1\")",
895 "@import url('".$BaseUrl."$1')",
896 "@import \"".$BaseUrl."$1\"",
897 "@import '".$BaseUrl."$1'",
898 ),
899 $FullPageOutput);
900 }
901 }
902
903 # provide the opportunity to modify full page output
904 $SignalResult = $this->SignalEvent("EVENT_PAGE_OUTPUT_FILTER", array(
905 "PageOutput" => $FullPageOutput));
906 if (isset($SignalResult["PageOutput"])
907 && strlen($SignalResult["PageOutput"]))
908 {
909 $FullPageOutput = $SignalResult["PageOutput"];
910 }
911
912 # write out full page
913 print $FullPageOutput;
914 }
915
916 # run any post-processing routines
917 foreach ($this->PostProcessingFuncs as $Func)
918 {
919 call_user_func_array($Func["FunctionName"], $Func["Arguments"]);
920 }
921
922 # write out any output buffered from page code execution
923 if (strlen($PageOutput))
924 {
925 if (!$this->SuppressHTML)
926 {
927 ?><table width="100%" cellpadding="5"
928 style="border: 2px solid #666666; background: #CCCCCC;
929 font-family: Courier New, Courier, monospace;
930 margin-top: 10px;"><tr><td><?PHP
931 }
932 if ($this->JumpToPage)
933 {
934 ?><div style="color: #666666;"><span style="font-size: 150%;">
935 <b>Page Jump Aborted</b></span>
936 (because of error or other unexpected output)<br />
937 <b>Jump Target:</b>
938 <i><?PHP print($this->JumpToPage); ?></i></div><?PHP
939 }
940 print $PageOutput;
941 if (!$this->SuppressHTML)
942 {
943 ?></td></tr></table><?PHP
944 }
945 }
946
947 # write out any output buffered from the page code execution complete signal
948 if (!$this->JumpToPage && !$this->SuppressHTML && strlen($PageCompleteOutput))
949 {
950 print $PageCompleteOutput;
951 }
952
953 # execute callbacks that should not have their output buffered
954 foreach ($this->UnbufferedCallbacks as $Callback)
955 {
956 call_user_func_array($Callback[0], $Callback[1]);
957 }
958
959 # log slow page loads
960 if ($this->LogSlowPageLoads()
961 && ($this->GetElapsedExecutionTime() >= $this->SlowPageLoadThreshold()))
962 {
963 $SlowPageLoadMsg = "Slow page load ("
964 .intval($this->GetElapsedExecutionTime())."s) for "
965 .$this->FullUrl()." from "
966 .$_SERVER["REMOTE_ADDR"];
967 $this->LogMessage(self::LOGLVL_INFO, $SlowPageLoadMsg);
968 }
969
970 # terminate and stay resident (TSR!) if indicated and HTML has been output
971 # (only TSR if HTML has been output because otherwise browsers will misbehave)
972 if ($ShouldTSR) { $this->LaunchTSR(); }
973 }
974
980 function GetPageName()
981 {
982 return $this->PageName;
983 }
984
990 function GetPageLocation()
991 {
992 # retrieve current URL
993 $Url = $this->GetScriptUrl();
994
995 # remove the base path if present
996 $BasePath = $this->Settings["BasePath"];
997 if (stripos($Url, $BasePath) === 0)
998 {
999 $Url = substr($Url, strlen($BasePath));
1000 }
1001
1002 return $Url;
1003 }
1004
1009 function GetPageUrl()
1010 {
1011 return self::BaseUrl() . $this->GetPageLocation();
1012 }
1013
1022 function SetJumpToPage($Page, $IsLiteral = FALSE)
1023 {
1024 if (!is_null($Page)
1025 && (!$IsLiteral)
1026 && (strpos($Page, "?") === FALSE)
1027 && ((strpos($Page, "=") !== FALSE)
1028 || ((stripos($Page, ".php") === FALSE)
1029 && (stripos($Page, ".htm") === FALSE)
1030 && (strpos($Page, "/") === FALSE)))
1031 && (stripos($Page, "http://") !== 0)
1032 && (stripos($Page, "https://") !== 0))
1033 {
1034 $this->JumpToPage = self::BaseUrl() . "index.php?P=".$Page;
1035 }
1036 else
1037 {
1038 $this->JumpToPage = $Page;
1039 }
1040 }
1041
1046 function JumpToPageIsSet()
1047 {
1048 return ($this->JumpToPage === NULL) ? FALSE : TRUE;
1049 }
1050
1060 function HtmlCharset($NewSetting = NULL)
1061 {
1062 if ($NewSetting !== NULL) { $this->HtmlCharset = $NewSetting; }
1063 return $this->HtmlCharset;
1064 }
1065
1072 public function UseMinimizedJavascript($NewSetting = NULL)
1073 {
1074 if ($NewSetting !== NULL) { $this->UseMinimizedJavascript = $NewSetting; }
1075 return $this->UseMinimizedJavascript;
1076 }
1077
1088 function UseBaseTag($NewValue = NULL)
1089 {
1090 if ($NewValue !== NULL) { $this->UseBaseTag = $NewValue ? TRUE : FALSE; }
1091 return $this->UseBaseTag;
1092 }
1093
1100 function SuppressHTMLOutput($NewSetting = TRUE)
1101 {
1102 $this->SuppressHTML = $NewSetting;
1103 }
1104
1111 function ActiveUserInterface($UIName = NULL)
1112 {
1113 if ($UIName !== NULL)
1114 {
1115 $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
1116 }
1117 return $this->ActiveUI;
1118 }
1119
1125 function GetUserInterfaces()
1126 {
1127 # possible UI directories
1128 $InterfaceDirs = array(
1129 "interface",
1130 "local/interface");
1131
1132 # start out with an empty list
1133 $Interfaces = array();
1134
1135 # for each possible UI directory
1136 foreach ($InterfaceDirs as $InterfaceDir)
1137 {
1138 $Dir = dir($InterfaceDir);
1139
1140 # for each file in current directory
1141 while (($DirEntry = $Dir->read()) !== FALSE)
1142 {
1143 $InterfacePath = $InterfaceDir."/".$DirEntry;
1144
1145 # skip anything that doesn't have a name in the required format
1146 if (!preg_match('/^[a-zA-Z0-9]+$/', $DirEntry))
1147 {
1148 continue;
1149 }
1150
1151 # skip anything that isn't a directory
1152 if (!is_dir($InterfacePath))
1153 {
1154 continue;
1155 }
1156
1157 # read the UI name (if available)
1158 $UIName = @file_get_contents($InterfacePath."/NAME");
1159
1160 # use the directory name if the UI name isn't available
1161 if ($UIName === FALSE || !strlen($UIName))
1162 {
1163 $UIName = $DirEntry;
1164 }
1165
1166 $Interfaces[$InterfacePath] = $UIName;
1167 }
1168
1169 $Dir->close();
1170 }
1171
1172 # return list to caller
1173 return $Interfaces;
1174 }
1175
1191 function AddPostProcessingCall($FunctionName,
1192 &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
1193 &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
1194 &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
1195 {
1196 $FuncIndex = count($this->PostProcessingFuncs);
1197 $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
1198 $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
1199 $Index = 1;
1200 while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
1201 {
1202 $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
1203 =& ${"Arg".$Index};
1204 $Index++;
1205 }
1206 }
1207
1213 function AddEnvInclude($FileName)
1214 {
1215 $this->EnvIncludes[] = $FileName;
1216 }
1217
1224 function GUIFile($FileName)
1225 {
1226 # determine if the file is an image or JavaScript file
1227 $FileIsImage = preg_match("/\.(gif|jpg|png)$/", $FileName);
1228 $FileIsJavascript = preg_match("/\.js$/", $FileName);
1229
1230 # determine which location to search based on file suffix
1231 $DirList = $FileIsImage ? $this->ImageDirList : $this->IncludeDirList;
1232
1233 # if directed to get a minimized JavaScript file
1234 if ($FileIsJavascript && $this->UseMinimizedJavascript)
1235 {
1236 # first try to find the minimized JavaScript file
1237 $MinimizedFileName = substr_replace($FileName, ".min", -3, 0);
1238 $FoundFileName = $this->FindFile($DirList, $MinimizedFileName);
1239
1240 # search for the regular file if a minimized file wasn't found
1241 if (is_null($FoundFileName))
1242 {
1243 $FoundFileName = $this->FindFile($DirList, $FileName);
1244 }
1245 }
1246
1247 # otherwise just search for the file
1248 else
1249 {
1250 $FoundFileName = $this->FindFile($DirList, $FileName);
1251 }
1252
1253 # add non-image files to list of found files (used for required files loading)
1254 if (!$FileIsImage) { $this->FoundUIFiles[] = basename($FoundFileName); }
1255
1256 # return file name to caller
1257 return $FoundFileName;
1258 }
1259
1269 function PUIFile($FileName)
1270 {
1271 $FullFileName = $this->GUIFile($FileName);
1272 if ($FullFileName) { print($FullFileName); }
1273 }
1274
1282 function RequireUIFile($FileName)
1283 {
1284 $this->AdditionalRequiredUIFiles[] = $FileName;
1285 }
1286
1295 function LoadFunction($Callback)
1296 {
1297 # if specified function is not currently available
1298 if (!is_callable($Callback))
1299 {
1300 # if function info looks legal
1301 if (is_string($Callback) && strlen($Callback))
1302 {
1303 # start with function directory list
1304 $Locations = $this->FunctionDirList;
1305
1306 # add object directories to list
1307 $Locations = array_merge(
1308 $Locations, array_keys(self::$ObjectDirectories));
1309
1310 # look for function file
1311 $FunctionFileName = $this->FindFile($Locations, "F-".$Callback,
1312 array("php", "html"));
1313
1314 # if function file was found
1315 if ($FunctionFileName)
1316 {
1317 # load function file
1318 include_once($FunctionFileName);
1319 }
1320 else
1321 {
1322 # log error indicating function load failed
1323 $this->LogError(self::LOGLVL_ERROR, "Unable to load function"
1324 ." for callback \"".$Callback."\".");
1325 }
1326 }
1327 else
1328 {
1329 # log error indicating specified function info was bad
1330 $this->LogError(self::LOGLVL_ERROR, "Unloadable callback value"
1331 ." (".$Callback.")"
1332 ." passed to AF::LoadFunction().");
1333 }
1334 }
1335
1336 # report to caller whether function load succeeded
1337 return is_callable($Callback);
1338 }
1339
1344 function GetElapsedExecutionTime()
1345 {
1346 return microtime(TRUE) - $this->ExecutionStartTime;
1347 }
1348
1353 function GetSecondsBeforeTimeout()
1354 {
1355 return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
1356 }
1357
1363 function GetFreeMemory()
1364 {
1365 $Str = strtoupper(ini_get("memory_limit"));
1366 if (substr($Str, -1) == "B") { $Str = substr($Str, 0, strlen($Str) - 1); }
1367 switch (substr($Str, -1))
1368 {
1369 case "K": $MemoryLimit = (int)$Str * 1024; break;
1370 case "M": $MemoryLimit = (int)$Str * 1048576; break;
1371 case "G": $MemoryLimit = (int)$Str * 1073741824; break;
1372 default: $MemoryLimit = (int)$Str; break;
1373 }
1374
1375 return $MemoryLimit - memory_get_usage();
1376 }
1377
1388 function LogSlowPageLoads($NewValue = DB_NOVALUE)
1389 {
1390 return $this->UpdateSetting("LogSlowPageLoads", $NewValue);
1391 }
1392
1400 function SlowPageLoadThreshold($NewValue = DB_NOVALUE)
1401 {
1402 return $this->UpdateSetting("SlowPageLoadThreshold", $NewValue);
1403 }
1404
1409 function HtaccessSupport()
1410 {
1411 # HTACCESS_SUPPORT is set in the .htaccess file
1412 return isset($_SERVER["HTACCESS_SUPPORT"]);
1413 }
1414
1419 static function BaseUrl()
1420 {
1421 $Protocol = (isset($_SERVER["HTTPS"]) ? "https" : "http");
1422 $BaseUrl = $Protocol."://"
1423 .(($_SERVER["SERVER_NAME"] != "127.0.0.1")
1424 ? $_SERVER["SERVER_NAME"]
1425 : $_SERVER["HTTP_HOST"])
1426 .dirname($_SERVER["SCRIPT_NAME"]);
1427 if (substr($BaseUrl, -1) != "/") { $BaseUrl .= "/"; }
1428 return $BaseUrl;
1429 }
1430
1435 static function FullUrl()
1436 {
1437 $Protocol = (isset($_SERVER["HTTPS"]) ? "https" : "http");
1438 $FullUrl = $Protocol."://"
1439 .(($_SERVER["SERVER_NAME"] != "127.0.0.1")
1440 ? $_SERVER["SERVER_NAME"]
1441 : $_SERVER["HTTP_HOST"])
1442 .$_SERVER["REQUEST_URI"];
1443 return $FullUrl;
1444 }
1445
1450 static function BasePath()
1451 {
1452 $BasePath = dirname($_SERVER["SCRIPT_NAME"]);
1453
1454 if (substr($BasePath, -1) != "/")
1455 {
1456 $BasePath .= "/";
1457 }
1458
1459 return $BasePath;
1460 }
1461
1467 static function GetScriptUrl()
1468 {
1469 if (array_key_exists("SCRIPT_URL", $_SERVER))
1470 {
1471 return $_SERVER["SCRIPT_URL"];
1472 }
1473 elseif (array_key_exists("REDIRECT_URL", $_SERVER))
1474 {
1475 return $_SERVER["REDIRECT_URL"];
1476 }
1477 elseif (array_key_exists("REQUEST_URI", $_SERVER))
1478 {
1479 $Pieces = parse_url($_SERVER["REQUEST_URI"]);
1480 return $Pieces["path"];
1481 }
1482 else
1483 {
1484 return NULL;
1485 }
1486 }
1487
1496 static function WasUrlRewritten($ScriptName="index.php")
1497 {
1498 # needed to get the path of the URL minus the query and fragment pieces
1499 $Components = parse_url(self::GetScriptUrl());
1500
1501 # if parsing was successful and a path is set
1502 if (is_array($Components) && isset($Components["path"]))
1503 {
1504 $BasePath = self::BasePath();
1505 $Path = $Components["path"];
1506
1507 # the URL was rewritten if the path isn't the base path, i.e., the
1508 # home page, and the file in the URL isn't the script generating the
1509 # page
1510 if ($BasePath != $Path && basename($Path) != $ScriptName)
1511 {
1512 return TRUE;
1513 }
1514 }
1515
1516 # the URL wasn't rewritten
1517 return FALSE;
1518 }
1519
1533 function LogError($Level, $Msg)
1534 {
1535 # if error level is at or below current logging level
1536 if ($this->Settings["LoggingLevel"] >= $Level)
1537 {
1538 # attempt to log error message
1539 $Result = $this->LogMessage($Level, $Msg);
1540
1541 # if logging attempt failed and level indicated significant error
1542 if (($Result === FALSE) && ($Level <= self::LOGLVL_ERROR))
1543 {
1544 # throw exception about inability to log error
1545 static $AlreadyThrewException = FALSE;
1546 if (!$AlreadyThrewException)
1547 {
1548 $AlreadyThrewException = TRUE;
1549 throw new Exception("Unable to log error (".$Level.": ".$Msg.").");
1550 }
1551 }
1552
1553 # report to caller whether message was logged
1554 return $Result;
1555 }
1556 else
1557 {
1558 # report to caller that message was not logged
1559 return FALSE;
1560 }
1561 }
1562
1574 function LogMessage($Level, $Msg)
1575 {
1576 # if message level is at or below current logging level
1577 if ($this->Settings["LoggingLevel"] >= $Level)
1578 {
1579 # attempt to open log file
1580 $FHndl = @fopen($this->LogFileName, "a");
1581
1582 # if log file could not be open
1583 if ($FHndl === FALSE)
1584 {
1585 # report to caller that message was not logged
1586 return FALSE;
1587 }
1588 else
1589 {
1590 # format log entry
1591 $ErrorAbbrevs = array(
1592 self::LOGLVL_FATAL => "FTL",
1593 self::LOGLVL_ERROR => "ERR",
1594 self::LOGLVL_WARNING => "WRN",
1595 self::LOGLVL_INFO => "INF",
1596 self::LOGLVL_DEBUG => "DBG",
1597 self::LOGLVL_TRACE => "TRC",
1598 );
1599 $LogEntry = date("Y-m-d H:i:s")
1600 ." ".($this->RunningInBackground ? "B" : "F")
1601 ." ".$ErrorAbbrevs[$Level]
1602 ." ".$Msg;
1603
1604 # write entry to log
1605 $Success = fwrite($FHndl, $LogEntry."\n");
1606
1607 # close log file
1608 fclose($FHndl);
1609
1610 # report to caller whether message was logged
1611 return ($Success === FALSE) ? FALSE : TRUE;
1612 }
1613 }
1614 else
1615 {
1616 # report to caller that message was not logged
1617 return FALSE;
1618 }
1619 }
1620
1642 function LoggingLevel($NewValue = DB_NOVALUE)
1643 {
1644 # constrain new level (if supplied) to within legal bounds
1645 if ($NewValue !== DB_NOVALUE)
1646 {
1647 $NewValue = max(min($NewValue, 6), 1);
1648 }
1649
1650 # set new logging level (if supplied) and return current level to caller
1651 return $this->UpdateSetting("LoggingLevel", $NewValue);
1652 }
1653
1660 function LogFile($NewValue = NULL)
1661 {
1662 if ($NewValue !== NULL) { $this->LogFileName = $NewValue; }
1663 return $this->LogFileName;
1664 }
1665
1670 const LOGLVL_TRACE = 6;
1675 const LOGLVL_DEBUG = 5;
1681 const LOGLVL_INFO = 4;
1686 const LOGLVL_WARNING = 3;
1692 const LOGLVL_ERROR = 2;
1697 const LOGLVL_FATAL = 1;
1698
1699 /*@)*/ /* Application Framework */
1700
1701 # ---- Event Handling ----------------------------------------------------
1702 /*@(*/
1704
1708 const EVENTTYPE_DEFAULT = 1;
1714 const EVENTTYPE_CHAIN = 2;
1720 const EVENTTYPE_FIRST = 3;
1728 const EVENTTYPE_NAMED = 4;
1729
1731 const ORDER_FIRST = 1;
1733 const ORDER_MIDDLE = 2;
1735 const ORDER_LAST = 3;
1736
1745 function RegisterEvent($EventsOrEventName, $EventType = NULL)
1746 {
1747 # convert parameters to array if not already in that form
1748 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1749 : array($EventsOrEventName => $Type);
1750
1751 # for each event
1752 foreach ($Events as $Name => $Type)
1753 {
1754 # store event information
1755 $this->RegisteredEvents[$Name]["Type"] = $Type;
1756 $this->RegisteredEvents[$Name]["Hooks"] = array();
1757 }
1758 }
1759
1766 function IsRegisteredEvent($EventName)
1767 {
1768 return array_key_exists($EventName, $this->RegisteredEvents)
1769 ? TRUE : FALSE;
1770 }
1771
1778 function IsHookedEvent($EventName)
1779 {
1780 # the event isn't hooked to if it isn't even registered
1781 if (!$this->IsRegisteredEvent($EventName))
1782 {
1783 return FALSE;
1784 }
1785
1786 # return TRUE if there is at least one callback hooked to the event
1787 return count($this->RegisteredEvents[$EventName]["Hooks"]) > 0;
1788 }
1789
1803 function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
1804 {
1805 # convert parameters to array if not already in that form
1806 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1807 : array($EventsOrEventName => $Callback);
1808
1809 # for each event
1810 $Success = TRUE;
1811 foreach ($Events as $EventName => $EventCallback)
1812 {
1813 # if callback is valid
1814 if (is_callable($EventCallback))
1815 {
1816 # if this is a periodic event we process internally
1817 if (isset($this->PeriodicEvents[$EventName]))
1818 {
1819 # process event now
1820 $this->ProcessPeriodicEvent($EventName, $EventCallback);
1821 }
1822 # if specified event has been registered
1823 elseif (isset($this->RegisteredEvents[$EventName]))
1824 {
1825 # add callback for event
1826 $this->RegisteredEvents[$EventName]["Hooks"][]
1827 = array("Callback" => $EventCallback, "Order" => $Order);
1828
1829 # sort callbacks by order
1830 if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
1831 {
1832 usort($this->RegisteredEvents[$EventName]["Hooks"],
1833 array("ApplicationFramework", "HookEvent_OrderCompare"));
1834 }
1835 }
1836 else
1837 {
1838 $Success = FALSE;
1839 }
1840 }
1841 else
1842 {
1843 $Success = FALSE;
1844 }
1845 }
1846
1847 # report to caller whether all callbacks were hooked
1848 return $Success;
1849 }
1851 private static function HookEvent_OrderCompare($A, $B)
1852 {
1853 if ($A["Order"] == $B["Order"]) { return 0; }
1854 return ($A["Order"] < $B["Order"]) ? -1 : 1;
1855 }
1856
1865 function SignalEvent($EventName, $Parameters = NULL)
1866 {
1867 $ReturnValue = NULL;
1868
1869 # if event has been registered
1870 if (isset($this->RegisteredEvents[$EventName]))
1871 {
1872 # set up default return value (if not NULL)
1873 switch ($this->RegisteredEvents[$EventName]["Type"])
1874 {
1875 case self::EVENTTYPE_CHAIN:
1876 $ReturnValue = $Parameters;
1877 break;
1878
1879 case self::EVENTTYPE_NAMED:
1880 $ReturnValue = array();
1881 break;
1882 }
1883
1884 # for each callback for this event
1885 foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
1886 {
1887 # invoke callback
1888 $Callback = $Hook["Callback"];
1889 $Result = ($Parameters !== NULL)
1890 ? call_user_func_array($Callback, $Parameters)
1891 : call_user_func($Callback);
1892
1893 # process return value based on event type
1894 switch ($this->RegisteredEvents[$EventName]["Type"])
1895 {
1896 case self::EVENTTYPE_CHAIN:
1897 if ($Result !== NULL)
1898 {
1899 foreach ($Parameters as $Index => $Value)
1900 {
1901 if (array_key_exists($Index, $Result))
1902 {
1903 $Parameters[$Index] = $Result[$Index];
1904 }
1905 }
1906 $ReturnValue = $Parameters;
1907 }
1908 break;
1909
1910 case self::EVENTTYPE_FIRST:
1911 if ($Result !== NULL)
1912 {
1913 $ReturnValue = $Result;
1914 break 2;
1915 }
1916 break;
1917
1918 case self::EVENTTYPE_NAMED:
1919 $CallbackName = is_array($Callback)
1920 ? (is_object($Callback[0])
1921 ? get_class($Callback[0])
1922 : $Callback[0])."::".$Callback[1]
1923 : $Callback;
1924 $ReturnValue[$CallbackName] = $Result;
1925 break;
1926
1927 default:
1928 break;
1929 }
1930 }
1931 }
1932 else
1933 {
1934 $this->LogError(self::LOGLVL_WARNING,
1935 "Unregistered event signaled (".$EventName.").");
1936 }
1937
1938 # return value if any to caller
1939 return $ReturnValue;
1940 }
1941
1947 function IsStaticOnlyEvent($EventName)
1948 {
1949 return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
1950 }
1951
1962 function EventWillNextRunAt($EventName, $Callback)
1963 {
1964 # if event is not a periodic event report failure to caller
1965 if (!array_key_exists($EventName, $this->EventPeriods)) { return FALSE; }
1966
1967 # retrieve last execution time for event if available
1968 $Signature = self::GetCallbackSignature($Callback);
1969 $LastRunTime = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
1970 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
1971
1972 # if event was not found report failure to caller
1973 if ($LastRunTime === NULL) { return FALSE; }
1974
1975 # calculate next run time based on event period
1976 $NextRunTime = strtotime($LastRunTime) + $this->EventPeriods[$EventName];
1977
1978 # report next run time to caller
1979 return $NextRunTime;
1980 }
1981
1997 function GetKnownPeriodicEvents()
1998 {
1999 # retrieve last execution times
2000 $this->DB->Query("SELECT * FROM PeriodicEvents");
2001 $LastRunTimes = $this->DB->FetchColumn("LastRunAt", "Signature");
2002
2003 # for each known event
2004 $Events = array();
2005 foreach ($this->KnownPeriodicEvents as $Signature => $Info)
2006 {
2007 # if last run time for event is available
2008 if (array_key_exists($Signature, $LastRunTimes))
2009 {
2010 # calculate next run time for event
2011 $LastRun = strtotime($LastRunTimes[$Signature]);
2012 $NextRun = $LastRun + $this->EventPeriods[$Info["Period"]];
2013 if ($Info["Period"] == "EVENT_PERIODIC") { $LastRun = FALSE; }
2014 }
2015 else
2016 {
2017 # set info to indicate run times are not known
2018 $LastRun = FALSE;
2019 $NextRun = FALSE;
2020 }
2021
2022 # add event info to list
2023 $Events[$Signature] = $Info;
2024 $Events[$Signature]["LastRun"] = $LastRun;
2025 $Events[$Signature]["NextRun"] = $NextRun;
2026 $Events[$Signature]["Parameters"] = NULL;
2027 }
2028
2029 # return list of known events to caller
2030 return $Events;
2031 }
2032
2033 /*@)*/ /* Event Handling */
2034
2035 # ---- Task Management ---------------------------------------------------
2036 /*@(*/
2038
2040 const PRIORITY_HIGH = 1;
2042 const PRIORITY_MEDIUM = 2;
2044 const PRIORITY_LOW = 3;
2046 const PRIORITY_BACKGROUND = 4;
2047
2060 function QueueTask($Callback, $Parameters = NULL,
2061 $Priority = self::PRIORITY_LOW, $Description = "")
2062 {
2063 # pack task info and write to database
2064 if ($Parameters === NULL) { $Parameters = array(); }
2065 $this->DB->Query("INSERT INTO TaskQueue"
2066 ." (Callback, Parameters, Priority, Description)"
2067 ." VALUES ('".addslashes(serialize($Callback))."', '"
2068 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
2069 .addslashes($Description)."')");
2070 }
2071
2089 function QueueUniqueTask($Callback, $Parameters = NULL,
2090 $Priority = self::PRIORITY_LOW, $Description = "")
2091 {
2092 if ($this->TaskIsInQueue($Callback, $Parameters))
2093 {
2094 $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
2095 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
2096 .($Parameters ? " AND Parameters = '"
2097 .addslashes(serialize($Parameters))."'" : ""));
2098 if ($QueryResult !== FALSE)
2099 {
2100 $Record = $this->DB->FetchRow();
2101 if ($Record["Priority"] > $Priority)
2102 {
2103 $this->DB->Query("UPDATE TaskQueue"
2104 ." SET Priority = ".intval($Priority)
2105 ." WHERE TaskId = ".intval($Record["TaskId"]));
2106 }
2107 }
2108 return FALSE;
2109 }
2110 else
2111 {
2112 $this->QueueTask($Callback, $Parameters, $Priority, $Description);
2113 return TRUE;
2114 }
2115 }
2116
2126 function TaskIsInQueue($Callback, $Parameters = NULL)
2127 {
2128 $QueuedCount = $this->DB->Query(
2129 "SELECT COUNT(*) AS FoundCount FROM TaskQueue"
2130 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
2131 .($Parameters ? " AND Parameters = '"
2132 .addslashes(serialize($Parameters))."'" : ""),
2133 "FoundCount");
2134 $RunningCount = $this->DB->Query(
2135 "SELECT COUNT(*) AS FoundCount FROM RunningTasks"
2136 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
2137 .($Parameters ? " AND Parameters = '"
2138 .addslashes(serialize($Parameters))."'" : ""),
2139 "FoundCount");
2140 $FoundCount = $QueuedCount + $RunningCount;
2141 return ($FoundCount ? TRUE : FALSE);
2142 }
2143
2149 function GetTaskQueueSize($Priority = NULL)
2150 {
2151 return $this->GetQueuedTaskCount(NULL, NULL, $Priority);
2152 }
2153
2161 function GetQueuedTaskList($Count = 100, $Offset = 0)
2162 {
2163 return $this->GetTaskList("SELECT * FROM TaskQueue"
2164 ." ORDER BY Priority, TaskId ", $Count, $Offset);
2165 }
2166
2180 function GetQueuedTaskCount($Callback = NULL,
2181 $Parameters = NULL, $Priority = NULL, $Description = NULL)
2182 {
2183 $Query = "SELECT COUNT(*) AS TaskCount FROM TaskQueue";
2184 $Sep = " WHERE";
2185 if ($Callback !== NULL)
2186 {
2187 $Query .= $Sep." Callback = '".addslashes(serialize($Callback))."'";
2188 $Sep = " AND";
2189 }
2190 if ($Parameters !== NULL)
2191 {
2192 $Query .= $Sep." Parameters = '".addslashes(serialize($Parameters))."'";
2193 $Sep = " AND";
2194 }
2195 if ($Priority !== NULL)
2196 {
2197 $Query .= $Sep." Priority = ".intval($Priority);
2198 $Sep = " AND";
2199 }
2200 if ($Description !== NULL)
2201 {
2202 $Query .= $Sep." Description = '".addslashes($Description)."'";
2203 }
2204 return $this->DB->Query($Query, "TaskCount");
2205 }
2206
2214 function GetRunningTaskList($Count = 100, $Offset = 0)
2215 {
2216 return $this->GetTaskList("SELECT * FROM RunningTasks"
2217 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
2218 (time() - ini_get("max_execution_time")))."'"
2219 ." ORDER BY StartedAt", $Count, $Offset);
2220 }
2221
2229 function GetOrphanedTaskList($Count = 100, $Offset = 0)
2230 {
2231 return $this->GetTaskList("SELECT * FROM RunningTasks"
2232 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
2233 (time() - ini_get("max_execution_time")))."'"
2234 ." ORDER BY StartedAt", $Count, $Offset);
2235 }
2236
2241 function GetOrphanedTaskCount()
2242 {
2243 return $this->DB->Query("SELECT COUNT(*) AS Count FROM RunningTasks"
2244 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
2245 (time() - ini_get("max_execution_time")))."'",
2246 "Count");
2247 }
2248
2254 function ReQueueOrphanedTask($TaskId, $NewPriority = NULL)
2255 {
2256 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
2257 $this->DB->Query("INSERT INTO TaskQueue"
2258 ." (Callback,Parameters,Priority,Description) "
2259 ."SELECT Callback, Parameters, Priority, Description"
2260 ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2261 if ($NewPriority !== NULL)
2262 {
2263 $NewTaskId = $this->DB->LastInsertId();
2264 $this->DB->Query("UPDATE TaskQueue SET Priority = "
2265 .intval($NewPriority)
2266 ." WHERE TaskId = ".intval($NewTaskId));
2267 }
2268 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2269 $this->DB->Query("UNLOCK TABLES");
2270 }
2271
2276 function DeleteTask($TaskId)
2277 {
2278 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2279 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2280 }
2281
2289 function GetTask($TaskId)
2290 {
2291 # assume task will not be found
2292 $Task = NULL;
2293
2294 # look for task in task queue
2295 $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2296
2297 # if task was not found in queue
2298 if (!$this->DB->NumRowsSelected())
2299 {
2300 # look for task in running task list
2301 $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = "
2302 .intval($TaskId));
2303 }
2304
2305 # if task was found
2306 if ($this->DB->NumRowsSelected())
2307 {
2308 # if task was periodic
2309 $Row = $this->DB->FetchRow();
2310 if ($Row["Callback"] ==
2311 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
2312 {
2313 # unpack periodic task callback
2314 $WrappedCallback = unserialize($Row["Parameters"]);
2315 $Task["Callback"] = $WrappedCallback[1];
2316 $Task["Parameters"] = $WrappedCallback[2];
2317 }
2318 else
2319 {
2320 # unpack task callback and parameters
2321 $Task["Callback"] = unserialize($Row["Callback"]);
2322 $Task["Parameters"] = unserialize($Row["Parameters"]);
2323 }
2324 }
2325
2326 # return task to caller
2327 return $Task;
2328 }
2329
2337 function TaskExecutionEnabled($NewValue = DB_NOVALUE)
2338 {
2339 return $this->UpdateSetting("TaskExecutionEnabled", $NewValue);
2340 }
2341
2347 function MaxTasks($NewValue = DB_NOVALUE)
2348 {
2349 return $this->UpdateSetting("MaxTasksRunning", $NewValue);
2350 }
2351
2359 function MaxExecutionTime($NewValue = NULL)
2360 {
2361 if (func_num_args() && !ini_get("safe_mode"))
2362 {
2363 if ($NewValue != $this->Settings["MaxExecTime"])
2364 {
2365 $this->Settings["MaxExecTime"] = max($NewValue, 5);
2366 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2367 ." SET MaxExecTime = '"
2368 .intval($this->Settings["MaxExecTime"])."'");
2369 }
2370 ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
2371 set_time_limit($this->Settings["MaxExecTime"]);
2372 }
2373 return ini_get("max_execution_time");
2374 }
2375
2376 /*@)*/ /* Task Management */
2377
2378 # ---- Backward Compatibility --------------------------------------------
2379 /*@(*/
2381
2386 function FindCommonTemplate($BaseName)
2387 {
2388 return $this->FindFile(
2389 $this->IncludeDirList, $BaseName, array("tpl", "html"));
2390 }
2391
2392 /*@)*/ /* Backward Compatibility */
2393
2394
2395 # ---- PRIVATE INTERFACE -------------------------------------------------
2396
2397 private $ActiveUI = "default";
2398 private $BrowserDetectFunc;
2399 private $CleanUrlMappings = array();
2400 private $CleanUrlRewritePerformed = FALSE;
2401 private $DB;
2402 private $DefaultPage = "Home";
2403 private $EnvIncludes = array();
2404 private $ExecutionStartTime;
2405 private $FoundUIFiles = array();
2406 private $AdditionalRequiredUIFiles = array();
2407 private $HtmlCharset = "UTF-8";
2408 private $JumpToPage = NULL;
2409 private $LogFileName = "local/logs/site.log";
2410 private $MaxRunningTasksToTrack = 250;
2411 private $OutputModificationPatterns = array();
2412 private $OutputModificationReplacements = array();
2413 private $OutputModificationCallbacks = array();
2414 private $OutputModificationCallbackInfo;
2415 private $PageName;
2416 private $PostProcessingFuncs = array();
2417 private $RunningInBackground = FALSE;
2418 private $RunningTask;
2419 private $Settings;
2420 private $SuppressHTML = FALSE;
2421 private $SaveTemplateLocationCache = FALSE;
2422 private $UnbufferedCallbacks = array();
2423 private $UseBaseTag = FALSE;
2424 private $UseMinimizedJavascript = FALSE;
2425
2426 private static $AppName = "ScoutAF";
2427 private static $ObjectDirectories = array();
2428 private static $ObjectLocationCache;
2429 private static $ObjectLocationCacheInterval = 60;
2430 private static $ObjectLocationCacheExpiration;
2431 private static $SaveObjectLocationCache = FALSE;
2432 private static $SessionLifetime = 1440;
2433
2438 private $NoTSR = FALSE;
2439
2440 private $KnownPeriodicEvents = array();
2441 private $PeriodicEvents = array(
2442 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
2443 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
2444 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
2445 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
2446 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
2447 );
2448 private $EventPeriods = array(
2449 "EVENT_HOURLY" => 3600,
2450 "EVENT_DAILY" => 86400,
2451 "EVENT_WEEKLY" => 604800,
2452 "EVENT_MONTHLY" => 2592000,
2453 "EVENT_PERIODIC" => 0,
2454 );
2455 private $UIEvents = array(
2456 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
2457 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2458 "EVENT_PHP_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2459 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2460 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2461 "EVENT_PAGE_OUTPUT_FILTER" => self::EVENTTYPE_CHAIN,
2462 );
2463
2467 private function LoadSettings()
2468 {
2469 # read settings in from database
2470 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2471 $this->Settings = $this->DB->FetchRow();
2472
2473 # if settings were not previously initialized
2474 if (!$this->Settings)
2475 {
2476 # initialize settings in database
2477 $this->DB->Query("INSERT INTO ApplicationFrameworkSettings"
2478 ." (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')");
2479
2480 # read new settings in from database
2481 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2482 $this->Settings = $this->DB->FetchRow();
2483 }
2484
2485 # if base path was not previously set or we appear to have moved
2486 if (!array_key_exists("BasePath", $this->Settings)
2487 || (!strlen($this->Settings["BasePath"]))
2488 || (!array_key_exists("BasePathCheck", $this->Settings))
2489 || (__FILE__ != $this->Settings["BasePathCheck"]))
2490 {
2491 # attempt to extract base path from Apache .htaccess file
2492 if (is_readable(".htaccess"))
2493 {
2494 $Lines = file(".htaccess");
2495 foreach ($Lines as $Line)
2496 {
2497 if (preg_match("/\\s*RewriteBase\\s+/", $Line))
2498 {
2499 $Pieces = preg_split(
2500 "/\\s+/", $Line, NULL, PREG_SPLIT_NO_EMPTY);
2501 $BasePath = $Pieces[1];
2502 }
2503 }
2504 }
2505
2506 # if base path was found
2507 if (isset($BasePath))
2508 {
2509 # save base path locally
2510 $this->Settings["BasePath"] = $BasePath;
2511
2512 # save base path to database
2513 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2514 ." SET BasePath = '".addslashes($BasePath)."'"
2515 .", BasePathCheck = '".addslashes(__FILE__)."'");
2516 }
2517 }
2518
2519 # if template location cache has been saved to database
2520 if (isset($this->Settings["TemplateLocationCache"]))
2521 {
2522 # unserialize cache values into array and use if valid
2523 $Cache = unserialize($this->Settings["TemplateLocationCache"]);
2524 $this->Settings["TemplateLocationCache"] =
2525 count($Cache) ? $Cache : array();
2526 }
2527 else
2528 {
2529 # start with empty cache
2530 $this->Settings["TemplateLocationCache"] = array();
2531 }
2532
2533 # if object location cache has been saved to database
2534 if (isset($this->Settings["ObjectLocationCache"]))
2535 {
2536 # unserialize cache values into array and use if valid
2537 $Cache = unserialize($this->Settings["ObjectLocationCache"]);
2538 $this->Settings["ObjectLocationCache"] =
2539 count($Cache) ? $Cache : array();
2540
2541 # store static versions for use when autoloading objects
2542 self::$ObjectLocationCache =
2543 $this->Settings["ObjectLocationCache"];
2544 self::$ObjectLocationCacheInterval =
2545 $this->Settings["ObjectLocationCacheInterval"];
2546 self::$ObjectLocationCacheExpiration =
2547 $this->Settings["ObjectLocationCacheExpiration"];
2548 }
2549 else
2550 {
2551 # start with empty cache
2552 $this->Settings["ObjectLocationCache"] = array();
2553 }
2554 }
2555
2562 private function RewriteCleanUrls($PageName)
2563 {
2564 # if URL rewriting is supported by the server
2565 if ($this->HtaccessSupport())
2566 {
2567 # retrieve current URL and remove base path if present
2568 $Url = $this->GetPageLocation();
2569
2570 # for each clean URL mapping
2571 foreach ($this->CleanUrlMappings as $Info)
2572 {
2573 # if current URL matches clean URL pattern
2574 if (preg_match($Info["Pattern"], $Url, $Matches))
2575 {
2576 # set new page
2577 $PageName = $Info["Page"];
2578
2579 # if $_GET variables specified for clean URL
2580 if ($Info["GetVars"] !== NULL)
2581 {
2582 # for each $_GET variable specified for clean URL
2583 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
2584 {
2585 # start with template for variable value
2586 $Value = $VarTemplate;
2587
2588 # for each subpattern matched in current URL
2589 foreach ($Matches as $Index => $Match)
2590 {
2591 # if not first (whole) match
2592 if ($Index > 0)
2593 {
2594 # make any substitutions in template
2595 $Value = str_replace("$".$Index, $Match, $Value);
2596 }
2597 }
2598
2599 # set $_GET variable
2600 $_GET[$VarName] = $Value;
2601 }
2602 }
2603
2604 # set flag indicating clean URL mapped
2605 $this->CleanUrlRewritePerformed = TRUE;
2606
2607 # stop looking for a mapping
2608 break;
2609 }
2610 }
2611 }
2612
2613 # return (possibly) updated page name to caller
2614 return $PageName;
2615 }
2616
2633 private function FindFile($DirectoryList, $BaseName,
2634 $PossibleSuffixes = NULL, $PossiblePrefixes = NULL)
2635 {
2636 # generate template cache index for this page
2637 $CacheIndex = md5(serialize($DirectoryList))
2638 .":".$this->ActiveUI.":".$BaseName;
2639
2640 # if we have cached location and cache expiration time has not elapsed
2641 if (($this->Settings["TemplateLocationCacheInterval"] > 0)
2642 && count($this->Settings["TemplateLocationCache"])
2643 && array_key_exists($CacheIndex,
2644 $this->Settings["TemplateLocationCache"])
2645 && (time() < strtotime(
2646 $this->Settings["TemplateLocationCacheExpiration"])))
2647 {
2648 # use template location from cache
2649 $FoundFileName = $this->Settings[
2650 "TemplateLocationCache"][$CacheIndex];
2651 }
2652 else
2653 {
2654 # if suffixes specified and base name does not include suffix
2655 if (count($PossibleSuffixes)
2656 && !preg_match("/\.[a-zA-Z0-9]+$/", $BaseName))
2657 {
2658 # add versions of file names with suffixes to file name list
2659 $FileNames = array();
2660 foreach ($PossibleSuffixes as $Suffix)
2661 {
2662 $FileNames[] = $BaseName.".".$Suffix;
2663 }
2664 }
2665 else
2666 {
2667 # use base name as file name
2668 $FileNames = array($BaseName);
2669 }
2670
2671 # if prefixes specified
2672 if (count($PossiblePrefixes))
2673 {
2674 # add versions of file names with prefixes to file name list
2675 $NewFileNames = array();
2676 foreach ($FileNames as $FileName)
2677 {
2678 foreach ($PossiblePrefixes as $Prefix)
2679 {
2680 $NewFileNames[] = $Prefix.$FileName;
2681 }
2682 }
2683 $FileNames = $NewFileNames;
2684 }
2685
2686 # for each possible location
2687 $FoundFileName = NULL;
2688 foreach ($DirectoryList as $Dir)
2689 {
2690 # substitute active UI name into path
2691 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
2692
2693 # for each possible file name
2694 foreach ($FileNames as $File)
2695 {
2696 # if template is found at location
2697 if (file_exists($Dir.$File))
2698 {
2699 # save full template file name and stop looking
2700 $FoundFileName = $Dir.$File;
2701 break 2;
2702 }
2703 }
2704 }
2705
2706 # save location in cache
2707 $this->Settings["TemplateLocationCache"][$CacheIndex]
2708 = $FoundFileName;
2709
2710 # set flag indicating that cache should be saved
2711 $this->SaveTemplateLocationCache = TRUE;
2712 }
2713
2714 # return full template file name to caller
2715 return $FoundFileName;
2716 }
2717
2724 private function GetRequiredFilesNotYetLoaded($PageContentFile)
2725 {
2726 # start out assuming no files required
2727 $RequiredFiles = array();
2728
2729 # if page content file supplied
2730 if ($PageContentFile)
2731 {
2732 # if file containing list of required files is available
2733 $Path = dirname($PageContentFile);
2734 $RequireListFile = $Path."/REQUIRES";
2735 if (file_exists($RequireListFile))
2736 {
2737 # read in list of required files
2738 $RequestedFiles = file($RequireListFile);
2739
2740 # for each line in required file list
2741 foreach ($RequestedFiles as $Line)
2742 {
2743 # if line is not a comment
2744 $Line = trim($Line);
2745 if (!preg_match("/^#/", $Line))
2746 {
2747 # if file has not already been loaded
2748 if (!in_array($Line, $this->FoundUIFiles))
2749 {
2750 # add to list of required files
2751 $RequiredFiles[] = $Line;
2752 }
2753 }
2754 }
2755 }
2756 }
2757
2758 # add in additional required files if any
2759 if (count($this->AdditionalRequiredUIFiles))
2760 {
2761 # make sure there are no duplicates
2762 $AdditionalRequiredUIFiles = array_unique(
2763 $this->AdditionalRequiredUIFiles);
2764
2765 $RequiredFiles = array_merge(
2766 $RequiredFiles, $AdditionalRequiredUIFiles);
2767 }
2768
2769 # return list of required files to caller
2770 return $RequiredFiles;
2771 }
2772
2776 private function SetUpObjectAutoloading()
2777 {
2779 function __autoload($ClassName)
2780 {
2781 ApplicationFramework::AutoloadObjects($ClassName);
2782 }
2783 }
2784
2790 static function AutoloadObjects($ClassName)
2791 {
2792 # if caching is not turned off
2793 # and we have a cached location for class
2794 # and cache expiration has not elapsed
2795 # and file at cached location is readable
2796 if ((self::$ObjectLocationCacheInterval > 0)
2797 && count(self::$ObjectLocationCache)
2798 && array_key_exists($ClassName,
2799 self::$ObjectLocationCache)
2800 && (time() < strtotime(
2801 self::$ObjectLocationCacheExpiration))
2802 && is_readable(self::$ObjectLocationCache[$ClassName]))
2803 {
2804 # use object location from cache
2805 require_once(self::$ObjectLocationCache[$ClassName]);
2806 }
2807 else
2808 {
2809 # for each possible object file directory
2810 static $FileLists;
2811 foreach (self::$ObjectDirectories as $Location => $Info)
2812 {
2813 # if directory looks valid
2814 if (is_dir($Location))
2815 {
2816 # build class file name
2817 $NewClassName = ($Info["ClassPattern"] && $Info["ClassReplacement"])
2818 ? preg_replace($Info["ClassPattern"],
2819 $Info["ClassReplacement"], $ClassName)
2820 : $ClassName;
2821
2822 # read in directory contents if not already retrieved
2823 if (!isset($FileLists[$Location]))
2824 {
2825 $FileLists[$Location] = self::ReadDirectoryTree(
2826 $Location, '/^.+\.php$/i');
2827 }
2828
2829 # for each file in target directory
2830 $FileNames = $FileLists[$Location];
2831 $TargetName = strtolower($Info["Prefix"].$NewClassName.".php");
2832 foreach ($FileNames as $FileName)
2833 {
2834 # if file matches our target object file name
2835 if (strtolower($FileName) == $TargetName)
2836 {
2837 # include object file
2838 require_once($Location.$FileName);
2839
2840 # save location to cache
2841 self::$ObjectLocationCache[$ClassName]
2842 = $Location.$FileName;
2843
2844 # set flag indicating that cache should be saved
2845 self::$SaveObjectLocationCache = TRUE;
2846
2847 # stop looking
2848 break 2;
2849 }
2850 }
2851 }
2852 }
2853 }
2854 }
2855
2863 private static function ReadDirectoryTree($Directory, $Pattern)
2864 {
2865 $CurrentDir = getcwd();
2866 chdir($Directory);
2867 $DirIter = new RecursiveDirectoryIterator(".");
2868 $IterIter = new RecursiveIteratorIterator($DirIter);
2869 $RegexResults = new RegexIterator($IterIter, $Pattern,
2870 RecursiveRegexIterator::GET_MATCH);
2871 $FileList = array();
2872 foreach ($RegexResults as $Result)
2873 {
2874 $FileList[] = substr($Result[0], 2);
2875 }
2876 chdir($CurrentDir);
2877 return $FileList;
2878 }
2884 private function UndoMagicQuotes()
2885 {
2886 # if this PHP version has magic quotes support
2887 if (version_compare(PHP_VERSION, "5.4.0", "<"))
2888 {
2889 # turn off runtime magic quotes if on
2890 if (get_magic_quotes_runtime())
2891 {
2892 set_magic_quotes_runtime(FALSE);
2893 }
2894
2895 # if magic quotes GPC is on
2896 if (get_magic_quotes_gpc())
2897 {
2898 # strip added slashes from incoming variables
2899 $GPC = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
2900 array_walk_recursive($GPC,
2901 array($this, "UndoMagicQuotes_StripCallback"));
2902 }
2903 }
2904 }
2905 private function UndoMagicQuotes_StripCallback(&$Value, $Key)
2906 {
2907 $Value = stripslashes($Value);
2908 }
2909
2914 private function LoadUIFunctions()
2915 {
2916 $Dirs = array(
2917 "local/interface/%ACTIVEUI%/include",
2918 "interface/%ACTIVEUI%/include",
2919 "local/interface/default/include",
2920 "interface/default/include",
2921 );
2922 foreach ($Dirs as $Dir)
2923 {
2924 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
2925 if (is_dir($Dir))
2926 {
2927 $FileNames = scandir($Dir);
2928 foreach ($FileNames as $FileName)
2929 {
2930 if (preg_match("/^F-([A-Za-z0-9_]+)\.php/", $FileName, $Matches)
2931 || preg_match("/^F-([A-Za-z0-9_]+)\.html/", $FileName, $Matches))
2932 {
2933 if (!function_exists($Matches[1]))
2934 {
2935 include_once($Dir."/".$FileName);
2936 }
2937 }
2938 }
2939 }
2940 }
2941 }
2942
2948 private function ProcessPeriodicEvent($EventName, $Callback)
2949 {
2950 # retrieve last execution time for event if available
2951 $Signature = self::GetCallbackSignature($Callback);
2952 $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
2953 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
2954
2955 # determine whether enough time has passed for event to execute
2956 $ShouldExecute = (($LastRun === NULL)
2957 || (time() > (strtotime($LastRun) + $this->EventPeriods[$EventName])))
2958 ? TRUE : FALSE;
2959
2960 # if event should run
2961 if ($ShouldExecute)
2962 {
2963 # add event to task queue
2964 $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
2965 $WrapperParameters = array(
2966 $EventName, $Callback, array("LastRunAt" => $LastRun));
2967 $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
2968 }
2969
2970 # add event to list of periodic events
2971 $this->KnownPeriodicEvents[$Signature] = array(
2972 "Period" => $EventName,
2973 "Callback" => $Callback,
2974 "Queued" => $ShouldExecute);
2975 }
2976
2984 private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
2985 {
2986 static $DB;
2987 if (!isset($DB)) { $DB = new Database(); }
2988
2989 # run event
2990 $ReturnVal = call_user_func_array($Callback, $Parameters);
2991
2992 # if event is already in database
2993 $Signature = self::GetCallbackSignature($Callback);
2994 if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
2995 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
2996 {
2997 # update last run time for event
2998 $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
2999 .(($EventName == "EVENT_PERIODIC")
3000 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
3001 : "NOW()")
3002 ." WHERE Signature = '".addslashes($Signature)."'");
3003 }
3004 else
3005 {
3006 # add last run time for event to database
3007 $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
3008 ."('".addslashes($Signature)."', "
3009 .(($EventName == "EVENT_PERIODIC")
3010 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
3011 : "NOW()").")");
3012 }
3013 }
3014
3020 private static function GetCallbackSignature($Callback)
3021 {
3022 return !is_array($Callback) ? $Callback
3023 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
3024 ."::".$Callback[1];
3025 }
3026
3031 private function PrepForTSR()
3032 {
3033 # if HTML has been output and it's time to launch another task
3034 # (only TSR if HTML has been output because otherwise browsers
3035 # may misbehave after connection is closed)
3036 if (($this->JumpToPage || !$this->SuppressHTML)
3037 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
3038 + (ini_get("max_execution_time")
3039 / $this->Settings["MaxTasksRunning"]) + 5))
3040 && $this->GetTaskQueueSize()
3041 && $this->Settings["TaskExecutionEnabled"])
3042 {
3043 # begin buffering output for TSR
3044 ob_start();
3045
3046 # let caller know it is time to launch another task
3047 return TRUE;
3048 }
3049 else
3050 {
3051 # let caller know it is not time to launch another task
3052 return FALSE;
3053 }
3054 }
3055
3060 private function LaunchTSR()
3061 {
3062 # set headers to close out connection to browser
3063 if (!$this->NoTSR)
3064 {
3065 ignore_user_abort(TRUE);
3066 header("Connection: close");
3067 header("Content-Length: ".ob_get_length());
3068 }
3069
3070 # output buffered content
3071 while (ob_get_level()) { ob_end_flush(); }
3072 flush();
3073
3074 # write out any outstanding data and end HTTP session
3075 session_write_close();
3076
3077 # set flag indicating that we are now running in background
3078 $this->RunningInBackground = TRUE;
3079
3080 # if there is still a task in the queue
3081 if ($this->GetTaskQueueSize())
3082 {
3083 # turn on output buffering to (hopefully) record any crash output
3084 ob_start();
3085
3086 # lock tables and grab last task run time to double check
3087 $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
3088 $this->LoadSettings();
3089
3090 # if still time to launch another task
3091 if (time() > (strtotime($this->Settings["LastTaskRunAt"])
3092 + (ini_get("max_execution_time")
3093 / $this->Settings["MaxTasksRunning"]) + 5))
3094 {
3095 # update the "last run" time and release tables
3096 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
3097 ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
3098 $this->DB->Query("UNLOCK TABLES");
3099
3100 # run tasks while there is a task in the queue and enough time left
3101 do
3102 {
3103 # run the next task
3104 $this->RunNextTask();
3105 }
3106 while ($this->GetTaskQueueSize()
3107 && ($this->GetSecondsBeforeTimeout() > 65));
3108 }
3109 else
3110 {
3111 # release tables
3112 $this->DB->Query("UNLOCK TABLES");
3113 }
3114 }
3115 }
3116
3124 private function GetTaskList($DBQuery, $Count, $Offset)
3125 {
3126 $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
3127 $Tasks = array();
3128 while ($Row = $this->DB->FetchRow())
3129 {
3130 $Tasks[$Row["TaskId"]] = $Row;
3131 if ($Row["Callback"] ==
3132 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
3133 {
3134 $WrappedCallback = unserialize($Row["Parameters"]);
3135 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
3136 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
3137 }
3138 else
3139 {
3140 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
3141 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
3142 }
3143 }
3144 return $Tasks;
3145 }
3146
3150 private function RunNextTask()
3151 {
3152 # lock tables to prevent same task from being run by multiple sessions
3153 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
3154
3155 # look for task at head of queue
3156 $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
3157 $Task = $this->DB->FetchRow();
3158
3159 # if there was a task available
3160 if ($Task)
3161 {
3162 # move task from queue to running tasks list
3163 $this->DB->Query("INSERT INTO RunningTasks "
3164 ."(TaskId,Callback,Parameters,Priority,Description) "
3165 ."SELECT * FROM TaskQueue WHERE TaskId = "
3166 .intval($Task["TaskId"]));
3167 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
3168 .intval($Task["TaskId"]));
3169
3170 # release table locks to again allow other sessions to run tasks
3171 $this->DB->Query("UNLOCK TABLES");
3172
3173 # unpack stored task info
3174 $Callback = unserialize($Task["Callback"]);
3175 $Parameters = unserialize($Task["Parameters"]);
3176
3177 # attempt to load task callback if not already available
3178 $this->LoadFunction($Callback);
3179
3180 # run task
3181 $this->RunningTask = $Task;
3182 if ($Parameters)
3183 {
3184 call_user_func_array($Callback, $Parameters);
3185 }
3186 else
3187 {
3188 call_user_func($Callback);
3189 }
3190 unset($this->RunningTask);
3191
3192 # remove task from running tasks list
3193 $this->DB->Query("DELETE FROM RunningTasks"
3194 ." WHERE TaskId = ".intval($Task["TaskId"]));
3195
3196 # prune running tasks list if necessary
3197 $RunningTasksCount = $this->DB->Query(
3198 "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
3199 if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
3200 {
3201 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
3202 ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
3203 }
3204 }
3205 else
3206 {
3207 # release table locks to again allow other sessions to run tasks
3208 $this->DB->Query("UNLOCK TABLES");
3209 }
3210 }
3211
3217 function OnCrash()
3218 {
3219 if (isset($this->RunningTask))
3220 {
3221 if (function_exists("error_get_last"))
3222 {
3223 $CrashInfo["LastError"] = error_get_last();
3224 }
3225 if (ob_get_length() !== FALSE)
3226 {
3227 $CrashInfo["OutputBuffer"] = ob_get_contents();
3228 }
3229 if (isset($CrashInfo))
3230 {
3231 $DB = new Database();
3232 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
3233 .addslashes(serialize($CrashInfo))
3234 ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
3235 }
3236 }
3237
3238 print("\n");
3239 return;
3240 }
3241
3258 private function AddToDirList($DirList, $Dir, $SearchLast, $SkipSlashCheck)
3259 {
3260 # convert incoming directory to array of directories (if needed)
3261 $Dirs = is_array($Dir) ? $Dir : array($Dir);
3262
3263 # reverse array so directories are searched in specified order
3264 $Dirs = array_reverse($Dirs);
3265
3266 # for each directory
3267 foreach ($Dirs as $Location)
3268 {
3269 # make sure directory includes trailing slash
3270 if (!$SkipSlashCheck)
3271 {
3272 $Location = $Location
3273 .((substr($Location, -1) != "/") ? "/" : "");
3274 }
3275
3276 # remove directory from list if already present
3277 if (in_array($Location, $DirList))
3278 {
3279 $DirList = array_diff(
3280 $DirList, array($Location));
3281 }
3282
3283 # add directory to list of directories
3284 if ($SearchLast)
3285 {
3286 array_push($DirList, $Location);
3287 }
3288 else
3289 {
3290 array_unshift($DirList, $Location);
3291 }
3292 }
3293
3294 # return updated directory list to caller
3295 return $DirList;
3296 }
3297
3305 private function ArrayPermutations($Items, $Perms = array())
3306 {
3307 if (empty($Items))
3308 {
3309 $Result = array($Perms);
3310 }
3311 else
3312 {
3313 $Result = array();
3314 for ($Index = count($Items) - 1; $Index >= 0; --$Index)
3315 {
3316 $NewItems = $Items;
3317 $NewPerms = $Perms;
3318 list($Segment) = array_splice($NewItems, $Index, 1);
3319 array_unshift($NewPerms, $Segment);
3320 $Result = array_merge($Result,
3321 $this->ArrayPermutations($NewItems, $NewPerms));
3322 }
3323 }
3324 return $Result;
3325 }
3326
3333 private function OutputModificationCallbackShell($Matches)
3334 {
3335 # call previously-stored external function
3336 return call_user_func($this->OutputModificationCallbackInfo["Callback"],
3337 $Matches,
3338 $this->OutputModificationCallbackInfo["Pattern"],
3339 $this->OutputModificationCallbackInfo["Page"],
3340 $this->OutputModificationCallbackInfo["SearchPattern"]);
3341 }
3342
3349 function UpdateSetting($FieldName, $NewValue = DB_NOVALUE)
3350 {
3351 return $this->DB->UpdateValue("ApplicationFrameworkSettings",
3352 $FieldName, $NewValue, NULL, $this->Settings);
3353 }
3354
3356 private $InterfaceDirList = array(
3357 "local/interface/%ACTIVEUI%/",
3358 "interface/%ACTIVEUI%/",
3359 "local/interface/default/",
3360 "interface/default/",
3361 );
3366 private $IncludeDirList = array(
3367 "local/interface/%ACTIVEUI%/include/",
3368 "interface/%ACTIVEUI%/include/",
3369 "local/interface/default/include/",
3370 "interface/default/include/",
3371 );
3373 private $ImageDirList = array(
3374 "local/interface/%ACTIVEUI%/images/",
3375 "interface/%ACTIVEUI%/images/",
3376 "local/interface/default/images/",
3377 "interface/default/images/",
3378 );
3380 private $FunctionDirList = array(
3381 "local/interface/%ACTIVEUI%/include/",
3382 "interface/%ACTIVEUI%/include/",
3383 "local/interface/default/include/",
3384 "interface/default/include/",
3385 "local/include/",
3386 "include/",
3387 );
3388
3389 const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
3390 };
ApplicationFramework\MaxTasks
MaxTasks($NewValue=DB_NOVALUE)
Get/set maximum number of tasks to have running simultaneously.
Definition: ApplicationFramework.php:2347
ApplicationFramework\LOGLVL_ERROR
const LOGLVL_ERROR
ERROR error logging level.
Definition: ApplicationFramework.php:1692
ApplicationFramework\GetOrphanedTaskList
GetOrphanedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:2229
ApplicationFramework\SuppressHTMLOutput
SuppressHTMLOutput($NewSetting=TRUE)
Suppress loading of HTML files.
Definition: ApplicationFramework.php:1100
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&#39;t set...
Definition: ApplicationFramework.php:1467
ApplicationFramework\LOGLVL_INFO
const LOGLVL_INFO
INFO error logging level.
Definition: ApplicationFramework.php:1681
ApplicationFramework\AddUnbufferedCallback
AddUnbufferedCallback($Callback, $Parameters=array())
Add a callback that will be executed after buffered content has been output and that won&#39;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:2089
ApplicationFramework\LOGLVL_FATAL
const LOGLVL_FATAL
FATAL error logging level.
Definition: ApplicationFramework.php:1697
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:1072
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:1191
ApplicationFramework\GetCleanUrlForPath
GetCleanUrlForPath($Path)
Get the clean URL mapped for a path.
Definition: ApplicationFramework.php:471
ApplicationFramework\PRIORITY_LOW
const PRIORITY_LOW
Lower priority.
Definition: ApplicationFramework.php:2044
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:2161
ApplicationFramework\LogFile
LogFile($NewValue=NULL)
Get/set log file name.
Definition: ApplicationFramework.php:1660
ApplicationFramework\GetCleanUrl
GetCleanUrl()
Get the clean URL for the current page if one is available.
Definition: ApplicationFramework.php:569
ApplicationFramework\MaxExecutionTime
MaxExecutionTime($NewValue=NULL)
Get/set maximum PHP execution time.
Definition: ApplicationFramework.php:2359
ApplicationFramework\RequireUIFile
RequireUIFile($FileName)
Add file to list of required UI files.
Definition: ApplicationFramework.php:1282
ApplicationFramework\FullUrl
static FullUrl()
Get current full URL.
Definition: ApplicationFramework.php:1435
ApplicationFramework
Top-level framework for web applications.
Definition: ApplicationFramework.php:14
ApplicationFramework\BaseUrl
static BaseUrl()
Get current base URL (usually the part before index.php).
Definition: ApplicationFramework.php:1419
ApplicationFramework\GetOrphanedTaskCount
GetOrphanedTaskCount()
Retrieve current number of orphaned tasks.
Definition: ApplicationFramework.php:2241
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:1388
ApplicationFramework\SlowPageLoadThreshold
SlowPageLoadThreshold($NewValue=DB_NOVALUE)
Get/set how long a page load can take before it should be considered &quot;slow&quot; and may be logged...
Definition: ApplicationFramework.php:1400
ApplicationFramework\GetTaskQueueSize
GetTaskQueueSize($Priority=NULL)
Retrieve current number of tasks in queue.
Definition: ApplicationFramework.php:2149
DB_NOVALUE
const DB_NOVALUE
Definition: Axis--Database.php:1180
ApplicationFramework\GetQueuedTaskCount
GetQueuedTaskCount($Callback=NULL, $Parameters=NULL, $Priority=NULL, $Description=NULL)
Get number of queued tasks that match supplied values.
Definition: ApplicationFramework.php:2180
ApplicationFramework\DeleteTask
DeleteTask($TaskId)
Remove task from task queues.
Definition: ApplicationFramework.php:2276
ApplicationFramework\LOGLVL_DEBUG
const LOGLVL_DEBUG
DEBUG error logging leve.
Definition: ApplicationFramework.php:1675
ApplicationFramework\EVENTTYPE_NAMED
const EVENTTYPE_NAMED
Named result event type.
Definition: ApplicationFramework.php:1728
ApplicationFramework\EVENTTYPE_FIRST
const EVENTTYPE_FIRST
First response event type.
Definition: ApplicationFramework.php:1720
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&#39;t direc...
Definition: ApplicationFramework.php:1496
ApplicationFramework\EVENTTYPE_DEFAULT
const EVENTTYPE_DEFAULT
Default event type.
Definition: ApplicationFramework.php:1708
ApplicationFramework\GetPageUrl
GetPageUrl()
Get the full URL to the page.
Definition: ApplicationFramework.php:1009
ApplicationFramework\IsStaticOnlyEvent
IsStaticOnlyEvent($EventName)
Report whether specified event only allows static callbacks.
Definition: ApplicationFramework.php:1947
ApplicationFramework\IsRegisteredEvent
IsRegisteredEvent($EventName)
Check if event has been registered (is available to be signaled).
Definition: ApplicationFramework.php:1766
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:1865
ApplicationFramework\BasePath
static BasePath()
Get current base path (usually the part after the host name).
Definition: ApplicationFramework.php:1450
ApplicationFramework\LOGLVL_TRACE
const LOGLVL_TRACE
TRACE error logging level.
Definition: ApplicationFramework.php:1670
ApplicationFramework\LOGLVL_WARNING
const LOGLVL_WARNING
WARNING error logging level.
Definition: ApplicationFramework.php:1686
ApplicationFramework\PRIORITY_MEDIUM
const PRIORITY_MEDIUM
Medium (default) priority.
Definition: ApplicationFramework.php:2042
ApplicationFramework\LogError
LogError($Level, $Msg)
Write error message to log.
Definition: ApplicationFramework.php:1533
ApplicationFramework\OnCrash
OnCrash()
Called automatically at program termination to ensure output is written out.
Definition: ApplicationFramework.php:3217
ApplicationFramework\GetKnownPeriodicEvents
GetKnownPeriodicEvents()
Get list of known periodic events.
Definition: ApplicationFramework.php:1997
ApplicationFramework\EVENTTYPE_CHAIN
const EVENTTYPE_CHAIN
Result chaining event type.
Definition: ApplicationFramework.php:1714
ApplicationFramework\GetSecondsBeforeTimeout
GetSecondsBeforeTimeout()
Get remaining available (PHP) execution time.
Definition: ApplicationFramework.php:1353
ApplicationFramework\TaskIsInQueue
TaskIsInQueue($Callback, $Parameters=NULL)
Check if task is already in queue or currently running.
Definition: ApplicationFramework.php:2126
ApplicationFramework\AddFunctionDirectories
AddFunctionDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for function (&quot;F-&quot;) files.
Definition: ApplicationFramework.php:262
ApplicationFramework\LoggingLevel
LoggingLevel($NewValue=DB_NOVALUE)
Get/set logging level.
Definition: ApplicationFramework.php:1642
ApplicationFramework\ORDER_MIDDLE
const ORDER_MIDDLE
Run hooked function after ORDER_FIRST and before ORDER_LAST events.
Definition: ApplicationFramework.php:1733
PHP
PHP
Definition: OAIClient.php:39
ApplicationFramework\RegisterEvent
RegisterEvent($EventsOrEventName, $EventType=NULL)
Register one or more events that may be signaled.
Definition: ApplicationFramework.php:1745
ApplicationFramework\SetJumpToPage
SetJumpToPage($Page, $IsLiteral=FALSE)
Set URL of page to autoload after PHP page file is executed.
Definition: ApplicationFramework.php:1022
ApplicationFramework\GetPageName
GetPageName()
Get name of page being loaded.
Definition: ApplicationFramework.php:980
ApplicationFramework\CleanUrlIsMapped
CleanUrlIsMapped($Path)
Report whether clean URL has already been mapped.
Definition: ApplicationFramework.php:453
ApplicationFramework\PRIORITY_HIGH
const PRIORITY_HIGH
Highest priority.
Definition: ApplicationFramework.php:2040
ApplicationFramework\LoadFunction
LoadFunction($Callback)
Attempt to load code for function or method if not currently available.
Definition: ApplicationFramework.php:1295
ApplicationFramework\GetRunningTaskList
GetRunningTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:2214
ApplicationFramework\FindCommonTemplate
FindCommonTemplate($BaseName)
Preserved for backward compatibility for use with code written prior to October 2012.
Definition: ApplicationFramework.php:2386
ApplicationFramework\EventWillNextRunAt
EventWillNextRunAt($EventName, $Callback)
Get date/time a periodic event will next run.
Definition: ApplicationFramework.php:1962
ApplicationFramework\SessionLifetime
static SessionLifetime($NewValue=NULL)
Get/set session timeout in seconds.
Definition: ApplicationFramework.php:320
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:1803
ApplicationFramework\IsHookedEvent
IsHookedEvent($EventName)
Check if an event is registered and is hooked to.
Definition: ApplicationFramework.php:1778
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:1060
ApplicationFramework\ORDER_FIRST
const ORDER_FIRST
Run hooked function first (i.e.
Definition: ApplicationFramework.php:1731
ApplicationFramework\HtaccessSupport
HtaccessSupport()
Determine if .htaccess files are enabled.
Definition: ApplicationFramework.php:1409
ApplicationFramework\GetUncleanUrlForPath
GetUncleanUrlForPath($Path)
Get the unclean URL for mapped for a path.
Definition: ApplicationFramework.php:519
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:578
ApplicationFramework\JumpToPageIsSet
JumpToPageIsSet()
Report whether a page to autoload has been set.
Definition: ApplicationFramework.php:1046
ApplicationFramework\ORDER_LAST
const ORDER_LAST
Run hooked function last (i.e.
Definition: ApplicationFramework.php:1735
ApplicationFramework\UseBaseTag
UseBaseTag($NewValue=NULL)
Get/set whether or not to use the &quot;base&quot; tag to ensure relative URL paths are correct.
Definition: ApplicationFramework.php:1088
ApplicationFramework\GetFreeMemory
GetFreeMemory()
Get current amount of free memory.
Definition: ApplicationFramework.php:1363
ApplicationFramework\UpdateSetting
UpdateSetting($FieldName, $NewValue=DB_NOVALUE)
Convenience function for getting/setting our settings.
Definition: ApplicationFramework.php:3349
ApplicationFramework\GetTask
GetTask($TaskId)
Retrieve task info from queue (either running or queued tasks).
Definition: ApplicationFramework.php:2289
ApplicationFramework\TaskExecutionEnabled
TaskExecutionEnabled($NewValue=DB_NOVALUE)
Get/set whether automatic task execution is enabled.
Definition: ApplicationFramework.php:2337
ApplicationFramework\LoadPage
LoadPage($PageName)
Load page PHP and HTML/TPL files.
Definition: ApplicationFramework.php:588
ApplicationFramework\AddEnvInclude
AddEnvInclude($FileName)
Add file to be included to set up environment.
Definition: ApplicationFramework.php:1213
ApplicationFramework\NOVALUE
const NOVALUE
Definition: ApplicationFramework.php:3389
ApplicationFramework\ReQueueOrphanedTask
ReQueueOrphanedTask($TaskId, $NewPriority=NULL)
Move orphaned task back into queue.
Definition: ApplicationFramework.php:2254
ApplicationFramework\GUIFile
GUIFile($FileName)
Search UI directories for specified image or CSS file and return name of correct file.
Definition: ApplicationFramework.php:1224
ApplicationFramework\QueueTask
QueueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue.
Definition: ApplicationFramework.php:2060
ApplicationFramework\GetUserInterfaces
GetUserInterfaces()
Get the list of available user interfaces.
Definition: ApplicationFramework.php:1125
ApplicationFramework\PUIFile
PUIFile($FileName)
Search UI directories for specified image or CSS file and print name of correct file.
Definition: ApplicationFramework.php:1269
ApplicationFramework\ActiveUserInterface
ActiveUserInterface($UIName=NULL)
Get/set name of current active user interface.
Definition: ApplicationFramework.php:1111
ApplicationFramework\GetPageLocation
GetPageLocation()
Get the URL path to the page without the base path, if present.
Definition: ApplicationFramework.php:990
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:1344
ApplicationFramework\SetBrowserDetectionFunc
SetBrowserDetectionFunc($DetectionFunc)
Specify function to use to detect the web browser type.
Definition: ApplicationFramework.php:274
ApplicationFramework\AddCleanUrl
AddCleanUrl($Pattern, $Page, $GetVars=NULL, $Template=NULL)
Add clean URL mapping.
Definition: ApplicationFramework.php:355
ApplicationFramework\PRIORITY_BACKGROUND
const PRIORITY_BACKGROUND
Lowest priority.
Definition: ApplicationFramework.php:2046
ApplicationFramework\LogMessage
LogMessage($Level, $Msg)
Write status message to log.
Definition: ApplicationFramework.php:1574
$Items
$Items
Definition: RSSClient--Test.php:26