3 # FILE: ApplicationFramework.php
5 # Part of the ScoutLib application support library
6 # Copyright 2009-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu
16 # ---- PUBLIC INTERFACE --------------------------------------------------
24 function __construct()
26 # save execution start time
27 $this->ExecutionStartTime = microtime(TRUE);
29 # begin/restore PHP session
30 $SessionDomain = isset($_SERVER[
"SERVER_NAME"]) ? $_SERVER[
"SERVER_NAME"]
31 : isset($_SERVER[
"HTTP_HOST"]) ? $_SERVER[
"HTTP_HOST"]
33 if (is_writable(session_save_path()))
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); }
40 ini_set(
"session.gc_maxlifetime", self::$SessionLifetime);
41 session_set_cookie_params(
42 self::$SessionLifetime,
"/", $SessionDomain);
45 # set up object file autoloader
46 $this->SetUpObjectAutoloading();
48 # set up function to output any buffered text in case of crash
49 register_shutdown_function(array($this,
"OnCrash"));
51 # set up our internal environment
54 # set up our exception handler
55 set_exception_handler(array($this,
"GlobalExceptionHandler"));
57 # perform any work needed to undo PHP magic quotes
58 $this->UndoMagicQuotes();
60 # load our settings from database
61 $this->LoadSettings();
63 # set PHP maximum execution time
66 # register events we handle internally
78 # if template location cache is flagged to be saved
79 if ($this->SaveTemplateLocationCache)
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 = "
88 .$this->Settings[
"TemplateLocationCacheInterval"]
98 function GlobalExceptionHandler($Exception)
100 # display exception info
101 $Location = $Exception->getFile().
"[".$Exception->getLine().
"]";
102 ?><table width=
"100%" cellpadding=
"5"
103 style=
"border: 2px solid #666666; background: #CCCCCC;
104 font-family: Courier New, Courier, monospace;
105 margin-top: 10px;"><tr><td>
106 <div style=
"color: #666666;">
107 <span style=
"font-size: 150%;">
108 <b>Uncaught Exception</b></span><br />
109 <b>
Message:</b> <i><?
PHP print $Exception->getMessage(); ?></i><br />
110 <b>Location:</b> <i><?
PHP print $Location; ?></i><br />
112 <blockquote><pre><?
PHP print $Exception->getTraceAsString();
113 ?></pre></blockquote>
115 </td></tr></table><?
PHP
117 # log exception if possible
118 $LogMsg =
"Uncaught exception (".$Exception->getMessage().
").";
119 $this->
LogError(self::LOGLVL_ERROR, $LogMsg);
135 $Dir, $Prefix =
"", $ClassPattern = NULL, $ClassReplacement = NULL)
137 # make sure directory has trailing slash
138 $Dir = $Dir.((substr($Dir, -1) !=
"/") ?
"/" :
"");
140 # add directory to directory list
141 self::$ObjectDirectories = array_merge(
144 "ClassPattern" => $ClassPattern,
145 "ClassReplacement" => $ClassReplacement,
147 self::$ObjectDirectories);
171 # add directories to existing image directory list
172 $this->ImageDirList = $this->AddToDirList(
173 $this->ImageDirList, $Dir, $SearchLast, $SkipSlashCheck);
198 # add directories to existing image directory list
199 $this->IncludeDirList = $this->AddToDirList(
200 $this->IncludeDirList, $Dir, $SearchLast, $SkipSlashCheck);
224 # add directories to existing image directory list
225 $this->InterfaceDirList = $this->AddToDirList(
226 $this->InterfaceDirList, $Dir, $SearchLast, $SkipSlashCheck);
250 # add directories to existing image directory list
251 $this->FunctionDirList = $this->AddToDirList(
252 $this->FunctionDirList, $Dir, $SearchLast, $SkipSlashCheck);
262 $this->BrowserDetectFunc = $DetectionFunc;
273 if (is_callable($Callback))
275 $this->UnbufferedCallbacks[] = array($Callback, $Parameters);
287 if ($NewInterval >= 0)
289 $this->Settings[
"TemplateLocationCacheInterval"] = $NewInterval;
290 $this->DB->Query(
"UPDATE ApplicationFrameworkSettings"
291 .
" SET TemplateLocationCacheInterval = '"
292 .intval($NewInterval).
"'");
294 return $this->Settings[
"TemplateLocationCacheInterval"];
304 if ($NewValue !== NULL)
306 self::$SessionLifetime = $NewValue;
308 return self::$SessionLifetime;
337 function AddCleanUrl($Pattern, $Page, $GetVars = NULL, $Template = NULL)
339 # save clean URL mapping parameters
340 $this->CleanUrlMappings[] = array(
341 "Pattern" => $Pattern,
343 "GetVars" => $GetVars,
346 # if replacement template specified
347 if ($Template !== NULL)
349 # if GET parameters specified
352 # retrieve all possible permutations of GET parameters
353 $GetPerms = $this->ArrayPermutations(array_keys($GetVars));
355 # for each permutation of GET parameters
356 foreach ($GetPerms as $VarPermutation)
358 # construct search pattern for permutation
359 $SearchPattern =
"/href=([\"'])index\\.php\\?P=".$Page;
361 foreach ($VarPermutation as $GetVar)
363 if (preg_match(
"%\\\$[0-9]+%", $GetVars[$GetVar]))
365 $GetVarSegment .=
"&".$GetVar.
"=((?:(?!\\1)[^&])+)";
369 $GetVarSegment .=
"&".$GetVar.
"=".$GetVars[$GetVar];
372 $SearchPattern .= $GetVarSegment.
"\\1/i";
374 # if template is actually a callback
375 if (is_callable($Template))
377 # add pattern to HTML output mod callbacks list
378 $this->OutputModificationCallbacks[] = array(
379 "Pattern" => $Pattern,
381 "SearchPattern" => $SearchPattern,
382 "Callback" => $Template,
387 # construct replacement string for permutation
388 $Replacement = $Template;
390 foreach ($VarPermutation as $GetVar)
392 $Replacement = str_replace(
393 "\$".$GetVar,
"\$".$Index, $Replacement);
396 $Replacement =
"href=\"".$Replacement.
"\"";
398 # add pattern to HTML output modifications list
399 $this->OutputModificationPatterns[] = $SearchPattern;
400 $this->OutputModificationReplacements[] = $Replacement;
406 # construct search pattern
407 $SearchPattern =
"/href=\"index\\.php\\?P=".$Page.
"\"/i";
409 # if template is actually a callback
410 if (is_callable($Template))
412 # add pattern to HTML output mod callbacks list
413 $this->OutputModificationCallbacks[] = array(
414 "Pattern" => $Pattern,
416 "SearchPattern" => $SearchPattern,
417 "Callback" => $Template,
422 # add simple pattern to HTML output modifications list
423 $this->OutputModificationPatterns[] = $SearchPattern;
424 $this->OutputModificationReplacements[] =
"href=\"".$Template.
"\"";
437 foreach ($this->CleanUrlMappings as $Info)
439 if (preg_match($Info[
"Pattern"], $Path))
455 # the search patterns and callbacks require a specific format
456 $Format =
"href=\"".str_replace(
"&",
"&", $Path).
"\"";
459 # perform any regular expression replacements on the search string
460 $Search = preg_replace(
461 $this->OutputModificationPatterns,
462 $this->OutputModificationReplacements,
465 # only run the callbacks if a replacement hasn't already been performed
466 if ($Search == $Format)
468 # perform any callback replacements on the search string
469 foreach ($this->OutputModificationCallbacks as $Info)
471 # make the information available to the callback
472 $this->OutputModificationCallbackInfo = $Info;
474 # execute the callback
475 $Search = preg_replace_callback(
476 $Info[
"SearchPattern"],
477 array($this,
"OutputModificationCallbackShell"),
482 # return the path untouched if no replacements were performed
483 if ($Search == $Format)
488 # remove the bits added to the search string to get it recognized by
489 # the replacement expressions and callbacks
490 $Result = substr($Search, 6, -1);
503 # for each clean URL mapping
504 foreach ($this->CleanUrlMappings as $Info)
506 # if current path matches the clean URL pattern
507 if (preg_match($Info[
"Pattern"], $Path, $Matches))
509 # the GET parameters for the URL, starting with the page name
510 $GetVars = array(
"P" => $Info[
"Page"]);
512 # if additional $_GET variables specified for clean URL
513 if ($Info[
"GetVars"] !== NULL)
515 # for each $_GET variable specified for clean URL
516 foreach ($Info[
"GetVars"] as $VarName => $VarTemplate)
518 # start with template for variable value
519 $Value = $VarTemplate;
521 # for each subpattern matched in current URL
522 foreach ($Matches as $Index => $Match)
524 # if not first (whole) match
527 # make any substitutions in template
528 $Value = str_replace(
"$".$Index, $Match, $Value);
532 # add the GET variable
533 $GetVars[$VarName] = $Value;
537 # return the unclean URL
538 return "index.php?" . http_build_query($GetVars);
542 # return the path unchanged
562 $GetVars = array(
"P" => $this->
GetPageName()) + $_GET;
563 return "index.php?" . http_build_query($GetVars);
572 # perform any clean URL rewriting
573 $PageName = $this->RewriteCleanUrls($PageName);
575 # sanitize incoming page name and save local copy
576 $PageName = preg_replace(
"/[^a-zA-Z0-9_.-]/",
"", $PageName);
577 $this->PageName = $PageName;
579 # buffer any output from includes or PHP file
582 # include any files needed to set up execution environment
583 foreach ($this->EnvIncludes as $IncludeFile)
585 include($IncludeFile);
589 $this->
SignalEvent(
"EVENT_PAGE_LOAD", array(
"PageName" => $PageName));
591 # signal PHP file load
592 $SignalResult = $this->
SignalEvent(
"EVENT_PHP_FILE_LOAD", array(
593 "PageName" => $PageName));
595 # if signal handler returned new page name value
596 $NewPageName = $PageName;
597 if (($SignalResult[
"PageName"] != $PageName)
598 && strlen($SignalResult[
"PageName"]))
600 # if new page name value is page file
601 if (file_exists($SignalResult[
"PageName"]))
603 # use new value for PHP file name
604 $PageFile = $SignalResult[
"PageName"];
608 # use new value for page name
609 $NewPageName = $SignalResult[
"PageName"];
612 # update local copy of page name
613 $this->PageName = $NewPageName;
616 # if we do not already have a PHP file
617 if (!isset($PageFile))
619 # look for PHP file for page
620 $OurPageFile =
"pages/".$NewPageName.
".php";
621 $LocalPageFile =
"local/pages/".$NewPageName.
".php";
622 $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
623 : (file_exists($OurPageFile) ? $OurPageFile
624 :
"pages/".$this->DefaultPage.
".php");
630 # save buffered output to be displayed later after HTML file loads
631 $PageOutput = ob_get_contents();
634 # signal PHP file load is complete
636 $Context[
"Variables"] = get_defined_vars();
638 array(
"PageName" => $PageName,
"Context" => $Context));
639 $PageCompleteOutput = ob_get_contents();
642 # set up for possible TSR (Terminate and Stay Resident :))
643 $ShouldTSR = $this->PrepForTSR();
645 # if PHP file indicated we should autorefresh to somewhere else
646 if ($this->JumpToPage)
648 if (!strlen(trim($PageOutput)))
652 <meta http-equiv=
"refresh" content=
"0; URL=<?PHP
653 print($this->JumpToPage); ?>">
655 <body bgcolor=
"white">
660 # else if HTML loading is not suppressed
661 elseif (!$this->SuppressHTML)
663 # set content-type to get rid of diacritic errors
664 header(
"Content-Type: text/html; charset="
667 # load common HTML file (defines common functions) if available
668 $CommonHtmlFile = $this->FindFile($this->IncludeDirList,
669 "Common", array(
"tpl",
"html"));
670 if ($CommonHtmlFile) { include($CommonHtmlFile); }
673 $this->LoadUIFunctions();
675 # begin buffering content
678 # signal HTML file load
679 $SignalResult = $this->
SignalEvent(
"EVENT_HTML_FILE_LOAD", array(
680 "PageName" => $PageName));
682 # if signal handler returned new page name value
683 $NewPageName = $PageName;
684 $PageContentFile = NULL;
685 if (($SignalResult[
"PageName"] != $PageName)
686 && strlen($SignalResult[
"PageName"]))
688 # if new page name value is HTML file
689 if (file_exists($SignalResult[
"PageName"]))
691 # use new value for HTML file name
692 $PageContentFile = $SignalResult[
"PageName"];
696 # use new value for page name
697 $NewPageName = $SignalResult[
"PageName"];
701 # load page content HTML file if available
702 if ($PageContentFile === NULL)
704 $PageContentFile = $this->FindFile(
705 $this->InterfaceDirList, $NewPageName,
706 array(
"tpl",
"html"));
708 if ($PageContentFile)
710 include($PageContentFile);
714 print
"<h2>ERROR: No HTML/TPL template found"
715 .
" for this page.</h2>";
718 # signal HTML file load complete
719 $SignalResult = $this->
SignalEvent(
"EVENT_HTML_FILE_LOAD_COMPLETE");
721 # stop buffering and save output
722 $PageContentOutput = ob_get_contents();
725 # load page start HTML file if available
727 $PageStartFile = $this->FindFile($this->IncludeDirList,
"Start",
728 array(
"tpl",
"html"), array(
"StdPage",
"StandardPage"));
729 if ($PageStartFile) { include($PageStartFile); }
730 $PageStartOutput = ob_get_contents();
733 # load page end HTML file if available
735 $PageEndFile = $this->FindFile($this->IncludeDirList,
"End",
736 array(
"tpl",
"html"), array(
"StdPage",
"StandardPage"));
737 if ($PageEndFile) { include($PageEndFile); }
738 $PageEndOutput = ob_get_contents();
741 # get list of any required files not loaded
742 $RequiredFiles = $this->GetRequiredFilesNotYetLoaded($PageContentFile);
744 # if a browser detection function has been made available
745 if (is_callable($this->BrowserDetectFunc))
747 # call function to get browser list
748 $Browsers = call_user_func($this->BrowserDetectFunc);
750 # for each required file
751 $NewRequiredFiles = array();
752 foreach ($RequiredFiles as $File)
754 # if file name includes browser keyword
755 if (preg_match(
"/%BROWSER%/", $File))
758 foreach ($Browsers as $Browser)
760 # substitute in browser name and add to new file list
761 $NewRequiredFiles[] = preg_replace(
762 "/%BROWSER%/", $Browser, $File);
767 # add to new file list
768 $NewRequiredFiles[] = $File;
771 $RequiredFiles = $NewRequiredFiles;
774 # for each required file
775 foreach ($RequiredFiles as $File)
777 # locate specific file to use
778 $FilePath = $this->
GUIFile($File);
783 # determine file type
784 $NamePieces = explode(
".", $File);
785 $FileSuffix = strtolower(array_pop($NamePieces));
787 # add file to HTML output based on file type
788 $FilePath = htmlspecialchars($FilePath);
792 $Tag =
'<script type="text/javascript" src="'
793 .$FilePath.
'"></script>';
794 $PageEndOutput = preg_replace(
795 "#</body>#i", $Tag.
"\n</body>", $PageEndOutput, 1);
799 $Tag =
'<link rel="stylesheet" type="text/css"'
800 .
' media="all" href="'.$FilePath.
'">';
801 $PageStartOutput = preg_replace(
802 "#</head>#i", $Tag.
"\n</head>", $PageStartOutput, 1);
809 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
811 # perform any regular expression replacements in output
812 $FullPageOutput = preg_replace($this->OutputModificationPatterns,
813 $this->OutputModificationReplacements, $FullPageOutput);
815 # perform any callback replacements in output
816 foreach ($this->OutputModificationCallbacks as $Info)
818 $this->OutputModificationCallbackInfo = $Info;
819 $FullPageOutput = preg_replace_callback($Info[
"SearchPattern"],
820 array($this,
"OutputModificationCallbackShell"),
824 # if relative paths may not work because we were invoked via clean URL
825 if ($this->CleanUrlRewritePerformed || self::WasUrlRewritten())
827 # if using the <base> tag is okay
831 # add <base> tag to header
832 $PageStartOutput = preg_replace(
"%<head>%",
833 "<head><base href=\"".$BaseUrl.
"\" />",
836 # re-assemble full page with new header
837 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
839 # the absolute URL to the current page
842 # make HREF attribute values with just a fragment ID
843 # absolute since they don't work with the <base> tag because
844 # they are relative to the current page/URL, not the site
846 $FullPageOutput = preg_replace(
847 array(
"%href=\"(#[^:\" ]+)\"%i",
"%href='(#[^:' ]+)'%i"),
848 array(
"href=\"".$FullUrl.
"$1\"",
"href='".$FullUrl.
"$1'"),
853 # try to fix any relative paths throughout code
854 $FullPageOutput = preg_replace(array(
855 "%src=\"([^?*:;{}\\\\\" ]+)\.(js|css|gif|png|jpg)\"%i",
856 "%src='([^?*:;{}\\\\' ]+)\.(js|css|gif|png|jpg)'%i",
857 # don
't rewrite HREF attributes that are just
858 # fragment IDs because they are relative to the
859 # current page/URL, not the site root
860 "%href=\"([^#][^:\" ]*)\"%i",
861 "%href='([^#][^:
' ]*)'%i
",
862 "%action=\
"([^#][^:\" ]*)\"%i",
863 "%action='([^#][^:' ]*)'%i",
864 "%@import\s+url\(\"([^:\" ]+)\"\s*\)%i",
865 "%@import\s+url\('([^:\" ]+)'\s*\)%i",
866 "%@import\s+\"([^:\" ]+)\"\s*%i",
867 "%@import\s+'([^:\" ]+)'\s*%i",
870 "src=\"".$BaseUrl.
"$1.$2\"",
871 "src=\"".$BaseUrl.
"$1.$2\"",
872 "href=\"".$BaseUrl.
"$1\"",
873 "href=\"".$BaseUrl.
"$1\"",
874 "action=\"".$BaseUrl.
"$1\"",
875 "action=\"".$BaseUrl.
"$1\"",
876 "@import url(\"".$BaseUrl.
"$1\")",
877 "@import url('".$BaseUrl.
"$1')",
878 "@import \"".$BaseUrl.
"$1\"",
879 "@import '".$BaseUrl.
"$1'",
885 # provide the opportunity to modify full page output
886 $SignalResult = $this->
SignalEvent(
"EVENT_PAGE_OUTPUT_FILTER", array(
887 "PageOutput" => $FullPageOutput));
888 if (isset($SignalResult[
"PageOutput"])
889 && strlen($SignalResult[
"PageOutput"]))
891 $FullPageOutput = $SignalResult[
"PageOutput"];
894 # write out full page
895 print $FullPageOutput;
898 # run any post-processing routines
899 foreach ($this->PostProcessingFuncs as $Func)
901 call_user_func_array($Func[
"FunctionName"], $Func[
"Arguments"]);
904 # write out any output buffered from page code execution
905 if (strlen($PageOutput))
907 if (!$this->SuppressHTML)
909 ?><table width=
"100%" cellpadding=
"5"
910 style=
"border: 2px solid #666666; background: #CCCCCC;
911 font-family: Courier New, Courier, monospace;
912 margin-top: 10px;"><tr><td><?
PHP
914 if ($this->JumpToPage)
916 ?><div style=
"color: #666666;"><span style=
"font-size: 150%;">
917 <b>Page Jump Aborted</b></span>
918 (because of error or other unexpected output)<br />
920 <i><?
PHP print($this->JumpToPage); ?></i></div><?
PHP
923 if (!$this->SuppressHTML)
925 ?></td></tr></table><?
PHP
929 # write out any output buffered from the page code execution complete signal
930 if (!$this->JumpToPage && !$this->SuppressHTML && strlen($PageCompleteOutput))
932 print $PageCompleteOutput;
935 # execute callbacks that should not have their output buffered
936 foreach ($this->UnbufferedCallbacks as $Callback)
938 call_user_func_array($Callback[0], $Callback[1]);
941 # terminate and stay resident (TSR!) if indicated and HTML has been output
942 # (only TSR if HTML has been output because otherwise browsers will misbehave)
943 if ($ShouldTSR) { $this->LaunchTSR(); }
953 return $this->PageName;
963 # retrieve current URL
966 # remove the base path if present
967 $BasePath = $this->Settings[
"BasePath"];
968 if (stripos($Url, $BasePath) === 0)
970 $Url = substr($Url, strlen($BasePath));
997 && (strpos($Page,
"?") === FALSE)
998 && ((strpos($Page,
"=") !== FALSE)
999 || ((stripos($Page,
".php") === FALSE)
1000 && (stripos($Page,
".htm") === FALSE)
1001 && (strpos($Page,
"/") === FALSE)))
1002 && (stripos($Page,
"http://") !== 0)
1003 && (stripos($Page,
"https://") !== 0))
1005 $this->JumpToPage = self::BaseUrl() .
"index.php?P=".$Page;
1009 $this->JumpToPage = $Page;
1019 return ($this->JumpToPage === NULL) ? FALSE : TRUE;
1033 if ($NewSetting !== NULL) { $this->
HtmlCharset = $NewSetting; }
1034 return $this->HtmlCharset;
1046 return $this->UseMinimizedJavascript;
1061 if ($NewValue !== NULL) { $this->
UseBaseTag = $NewValue ? TRUE : FALSE; }
1062 return $this->UseBaseTag;
1073 $this->SuppressHTML = $NewSetting;
1084 if ($UIName !== NULL)
1086 $this->ActiveUI = preg_replace(
"/^SPTUI--/",
"", $UIName);
1088 return $this->ActiveUI;
1098 # possible UI directories
1099 $InterfaceDirs = array(
1103 # start out with an empty list
1104 $Interfaces = array();
1106 # for each possible UI directory
1107 foreach ($InterfaceDirs as $InterfaceDir)
1109 $Dir = dir($InterfaceDir);
1111 # for each file in current directory
1112 while (($DirEntry = $Dir->read()) !== FALSE)
1114 $InterfacePath = $InterfaceDir.
"/".$DirEntry;
1116 # skip anything that doesn't have a name in the required format
1117 if (!preg_match(
'/^[a-zA-Z]+$/', $DirEntry))
1122 # skip anything that isn't a directory
1123 if (!is_dir($InterfacePath))
1128 # read the UI name (if available)
1129 $UIName = @file_get_contents($InterfacePath.
"/NAME");
1131 # use the directory name if the UI name isn't available
1132 if ($UIName === FALSE || !strlen($UIName))
1134 $UIName = $DirEntry;
1137 $Interfaces[$InterfacePath] = $UIName;
1143 # return list to caller
1163 &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
1164 &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
1165 &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
1167 $FuncIndex = count($this->PostProcessingFuncs);
1168 $this->PostProcessingFuncs[$FuncIndex][
"FunctionName"] = $FunctionName;
1169 $this->PostProcessingFuncs[$FuncIndex][
"Arguments"] = array();
1171 while (isset(${
"Arg".$Index}) && (${
"Arg".$Index} !== self::NOVALUE))
1173 $this->PostProcessingFuncs[$FuncIndex][
"Arguments"][$Index]
1186 $this->EnvIncludes[] = $FileName;
1197 # determine if the file is an image or JavaScript file
1198 $FileIsImage = preg_match(
"/\.(gif|jpg|png)$/", $FileName);
1199 $FileIsJavascript = preg_match(
"/\.js$/", $FileName);
1201 # determine which location to search based on file suffix
1202 $DirList = $FileIsImage ? $this->ImageDirList : $this->IncludeDirList;
1204 # if directed to get a minimized JavaScript file
1207 # first try to find the minimized JavaScript file
1208 $MinimizedFileName = substr_replace($FileName,
".min", -3, 0);
1209 $FoundFileName = $this->FindFile($DirList, $MinimizedFileName);
1211 # search for the regular file if a minimized file wasn't found
1212 if (is_null($FoundFileName))
1214 $FoundFileName = $this->FindFile($DirList, $FileName);
1218 # otherwise just search for the file
1221 $FoundFileName = $this->FindFile($DirList, $FileName);
1224 # add non-image files to list of found files (used for required files loading)
1225 if (!$FileIsImage) { $this->FoundUIFiles[] = basename($FoundFileName); }
1227 # return file name to caller
1228 return $FoundFileName;
1242 $FullFileName = $this->
GUIFile($FileName);
1243 if ($FullFileName) { print($FullFileName); }
1255 $this->AdditionalRequiredUIFiles[] = $FileName;
1268 # if specified function is not currently available
1269 if (!is_callable($Callback))
1271 # if function info looks legal
1272 if (is_string($Callback) && strlen($Callback))
1274 # start with function directory list
1275 $Locations = $this->FunctionDirList;
1277 # add object directories to list
1278 $Locations = array_merge(
1279 $Locations, array_keys(self::$ObjectDirectories));
1281 # look for function file
1282 $FunctionFileName = $this->FindFile($Locations,
"F-".$Callback,
1283 array(
"php",
"html"));
1285 # if function file was found
1286 if ($FunctionFileName)
1288 # load function file
1289 include_once($FunctionFileName);
1293 # log error indicating function load failed
1294 $this->
LogError(self::LOGLVL_ERROR,
"Unable to load function"
1295 .
" for callback \"".$Callback.
"\".");
1300 # log error indicating specified function info was bad
1301 $this->
LogError(self::LOGLVL_ERROR,
"Unloadable callback value"
1303 .
" passed to AF::LoadFunction().");
1307 # report to caller whether function load succeeded
1308 return is_callable($Callback);
1317 return microtime(TRUE) - $this->ExecutionStartTime;
1336 $Str = strtoupper(ini_get(
"memory_limit"));
1337 if (substr($Str, -1) ==
"B") { $Str = substr($Str, 0, strlen($Str) - 1); }
1338 switch (substr($Str, -1))
1340 case "K": $MemoryLimit = (int)$Str * 1024;
break;
1341 case "M": $MemoryLimit = (int)$Str * 1048576;
break;
1342 case "G": $MemoryLimit = (int)$Str * 1073741824;
break;
1343 default: $MemoryLimit = (int)$Str;
break;
1346 return $MemoryLimit - memory_get_usage();
1355 # HTACCESS_SUPPORT is set in the .htaccess file
1356 return isset($_SERVER[
"HTACCESS_SUPPORT"]);
1365 $Protocol = (isset($_SERVER[
"HTTPS"]) ?
"https" :
"http");
1366 $BaseUrl = $Protocol.
"://"
1367 .(($_SERVER[
"SERVER_NAME"] !=
"127.0.0.1")
1368 ? $_SERVER[
"SERVER_NAME"]
1369 : $_SERVER[
"HTTP_HOST"])
1370 .dirname($_SERVER[
"SCRIPT_NAME"]);
1371 if (substr($BaseUrl, -1) !=
"/") { $BaseUrl .=
"/"; }
1381 $BasePath = dirname($_SERVER[
"SCRIPT_NAME"]);
1383 if (substr($BasePath, -1) !=
"/")
1398 if (array_key_exists(
"SCRIPT_URL", $_SERVER))
1400 return $_SERVER[
"SCRIPT_URL"];
1402 elseif (array_key_exists(
"REDIRECT_URL", $_SERVER))
1404 return $_SERVER[
"REDIRECT_URL"];
1406 elseif (array_key_exists(
"REQUEST_URI", $_SERVER))
1408 $Pieces = parse_url($_SERVER[
"REQUEST_URI"]);
1409 return $Pieces[
"path"];
1427 # needed to get the path of the URL minus the query and fragment pieces
1428 $Components = parse_url(self::GetScriptUrl());
1430 # if parsing was successful and a path is set
1431 if (is_array($Components) && isset($Components[
"path"]))
1433 $BasePath = self::BasePath();
1434 $Path = $Components[
"path"];
1436 # the URL was rewritten if the path isn't the base path, i.e., the
1437 # home page, and the file in the URL isn't the script generating the
1439 if ($BasePath != $Path && basename($Path) != $ScriptName)
1445 # the URL wasn't rewritten
1464 # if error level is at or below current logging level
1465 if ($this->Settings[
"LoggingLevel"] >= $Level)
1467 # attempt to log error message
1470 # if logging attempt failed and level indicated significant error
1471 if (($Result === FALSE) && ($Level <= self::LOGLVL_ERROR))
1473 # throw exception about inability to log error
1474 static $AlreadyThrewException = FALSE;
1475 if (!$AlreadyThrewException)
1477 $AlreadyThrewException = TRUE;
1478 throw new Exception(
"Unable to log error (".$Level.
": ".$Msg.
").");
1482 # report to caller whether message was logged
1487 # report to caller that message was not logged
1505 # if message level is at or below current logging level
1506 if ($this->Settings[
"LoggingLevel"] >= $Level)
1508 # attempt to open log file
1509 $FHndl = @fopen($this->LogFileName,
"a");
1511 # if log file could not be open
1512 if ($FHndl === FALSE)
1514 # report to caller that message was not logged
1520 $ErrorAbbrevs = array(
1521 self::LOGLVL_FATAL =>
"FTL",
1522 self::LOGLVL_ERROR =>
"ERR",
1523 self::LOGLVL_WARNING =>
"WRN",
1524 self::LOGLVL_INFO =>
"INF",
1525 self::LOGLVL_DEBUG =>
"DBG",
1526 self::LOGLVL_TRACE =>
"TRC",
1528 $LogEntry = date(
"Y-m-d H:i:s")
1529 .
" ".($this->RunningInBackground ?
"B" :
"F")
1530 .
" ".$ErrorAbbrevs[$Level]
1533 # write entry to log
1534 $Success = fputs($FHndl, $LogEntry.
"\n");
1539 # report to caller whether message was logged
1540 return ($Success === FALSE) ? FALSE : TRUE;
1545 # report to caller that message was not logged
1573 # if new logging level was specified
1574 if ($NewValue !== NULL)
1576 # constrain new level to within legal bounds and store locally
1577 $this->Settings[
"LoggingLevel"] = max(min($NewValue, 6), 1);
1579 # save new logging level in database
1580 $this->DB->Query(
"UPDATE ApplicationFrameworkSettings"
1581 .
" SET LoggingLevel = "
1582 .intval($this->Settings[
"LoggingLevel"]));
1585 # report current logging level to caller
1586 return $this->Settings[
"LoggingLevel"];
1597 if ($NewValue !== NULL) { $this->LogFileName = $NewValue; }
1598 return $this->LogFileName;
1636 # ---- Event Handling ----------------------------------------------------
1682 # convert parameters to array if not already in that form
1683 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1684 : array($EventsOrEventName => $Type);
1687 foreach ($Events as $Name => $Type)
1689 # store event information
1690 $this->RegisteredEvents[$Name][
"Type"] = $Type;
1691 $this->RegisteredEvents[$Name][
"Hooks"] = array();
1703 return array_key_exists($EventName, $this->RegisteredEvents)
1715 # the event isn't hooked to if it isn't even registered
1721 # return TRUE if there is at least one callback hooked to the event
1722 return count($this->RegisteredEvents[$EventName][
"Hooks"]) > 0;
1738 function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
1740 # convert parameters to array if not already in that form
1741 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1742 : array($EventsOrEventName => $Callback);
1746 foreach ($Events as $EventName => $EventCallback)
1748 # if callback is valid
1749 if (is_callable($EventCallback))
1751 # if this is a periodic event we process internally
1752 if (isset($this->PeriodicEvents[$EventName]))
1755 $this->ProcessPeriodicEvent($EventName, $EventCallback);
1757 # if specified event has been registered
1758 elseif (isset($this->RegisteredEvents[$EventName]))
1760 # add callback for event
1761 $this->RegisteredEvents[$EventName][
"Hooks"][]
1762 = array(
"Callback" => $EventCallback,
"Order" => $Order);
1764 # sort callbacks by order
1765 if (count($this->RegisteredEvents[$EventName][
"Hooks"]) > 1)
1767 usort($this->RegisteredEvents[$EventName][
"Hooks"],
1768 array(
"ApplicationFramework",
"HookEvent_OrderCompare"));
1782 # report to caller whether all callbacks were hooked
1786 private static function HookEvent_OrderCompare($A, $B)
1788 if ($A[
"Order"] == $B[
"Order"]) {
return 0; }
1789 return ($A[
"Order"] < $B[
"Order"]) ? -1 : 1;
1802 $ReturnValue = NULL;
1804 # if event has been registered
1805 if (isset($this->RegisteredEvents[$EventName]))
1807 # set up default return value (if not NULL)
1808 switch ($this->RegisteredEvents[$EventName][
"Type"])
1810 case self::EVENTTYPE_CHAIN:
1811 $ReturnValue = $Parameters;
1814 case self::EVENTTYPE_NAMED:
1815 $ReturnValue = array();
1819 # for each callback for this event
1820 foreach ($this->RegisteredEvents[$EventName][
"Hooks"] as $Hook)
1823 $Callback = $Hook[
"Callback"];
1824 $Result = ($Parameters !== NULL)
1825 ? call_user_func_array($Callback, $Parameters)
1826 : call_user_func($Callback);
1828 # process return value based on event type
1829 switch ($this->RegisteredEvents[$EventName][
"Type"])
1831 case self::EVENTTYPE_CHAIN:
1832 if ($Result !== NULL)
1834 foreach ($Parameters as $Index => $Value)
1836 if (array_key_exists($Index, $Result))
1838 $Parameters[$Index] = $Result[$Index];
1841 $ReturnValue = $Parameters;
1845 case self::EVENTTYPE_FIRST:
1846 if ($Result !== NULL)
1848 $ReturnValue = $Result;
1853 case self::EVENTTYPE_NAMED:
1854 $CallbackName = is_array($Callback)
1855 ? (is_object($Callback[0])
1856 ? get_class($Callback[0])
1857 : $Callback[0]).
"::".$Callback[1]
1859 $ReturnValue[$CallbackName] = $Result;
1869 $this->
LogError(self::LOGLVL_WARNING,
1870 "Unregistered event signaled (".$EventName.
").");
1873 # return value if any to caller
1874 return $ReturnValue;
1884 return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
1899 # if event is not a periodic event report failure to caller
1900 if (!array_key_exists($EventName, $this->EventPeriods)) {
return FALSE; }
1902 # retrieve last execution time for event if available
1903 $Signature = self::GetCallbackSignature($Callback);
1904 $LastRunTime = $this->DB->Query(
"SELECT LastRunAt FROM PeriodicEvents"
1905 .
" WHERE Signature = '".addslashes($Signature).
"'",
"LastRunAt");
1907 # if event was not found report failure to caller
1908 if ($LastRunTime === NULL) {
return FALSE; }
1910 # calculate next run time based on event period
1911 $NextRunTime = strtotime($LastRunTime) + $this->EventPeriods[$EventName];
1913 # report next run time to caller
1914 return $NextRunTime;
1934 # retrieve last execution times
1935 $this->DB->Query(
"SELECT * FROM PeriodicEvents");
1936 $LastRunTimes = $this->DB->FetchColumn(
"LastRunAt",
"Signature");
1938 # for each known event
1940 foreach ($this->KnownPeriodicEvents as $Signature => $Info)
1942 # if last run time for event is available
1943 if (array_key_exists($Signature, $LastRunTimes))
1945 # calculate next run time for event
1946 $LastRun = strtotime($LastRunTimes[$Signature]);
1947 $NextRun = $LastRun + $this->EventPeriods[$Info[
"Period"]];
1948 if ($Info[
"Period"] ==
"EVENT_PERIODIC") { $LastRun = FALSE; }
1952 # set info to indicate run times are not known
1957 # add event info to list
1958 $Events[$Signature] = $Info;
1959 $Events[$Signature][
"LastRun"] = $LastRun;
1960 $Events[$Signature][
"NextRun"] = $NextRun;
1961 $Events[$Signature][
"Parameters"] = NULL;
1964 # return list of known events to caller
1970 # ---- Task Management ---------------------------------------------------
1996 $Priority = self::PRIORITY_LOW, $Description =
"")
1998 # pack task info and write to database
1999 if ($Parameters === NULL) { $Parameters = array(); }
2000 $this->DB->Query(
"INSERT INTO TaskQueue"
2001 .
" (Callback, Parameters, Priority, Description)"
2002 .
" VALUES ('".addslashes(serialize($Callback)).
"', '"
2003 .addslashes(serialize($Parameters)).
"', ".intval($Priority).
", '"
2004 .addslashes($Description).
"')");
2025 $Priority = self::PRIORITY_LOW, $Description =
"")
2029 $QueryResult = $this->DB->Query(
"SELECT TaskId,Priority FROM TaskQueue"
2030 .
" WHERE Callback = '".addslashes(serialize($Callback)).
"'"
2031 .($Parameters ?
" AND Parameters = '"
2032 .addslashes(serialize($Parameters)).
"'" :
""));
2033 if ($QueryResult !== FALSE)
2035 $Record = $this->DB->FetchRow();
2036 if ($Record[
"Priority"] > $Priority)
2038 $this->DB->Query(
"UPDATE TaskQueue"
2039 .
" SET Priority = ".intval($Priority)
2040 .
" WHERE TaskId = ".intval($Record[
"TaskId"]));
2047 $this->
QueueTask($Callback, $Parameters, $Priority, $Description);
2063 $QueuedCount = $this->DB->Query(
2064 "SELECT COUNT(*) AS FoundCount FROM TaskQueue"
2065 .
" WHERE Callback = '".addslashes(serialize($Callback)).
"'"
2066 .($Parameters ?
" AND Parameters = '"
2067 .addslashes(serialize($Parameters)).
"'" :
""),
2069 $RunningCount = $this->DB->Query(
2070 "SELECT COUNT(*) AS FoundCount FROM RunningTasks"
2071 .
" WHERE Callback = '".addslashes(serialize($Callback)).
"'"
2072 .($Parameters ?
" AND Parameters = '"
2073 .addslashes(serialize($Parameters)).
"'" :
""),
2075 $FoundCount = $QueuedCount + $RunningCount;
2076 return ($FoundCount ? TRUE : FALSE);
2098 return $this->GetTaskList(
"SELECT * FROM TaskQueue"
2099 .
" ORDER BY Priority, TaskId ", $Count, $Offset);
2116 $Parameters = NULL, $Priority = NULL, $Description = NULL)
2118 $Query =
"SELECT COUNT(*) AS TaskCount FROM TaskQueue";
2120 if ($Callback !== NULL)
2122 $Query .= $Sep.
" Callback = '".addslashes(serialize($Callback)).
"'";
2125 if ($Parameters !== NULL)
2127 $Query .= $Sep.
" Parameters = '".addslashes(serialize($Parameters)).
"'";
2130 if ($Priority !== NULL)
2132 $Query .= $Sep.
" Priority = ".intval($Priority);
2135 if ($Description !== NULL)
2137 $Query .= $Sep.
" Description = '".addslashes($Description).
"'";
2139 return $this->DB->Query($Query,
"TaskCount");
2151 return $this->GetTaskList(
"SELECT * FROM RunningTasks"
2152 .
" WHERE StartedAt >= '".date(
"Y-m-d H:i:s",
2153 (time() - ini_get(
"max_execution_time"))).
"'"
2154 .
" ORDER BY StartedAt", $Count, $Offset);
2166 return $this->GetTaskList(
"SELECT * FROM RunningTasks"
2167 .
" WHERE StartedAt < '".date(
"Y-m-d H:i:s",
2168 (time() - ini_get(
"max_execution_time"))).
"'"
2169 .
" ORDER BY StartedAt", $Count, $Offset);
2178 return $this->DB->Query(
"SELECT COUNT(*) AS Count FROM RunningTasks"
2179 .
" WHERE StartedAt < '".date(
"Y-m-d H:i:s",
2180 (time() - ini_get(
"max_execution_time"))).
"'",
2191 $this->DB->Query(
"LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
2192 $this->DB->Query(
"INSERT INTO TaskQueue"
2193 .
" (Callback,Parameters,Priority,Description) "
2194 .
"SELECT Callback, Parameters, Priority, Description"
2195 .
" FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2196 if ($NewPriority !== NULL)
2198 $NewTaskId = $this->DB->LastInsertId(
"TaskQueue");
2199 $this->DB->Query(
"UPDATE TaskQueue SET Priority = "
2200 .intval($NewPriority)
2201 .
" WHERE TaskId = ".intval($NewTaskId));
2203 $this->DB->Query(
"DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2204 $this->DB->Query(
"UNLOCK TABLES");
2213 $this->DB->Query(
"DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2214 $this->DB->Query(
"DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2226 # assume task will not be found
2229 # look for task in task queue
2230 $this->DB->Query(
"SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2232 # if task was not found in queue
2233 if (!$this->DB->NumRowsSelected())
2235 # look for task in running task list
2236 $this->DB->Query(
"SELECT * FROM RunningTasks WHERE TaskId = "
2241 if ($this->DB->NumRowsSelected())
2243 # if task was periodic
2244 $Row = $this->DB->FetchRow();
2245 if ($Row[
"Callback"] ==
2246 serialize(array(
"ApplicationFramework",
"PeriodicEventWrapper")))
2248 # unpack periodic task callback
2249 $WrappedCallback = unserialize($Row[
"Parameters"]);
2250 $Task[
"Callback"] = $WrappedCallback[1];
2251 $Task[
"Parameters"] = $WrappedCallback[2];
2255 # unpack task callback and parameters
2256 $Task[
"Callback"] = unserialize($Row[
"Callback"]);
2257 $Task[
"Parameters"] = unserialize($Row[
"Parameters"]);
2261 # return task to caller
2274 if ($NewValue !== NULL)
2276 $this->Settings[
"TaskExecutionEnabled"] = $NewValue ? 1 : 0;
2277 $this->DB->Query(
"UPDATE ApplicationFrameworkSettings"
2278 .
" SET TaskExecutionEnabled = "
2279 .$this->Settings[
"TaskExecutionEnabled"]);
2281 return $this->Settings[
"TaskExecutionEnabled"];
2291 if (func_num_args() && ($NewValue >= 1))
2293 $this->DB->Query(
"UPDATE ApplicationFrameworkSettings"
2294 .
" SET MaxTasksRunning = ".intval($NewValue));
2295 $this->Settings[
"MaxTasksRunning"] = intval($NewValue);
2297 return $this->Settings[
"MaxTasksRunning"];
2309 if (func_num_args() && !ini_get(
"safe_mode"))
2311 if ($NewValue != $this->Settings[
"MaxExecTime"])
2313 $this->Settings[
"MaxExecTime"] = max($NewValue, 5);
2314 $this->DB->Query(
"UPDATE ApplicationFrameworkSettings"
2315 .
" SET MaxExecTime = '"
2316 .intval($this->Settings[
"MaxExecTime"]).
"'");
2318 ini_set(
"max_execution_time", $this->Settings[
"MaxExecTime"]);
2319 set_time_limit($this->Settings[
"MaxExecTime"]);
2321 return ini_get(
"max_execution_time");
2326 # ---- Backward Compatibility --------------------------------------------
2336 return $this->FindFile(
2337 $this->IncludeDirList, $BaseName, array(
"tpl",
"html"));
2343 # ---- PRIVATE INTERFACE -------------------------------------------------
2345 private $ActiveUI =
"default";
2346 private $BrowserDetectFunc;
2348 private $DefaultPage =
"Home";
2349 private $EnvIncludes = array();
2350 private $ExecutionStartTime;
2351 private $FoundUIFiles = array();
2352 private $AdditionalRequiredUIFiles = array();
2353 private $HtmlCharset =
"UTF-8";
2354 private $UseMinimizedJavascript = FALSE;
2355 private $JumpToPage = NULL;
2357 private $LogFileName =
"local/logs/site.log";
2358 private $MaxRunningTasksToTrack = 250;
2359 private $PostProcessingFuncs = array();
2360 private $RunningInBackground = FALSE;
2361 private $RunningTask;
2363 private $SuppressHTML = FALSE;
2364 private $SaveTemplateLocationCache = FALSE;
2365 private $UnbufferedCallbacks = array();
2366 private $UseBaseTag = FALSE;
2367 private $CleanUrlMappings = array();
2368 private $CleanUrlRewritePerformed = FALSE;
2369 private $OutputModificationPatterns = array();
2370 private $OutputModificationReplacements = array();
2371 private $OutputModificationCallbacks = array();
2372 private $OutputModificationCallbackInfo;
2374 private static $AppName =
"ScoutAF";
2375 private static $ObjectDirectories = array();
2376 private static $SessionLifetime = 1440;
2382 private $NoTSR = FALSE;
2384 private $KnownPeriodicEvents = array();
2385 private $PeriodicEvents = array(
2386 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
2387 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
2388 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
2389 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
2390 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
2392 private $EventPeriods = array(
2393 "EVENT_HOURLY" => 3600,
2394 "EVENT_DAILY" => 86400,
2395 "EVENT_WEEKLY" => 604800,
2396 "EVENT_MONTHLY" => 2592000,
2397 "EVENT_PERIODIC" => 0,
2399 private $UIEvents = array(
2400 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
2401 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2402 "EVENT_PHP_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2403 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2404 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2405 "EVENT_PAGE_OUTPUT_FILTER" => self::EVENTTYPE_CHAIN,
2411 private function LoadSettings()
2413 # read settings in from database
2414 $this->DB->Query(
"SELECT * FROM ApplicationFrameworkSettings");
2415 $this->Settings = $this->DB->FetchRow();
2417 # if settings were not previously initialized
2418 if (!$this->Settings)
2420 # initialize settings in database
2421 $this->DB->Query(
"INSERT INTO ApplicationFrameworkSettings"
2422 .
" (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')");
2424 # read new settings in from database
2425 $this->DB->Query(
"SELECT * FROM ApplicationFrameworkSettings");
2426 $this->Settings = $this->DB->FetchRow();
2429 # if base path was not previously set or we appear to have moved
2430 if (!array_key_exists(
"BasePath", $this->Settings)
2431 || (!strlen($this->Settings[
"BasePath"]))
2432 || (!array_key_exists(
"BasePathCheck", $this->Settings))
2433 || (__FILE__ != $this->Settings[
"BasePathCheck"]))
2435 # attempt to extract base path from Apache .htaccess file
2436 if (is_readable(
".htaccess"))
2438 $Lines = file(
".htaccess");
2439 foreach ($Lines as $Line)
2441 if (preg_match(
"/\\s*RewriteBase\\s+/", $Line))
2443 $Pieces = preg_split(
2444 "/\\s+/", $Line, NULL, PREG_SPLIT_NO_EMPTY);
2445 $BasePath = $Pieces[1];
2450 # if base path was found
2451 if (isset($BasePath))
2453 # save base path locally
2454 $this->Settings[
"BasePath"] = $BasePath;
2456 # save base path to database
2457 $this->DB->Query(
"UPDATE ApplicationFrameworkSettings"
2458 .
" SET BasePath = '".addslashes($BasePath).
"'"
2459 .
", BasePathCheck = '".addslashes(__FILE__).
"'");
2463 # if template location cache has been saved to database
2464 if (isset($this->Settings[
"TemplateLocationCache"]))
2466 # unserialize cache values into array and use if valid
2467 $Cache = unserialize($this->Settings[
"TemplateLocationCache"]);
2468 $this->Settings[
"TemplateLocationCache"] =
2469 count($Cache) ? $Cache : array();
2473 # start with empty cache
2474 $this->Settings[
"TemplateLocationCache"] = array();
2484 private function RewriteCleanUrls($PageName)
2486 # if URL rewriting is supported by the server
2489 # retrieve current URL and remove base path if present
2492 # for each clean URL mapping
2493 foreach ($this->CleanUrlMappings as $Info)
2495 # if current URL matches clean URL pattern
2496 if (preg_match($Info[
"Pattern"], $Url, $Matches))
2499 $PageName = $Info[
"Page"];
2501 # if $_GET variables specified for clean URL
2502 if ($Info[
"GetVars"] !== NULL)
2504 # for each $_GET variable specified for clean URL
2505 foreach ($Info[
"GetVars"] as $VarName => $VarTemplate)
2507 # start with template for variable value
2508 $Value = $VarTemplate;
2510 # for each subpattern matched in current URL
2511 foreach ($Matches as $Index => $Match)
2513 # if not first (whole) match
2516 # make any substitutions in template
2517 $Value = str_replace(
"$".$Index, $Match, $Value);
2521 # set $_GET variable
2522 $_GET[$VarName] = $Value;
2526 # set flag indicating clean URL mapped
2527 $this->CleanUrlRewritePerformed = TRUE;
2529 # stop looking for a mapping
2535 # return (possibly) updated page name to caller
2555 private function FindFile($DirectoryList, $BaseName,
2556 $PossibleSuffixes = NULL, $PossiblePrefixes = NULL)
2558 # generate template cache index for this page
2559 $CacheIndex = md5(serialize($DirectoryList))
2560 .
":".$this->ActiveUI.
":".$BaseName;
2562 # if we have cached location and cache expiration time has not elapsed
2563 if (($this->Settings[
"TemplateLocationCacheInterval"] > 0)
2564 && count($this->Settings[
"TemplateLocationCache"])
2565 && array_key_exists($CacheIndex,
2566 $this->Settings[
"TemplateLocationCache"])
2567 && (time() < strtotime(
2568 $this->Settings[
"TemplateLocationCacheExpiration"])))
2570 # use template location from cache
2571 $FoundFileName = $this->Settings[
2572 "TemplateLocationCache"][$CacheIndex];
2576 # if suffixes specified and base name does not include suffix
2577 if (count($PossibleSuffixes)
2578 && !preg_match(
"/\.[a-zA-Z0-9]+$/", $BaseName))
2580 # add versions of file names with suffixes to file name list
2581 $FileNames = array();
2582 foreach ($PossibleSuffixes as $Suffix)
2584 $FileNames[] = $BaseName.
".".$Suffix;
2589 # use base name as file name
2590 $FileNames = array($BaseName);
2593 # if prefixes specified
2594 if (count($PossiblePrefixes))
2596 # add versions of file names with prefixes to file name list
2597 $NewFileNames = array();
2598 foreach ($FileNames as $FileName)
2600 foreach ($PossiblePrefixes as $Prefix)
2602 $NewFileNames[] = $Prefix.$FileName;
2605 $FileNames = $NewFileNames;
2608 # for each possible location
2609 $FoundFileName = NULL;
2610 foreach ($DirectoryList as $Dir)
2612 # substitute active UI name into path
2613 $Dir = str_replace(
"%ACTIVEUI%", $this->ActiveUI, $Dir);
2615 # for each possible file name
2616 foreach ($FileNames as $File)
2618 # if template is found at location
2619 if (file_exists($Dir.$File))
2621 # save full template file name and stop looking
2622 $FoundFileName = $Dir.$File;
2628 # save location in cache
2629 $this->Settings[
"TemplateLocationCache"][$CacheIndex]
2632 # set flag indicating that cache should be saved
2633 $this->SaveTemplateLocationCache = TRUE;
2636 # return full template file name to caller
2637 return $FoundFileName;
2646 private function GetRequiredFilesNotYetLoaded($PageContentFile)
2648 # start out assuming no files required
2649 $RequiredFiles = array();
2651 # if page content file supplied
2652 if ($PageContentFile)
2654 # if file containing list of required files is available
2655 $Path = dirname($PageContentFile);
2656 $RequireListFile = $Path.
"/REQUIRES";
2657 if (file_exists($RequireListFile))
2659 # read in list of required files
2660 $RequestedFiles = file($RequireListFile);
2662 # for each line in required file list
2663 foreach ($RequestedFiles as $Line)
2665 # if line is not a comment
2666 $Line = trim($Line);
2667 if (!preg_match(
"/^#/", $Line))
2669 # if file has not already been loaded
2670 if (!in_array($Line, $this->FoundUIFiles))
2672 # add to list of required files
2673 $RequiredFiles[] = $Line;
2680 # add in additional required files if any
2681 if (count($this->AdditionalRequiredUIFiles))
2683 # make sure there are no duplicates
2684 $AdditionalRequiredUIFiles = array_unique(
2685 $this->AdditionalRequiredUIFiles);
2687 $RequiredFiles = array_merge(
2688 $RequiredFiles, $AdditionalRequiredUIFiles);
2691 # return list of required files to caller
2692 return $RequiredFiles;
2698 private function SetUpObjectAutoloading()
2701 function __autoload($ClassName)
2703 ApplicationFramework::AutoloadObjects($ClassName);
2712 static function AutoloadObjects($ClassName)
2715 foreach (self::$ObjectDirectories as $Location => $Info)
2717 if (is_dir($Location))
2719 $NewClassName = ($Info[
"ClassPattern"] && $Info[
"ClassReplacement"])
2720 ? preg_replace($Info[
"ClassPattern"],
2721 $Info[
"ClassReplacement"], $ClassName)
2723 if (!isset($FileLists[$Location]))
2725 $FileLists[$Location] = self::ReadDirectoryTree(
2726 $Location,
'/^.+\.php$/i');
2728 $FileNames = $FileLists[$Location];
2729 $TargetName = strtolower($Info[
"Prefix"].$NewClassName.
".php");
2730 foreach ($FileNames as $FileName)
2732 if (strtolower($FileName) == $TargetName)
2734 require_once($Location.$FileName);
2749 private static function ReadDirectoryTree($Directory, $Pattern)
2751 $CurrentDir = getcwd();
2753 $DirIter =
new RecursiveDirectoryIterator(
".");
2754 $IterIter =
new RecursiveIteratorIterator($DirIter);
2755 $RegexResults =
new RegexIterator($IterIter, $Pattern,
2756 RecursiveRegexIterator::GET_MATCH);
2757 $FileList = array();
2758 foreach ($RegexResults as $Result)
2760 $FileList[] = substr($Result[0], 2);
2770 private function UndoMagicQuotes()
2772 # if this PHP version has magic quotes support
2773 if (version_compare(PHP_VERSION,
"5.4.0",
"<"))
2775 # turn off runtime magic quotes if on
2776 if (get_magic_quotes_runtime())
2778 set_magic_quotes_runtime(FALSE);
2781 # if magic quotes GPC is on
2782 if (get_magic_quotes_gpc())
2784 # strip added slashes from incoming variables
2785 $GPC = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
2786 array_walk_recursive($GPC,
2787 array($this,
"UndoMagicQuotes_StripCallback"));
2791 private function UndoMagicQuotes_StripCallback(&$Value, $Key)
2793 $Value = stripslashes($Value);
2800 private function LoadUIFunctions()
2803 "local/interface/%ACTIVEUI%/include",
2804 "interface/%ACTIVEUI%/include",
2805 "local/interface/default/include",
2806 "interface/default/include",
2808 foreach ($Dirs as $Dir)
2810 $Dir = str_replace(
"%ACTIVEUI%", $this->ActiveUI, $Dir);
2813 $FileNames = scandir($Dir);
2814 foreach ($FileNames as $FileName)
2816 if (preg_match(
"/^F-([A-Za-z_]+)\.php/", $FileName, $Matches)
2817 || preg_match(
"/^F-([A-Za-z_]+)\.html/", $FileName, $Matches))
2819 if (!function_exists($Matches[1]))
2821 include_once($Dir.
"/".$FileName);
2834 private function ProcessPeriodicEvent($EventName, $Callback)
2836 # retrieve last execution time for event if available
2837 $Signature = self::GetCallbackSignature($Callback);
2838 $LastRun = $this->DB->Query(
"SELECT LastRunAt FROM PeriodicEvents"
2839 .
" WHERE Signature = '".addslashes($Signature).
"'",
"LastRunAt");
2841 # determine whether enough time has passed for event to execute
2842 $ShouldExecute = (($LastRun === NULL)
2843 || (time() > (strtotime($LastRun) + $this->EventPeriods[$EventName])))
2846 # if event should run
2849 # add event to task queue
2850 $WrapperCallback = array(
"ApplicationFramework",
"PeriodicEventWrapper");
2851 $WrapperParameters = array(
2852 $EventName, $Callback, array(
"LastRunAt" => $LastRun));
2856 # add event to list of periodic events
2857 $this->KnownPeriodicEvents[$Signature] = array(
2858 "Period" => $EventName,
2859 "Callback" => $Callback,
2860 "Queued" => $ShouldExecute);
2870 private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
2873 if (!isset($DB)) { $DB =
new Database(); }
2876 $ReturnVal = call_user_func_array($Callback, $Parameters);
2878 # if event is already in database
2879 $Signature = self::GetCallbackSignature($Callback);
2880 if ($DB->Query(
"SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
2881 .
" WHERE Signature = '".addslashes($Signature).
"'",
"EventCount"))
2883 # update last run time for event
2884 $DB->Query(
"UPDATE PeriodicEvents SET LastRunAt = "
2885 .(($EventName ==
"EVENT_PERIODIC")
2886 ?
"'".date(
"Y-m-d H:i:s", time() + ($ReturnVal * 60)).
"'"
2888 .
" WHERE Signature = '".addslashes($Signature).
"'");
2892 # add last run time for event to database
2893 $DB->Query(
"INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
2894 .
"('".addslashes($Signature).
"', "
2895 .(($EventName ==
"EVENT_PERIODIC")
2896 ?
"'".date(
"Y-m-d H:i:s", time() + ($ReturnVal * 60)).
"'"
2906 private static function GetCallbackSignature($Callback)
2908 return !is_array($Callback) ? $Callback
2909 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
2917 private function PrepForTSR()
2919 # if HTML has been output and it's time to launch another task
2920 # (only TSR if HTML has been output because otherwise browsers
2921 # may misbehave after connection is closed)
2922 if (($this->JumpToPage || !$this->SuppressHTML)
2923 && (time() > (strtotime($this->Settings[
"LastTaskRunAt"])
2924 + (ini_get(
"max_execution_time")
2925 / $this->Settings[
"MaxTasksRunning"]) + 5))
2927 && $this->Settings[
"TaskExecutionEnabled"])
2929 # begin buffering output for TSR
2932 # let caller know it is time to launch another task
2937 # let caller know it is not time to launch another task
2946 private function LaunchTSR()
2948 # set headers to close out connection to browser
2951 ignore_user_abort(TRUE);
2952 header(
"Connection: close");
2953 header(
"Content-Length: ".ob_get_length());
2956 # output buffered content
2957 while (ob_get_level()) { ob_end_flush(); }
2960 # write out any outstanding data and end HTTP session
2961 session_write_close();
2963 # set flag indicating that we are now running in background
2964 $this->RunningInBackground = TRUE;
2966 # if there is still a task in the queue
2969 # turn on output buffering to (hopefully) record any crash output
2972 # lock tables and grab last task run time to double check
2973 $this->DB->Query(
"LOCK TABLES ApplicationFrameworkSettings WRITE");
2974 $this->LoadSettings();
2976 # if still time to launch another task
2977 if (time() > (strtotime($this->Settings[
"LastTaskRunAt"])
2978 + (ini_get(
"max_execution_time")
2979 / $this->Settings[
"MaxTasksRunning"]) + 5))
2981 # update the "last run" time and release tables
2982 $this->DB->Query(
"UPDATE ApplicationFrameworkSettings"
2983 .
" SET LastTaskRunAt = '".date(
"Y-m-d H:i:s").
"'");
2984 $this->DB->Query(
"UNLOCK TABLES");
2986 # run tasks while there is a task in the queue and enough time left
2990 $this->RunNextTask();
2998 $this->DB->Query(
"UNLOCK TABLES");
3010 private function GetTaskList($DBQuery, $Count, $Offset)
3012 $this->DB->Query($DBQuery.
" LIMIT ".intval($Offset).
",".intval($Count));
3014 while ($Row = $this->DB->FetchRow())
3016 $Tasks[$Row[
"TaskId"]] = $Row;
3017 if ($Row[
"Callback"] ==
3018 serialize(array(
"ApplicationFramework",
"PeriodicEventWrapper")))
3020 $WrappedCallback = unserialize($Row[
"Parameters"]);
3021 $Tasks[$Row[
"TaskId"]][
"Callback"] = $WrappedCallback[1];
3022 $Tasks[$Row[
"TaskId"]][
"Parameters"] = NULL;
3026 $Tasks[$Row[
"TaskId"]][
"Callback"] = unserialize($Row[
"Callback"]);
3027 $Tasks[$Row[
"TaskId"]][
"Parameters"] = unserialize($Row[
"Parameters"]);
3036 private function RunNextTask()
3038 # lock tables to prevent same task from being run by multiple sessions
3039 $this->DB->Query(
"LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
3041 # look for task at head of queue
3042 $this->DB->Query(
"SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
3043 $Task = $this->DB->FetchRow();
3045 # if there was a task available
3048 # move task from queue to running tasks list
3049 $this->DB->Query(
"INSERT INTO RunningTasks "
3050 .
"(TaskId,Callback,Parameters,Priority,Description) "
3051 .
"SELECT * FROM TaskQueue WHERE TaskId = "
3052 .intval($Task[
"TaskId"]));
3053 $this->DB->Query(
"DELETE FROM TaskQueue WHERE TaskId = "
3054 .intval($Task[
"TaskId"]));
3056 # release table locks to again allow other sessions to run tasks
3057 $this->DB->Query(
"UNLOCK TABLES");
3059 # unpack stored task info
3060 $Callback = unserialize($Task[
"Callback"]);
3061 $Parameters = unserialize($Task[
"Parameters"]);
3063 # attempt to load task callback if not already available
3067 $this->RunningTask = $Task;
3070 call_user_func_array($Callback, $Parameters);
3074 call_user_func($Callback);
3076 unset($this->RunningTask);
3078 # remove task from running tasks list
3079 $this->DB->Query(
"DELETE FROM RunningTasks"
3080 .
" WHERE TaskId = ".intval($Task[
"TaskId"]));
3082 # prune running tasks list if necessary
3083 $RunningTasksCount = $this->DB->Query(
3084 "SELECT COUNT(*) AS TaskCount FROM RunningTasks",
"TaskCount");
3085 if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
3087 $this->DB->Query(
"DELETE FROM RunningTasks ORDER BY StartedAt"
3088 .
" LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
3093 # release table locks to again allow other sessions to run tasks
3094 $this->DB->Query(
"UNLOCK TABLES");
3105 if (isset($this->RunningTask))
3107 if (function_exists(
"error_get_last"))
3109 $CrashInfo[
"LastError"] = error_get_last();
3111 if (ob_get_length() !== FALSE)
3113 $CrashInfo[
"OutputBuffer"] = ob_get_contents();
3115 if (isset($CrashInfo))
3118 $DB->Query(
"UPDATE RunningTasks SET CrashInfo = '"
3119 .addslashes(serialize($CrashInfo))
3120 .
"' WHERE TaskId = ".intval($this->RunningTask[
"TaskId"]));
3144 private function AddToDirList($DirList, $Dir, $SearchLast, $SkipSlashCheck)
3146 # convert incoming directory to array of directories (if needed)
3147 $Dirs = is_array($Dir) ? $Dir : array($Dir);
3149 # reverse array so directories are searched in specified order
3150 $Dirs = array_reverse($Dirs);
3152 # for each directory
3153 foreach ($Dirs as $Location)
3155 # make sure directory includes trailing slash
3156 if (!$SkipSlashCheck)
3158 $Location = $Location
3159 .((substr($Location, -1) !=
"/") ?
"/" :
"");
3162 # remove directory from list if already present
3163 if (in_array($Location, $DirList))
3165 $DirList = array_diff(
3166 $DirList, array($Location));
3169 # add directory to list of directories
3172 array_push($DirList, $Location);
3176 array_unshift($DirList, $Location);
3180 # return updated directory list to caller
3191 private function ArrayPermutations(
$Items, $Perms = array())
3195 $Result = array($Perms);
3200 for ($Index = count(
$Items) - 1; $Index >= 0; --$Index)
3204 list($Segment) = array_splice($NewItems, $Index, 1);
3205 array_unshift($NewPerms, $Segment);
3206 $Result = array_merge($Result,
3207 $this->ArrayPermutations($NewItems, $NewPerms));
3219 private function OutputModificationCallbackShell($Matches)
3221 # call previously-stored external function
3222 return call_user_func($this->OutputModificationCallbackInfo[
"Callback"],
3224 $this->OutputModificationCallbackInfo[
"Pattern"],
3225 $this->OutputModificationCallbackInfo[
"Page"],
3226 $this->OutputModificationCallbackInfo[
"SearchPattern"]);
3230 private $InterfaceDirList = array(
3231 "local/interface/%ACTIVEUI%/",
3232 "interface/%ACTIVEUI%/",
3233 "local/interface/default/",
3234 "interface/default/",
3240 private $IncludeDirList = array(
3241 "local/interface/%ACTIVEUI%/include/",
3242 "interface/%ACTIVEUI%/include/",
3243 "local/interface/default/include/",
3244 "interface/default/include/",
3247 private $ImageDirList = array(
3248 "local/interface/%ACTIVEUI%/images/",
3249 "interface/%ACTIVEUI%/images/",
3250 "local/interface/default/images/",
3251 "interface/default/images/",
3254 private $FunctionDirList = array(
3255 "local/interface/%ACTIVEUI%/include/",
3256 "interface/%ACTIVEUI%/include/",
3257 "local/interface/default/include/",
3258 "interface/default/include/",
3263 const NOVALUE =
".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
const LOGLVL_ERROR
ERROR error logging level.
LoggingLevel($NewValue=NULL)
Get/set logging level.
GetOrphanedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
SuppressHTMLOutput($NewSetting=TRUE)
Suppress loading of HTML files.
AddInterfaceDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for user interface (HTML/TPL) files.
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.
static GetScriptUrl()
Retrieve SCRIPT_URL server value, pulling it from elsewhere if that variable isn't set...
const LOGLVL_INFO
INFO error logging level.
AddUnbufferedCallback($Callback, $Parameters=array())
Add a callback that will not be executed after buffered content has been output and that won't have i...
QueueUniqueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue if not already in queue or currently running.
const LOGLVL_FATAL
FATAL error logging level.
UseMinimizedJavascript($NewSetting=NULL)
Get/set whether or not to check for and use minimized JavaScript files when getting a JavaScript UI f...
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.
GetCleanUrlForPath($Path)
Get the clean URL mapped for a path.
const PRIORITY_LOW
Lower priority.
Abstraction for forum messages and resource comments.
GetQueuedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
LogFile($NewValue=NULL)
Get/set log file name.
GetCleanUrl()
Get the clean URL for the current page if one is available.
MaxExecutionTime($NewValue=NULL)
Get/set maximum PHP execution time.
RequireUIFile($FileName)
Add file to list of required UI files.
Top-level framework for web applications.
static BaseUrl()
Get current base URL (usually the part before index.php).
GetOrphanedTaskCount()
Retrieve current number of orphaned tasks.
SQL database abstraction object with smart query caching.
GetTaskQueueSize($Priority=NULL)
Retrieve current number of tasks in queue.
GetQueuedTaskCount($Callback=NULL, $Parameters=NULL, $Priority=NULL, $Description=NULL)
Get number of queued tasks that match supplied values.
DeleteTask($TaskId)
Remove task from task queues.
const LOGLVL_DEBUG
DEBUG error logging leve.
const EVENTTYPE_NAMED
Named result event type.
const EVENTTYPE_FIRST
First response event type.
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...
const EVENTTYPE_DEFAULT
Default event type.
GetPageUrl()
Get the full URL to the page.
IsStaticOnlyEvent($EventName)
Report whether specified event only allows static callbacks.
IsRegisteredEvent($EventName)
Check if event has been registered (is available to be signaled).
static AddObjectDirectory($Dir, $Prefix="", $ClassPattern=NULL, $ClassReplacement=NULL)
Add directory to be searched for object files when autoloading.
SignalEvent($EventName, $Parameters=NULL)
Signal that an event has occured.
static BasePath()
Get current base path (usually the part after the host name).
const LOGLVL_TRACE
TRACE error logging level.
const LOGLVL_WARNING
WARNING error logging level.
const PRIORITY_MEDIUM
Medium (default) priority.
LogError($Level, $Msg)
Write error message to log.
OnCrash()
Called automatically at program termination to ensure output is written out.
GetKnownPeriodicEvents()
Get list of known periodic events.
const EVENTTYPE_CHAIN
Result chaining event type.
GetSecondsBeforeTimeout()
Get remaining available (PHP) execution time.
TaskIsInQueue($Callback, $Parameters=NULL)
Check if task is already in queue or currently running.
AddFunctionDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for function ("F-") files.
const ORDER_MIDDLE
Run hooked function after ORDER_FIRST and before ORDER_LAST events.
RegisterEvent($EventsOrEventName, $EventType=NULL)
Register one or more events that may be signaled.
SetJumpToPage($Page, $IsLiteral=FALSE)
Set URL of page to autoload after PHP page file is executed.
GetPageName()
Get name of page being loaded.
CleanUrlIsMapped($Path)
Report whether clean URL has already been mapped.
TaskExecutionEnabled($NewValue=NULL)
Get/set whether automatic task execution is enabled.
const PRIORITY_HIGH
Highest priority.
LoadFunction($Callback)
Attempt to load code for function or method if not currently available.
GetRunningTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
FindCommonTemplate($BaseName)
Preserved for backward compatibility for use with code written prior to October 2012.
EventWillNextRunAt($EventName, $Callback)
Get date/time a periodic event will next run.
static SessionLifetime($NewValue=NULL)
Get/set session timeout in seconds.
HookEvent($EventsOrEventName, $Callback=NULL, $Order=self::ORDER_MIDDLE)
Hook one or more functions to be called when the specified event is signaled.
IsHookedEvent($EventName)
Check if an event is registered and is hooked to.
TemplateLocationCacheExpirationInterval($NewInterval=-1)
Get/set UI template location cache expiration period in minutes.
AddImageDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for image files.
HtmlCharset($NewSetting=NULL)
Get/set HTTP character encoding value.
const ORDER_FIRST
Run hooked function first (i.e.
HtaccessSupport()
Determine if .htaccess files are enabled.
GetUncleanUrlForPath($Path)
Get the unclean URL for mapped for a path.
GetUncleanUrl()
Get the unclean URL for the current page.
JumpToPageIsSet()
Report whether a page to autoload has been set.
const ORDER_LAST
Run hooked function last (i.e.
UseBaseTag($NewValue=NULL)
Get/set whether or not to use the "base" tag to ensure relative URL paths are correct.
GetFreeMemory()
Get current amount of free memory.
GetTask($TaskId)
Retrieve task info from queue (either running or queued tasks).
LoadPage($PageName)
Load page PHP and HTML/TPL files.
AddEnvInclude($FileName)
Add file to be included to set up environment.
ReQueueOrphanedTask($TaskId, $NewPriority=NULL)
Move orphaned task back into queue.
GUIFile($FileName)
Search UI directories for specified image or CSS file and return name of correct file.
QueueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue.
MaxTasks($NewValue=NULL)
Get/set maximum number of tasks to have running simultaneously.
GetUserInterfaces()
Get the list of available user interfaces.
PUIFile($FileName)
Search UI directories for specified image or CSS file and print name of correct file.
ActiveUserInterface($UIName=NULL)
Get/set name of current active user interface.
GetPageLocation()
Get the URL path to the page without the base path, if present.
GetElapsedExecutionTime()
Get time elapsed since constructor was called.
SetBrowserDetectionFunc($DetectionFunc)
Specify function to use to detect the web browser type.
AddCleanUrl($Pattern, $Page, $GetVars=NULL, $Template=NULL)
Add clean URL mapping.
const PRIORITY_BACKGROUND
Lowest priority.
LogMessage($Level, $Msg)
Write status message to log.