00001 <?PHP
00002
00003 #
00004 # FILE: ApplicationFramework.php
00005 #
00006 # Part of the ScoutLib application support library
00007 # Copyright 2009-2012 Edward Almasy and Internet Scout
00008 # http://scout.wisc.edu
00009 #
00010
00015 class ApplicationFramework {
00016
00017 # ---- PUBLIC INTERFACE --------------------------------------------------
00018
00020
00028 function __construct($ObjectDirectories = NULL)
00029 {
00030 # save execution start time
00031 $this->ExecutionStartTime = microtime(TRUE);
00032
00033 # save object directory search list
00034 if ($ObjectDirectories) { $this->AddObjectDirectories($ObjectDirectories); }
00035
00036 # set up object file autoloader
00037 $this->SetUpObjectAutoloading();
00038
00039 # set up function to output any buffered text in case of crash
00040 register_shutdown_function(array($this, "OnCrash"));
00041
00042 # set up our internal environment
00043 $this->DB = new Database();
00044
00045 # load our settings from database
00046 $this->LoadSettings();
00047
00048 # set PHP maximum execution time
00049 $this->MaxExecutionTime($this->Settings["MaxExecTime"]);
00050
00051 # register events we handle internally
00052 $this->RegisterEvent($this->PeriodicEvents);
00053 $this->RegisterEvent($this->UIEvents);
00054 }
00061 function __destruct()
00062 {
00063 # if template location cache is flagged to be saved
00064 if ($this->SaveTemplateLocationCache)
00065 {
00066 # write template location cache out and update cache expiration
00067 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
00068 ." SET TemplateLocationCache = '"
00069 .addslashes(serialize(
00070 $this->Settings["TemplateLocationCache"]))."',"
00071 ." TemplateLocationCacheExpiration = "
00072 ." NOW() + INTERVAL "
00073 .$this->Settings["TemplateLocationCacheInterval"]
00074 ." MINUTE");
00075 }
00076 }
00084 function AddObjectDirectories($Dirs)
00085 {
00086 foreach ($Dirs as $Location => $Prefix)
00087 {
00088 $Location = $Location
00089 .((substr($Location, -1) != "/") ? "/" : "");
00090 self::$ObjectDirectories = array_merge(
00091 array($Location => $Prefix),
00092 self::$ObjectDirectories);
00093 }
00094 }
00095
00101 function SetBrowserDetectionFunc($DetectionFunc)
00102 {
00103 $this->BrowserDetectFunc = $DetectionFunc;
00104 }
00105
00112 function AddUnbufferedCallback($Callback, $Parameters=array())
00113 {
00114 if (is_callable($Callback))
00115 {
00116 $this->UnbufferedCallbacks[] = array($Callback, $Parameters);
00117 }
00118 }
00119
00126 function TemplateLocationCacheExpirationInterval($NewInterval = -1)
00127 {
00128 if ($NewInterval >= 0)
00129 {
00130 $this->Settings["TemplateLocationCacheInterval"] = $NewInterval;
00131 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
00132 ." SET TemplateLocationCacheInterval = '"
00133 .intval($NewInterval)."'");
00134 }
00135 return $this->Settings["TemplateLocationCacheInterval"];
00136 }
00137
00142 function LoadPage($PageName)
00143 {
00144 # buffer any output from includes or PHP file
00145 ob_start();
00146
00147 # include any files needed to set up execution environment
00148 foreach ($this->EnvIncludes as $IncludeFile)
00149 {
00150 include($IncludeFile);
00151 }
00152
00153 # sanitize incoming page name
00154 $PageName = preg_replace("/[^a-zA-Z0-9_.-]/", "", $PageName);
00155
00156 # signal page load
00157 $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName));
00158
00159 # signal PHP file load
00160 $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array(
00161 "PageName" => $PageName));
00162
00163 # if signal handler returned new page name value
00164 $NewPageName = $PageName;
00165 if (($SignalResult["PageName"] != $PageName)
00166 && strlen($SignalResult["PageName"]))
00167 {
00168 # if new page name value is page file
00169 if (file_exists($SignalResult["PageName"]))
00170 {
00171 # use new value for PHP file name
00172 $PageFile = $SignalResult["PageName"];
00173 }
00174 else
00175 {
00176 # use new value for page name
00177 $NewPageName = $SignalResult["PageName"];
00178 }
00179 }
00180
00181 # if we do not already have a PHP file
00182 if (!isset($PageFile))
00183 {
00184 # look for PHP file for page
00185 $OurPageFile = "pages/".$NewPageName.".php";
00186 $LocalPageFile = "local/pages/".$NewPageName.".php";
00187 $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
00188 : (file_exists($OurPageFile) ? $OurPageFile
00189 : "pages/".$this->DefaultPage.".php");
00190 }
00191
00192 # load PHP file
00193 include($PageFile);
00194
00195 # save buffered output to be displayed later after HTML file loads
00196 $PageOutput = ob_get_contents();
00197 ob_end_clean();
00198
00199 # set up for possible TSR (Terminate and Stay Resident :))
00200 $ShouldTSR = $this->PrepForTSR();
00201
00202 # if PHP file indicated we should autorefresh to somewhere else
00203 if ($this->JumpToPage)
00204 {
00205 if (!strlen(trim($PageOutput)))
00206 {
00207 ?><html>
00208 <head>
00209 <meta http-equiv="refresh" content="0; URL=<?PHP
00210 print($this->JumpToPage); ?>">
00211 </head>
00212 <body bgcolor="white">
00213 </body>
00214 </html><?PHP
00215 }
00216 }
00217 # else if HTML loading is not suppressed
00218 elseif (!$this->SuppressHTML)
00219 {
00220 # set content-type to get rid of diacritic errors
00221 header("Content-Type: text/html; charset="
00222 .$this->HtmlCharset, TRUE);
00223
00224 # load common HTML file (defines common functions) if available
00225 $CommonHtmlFile = $this->FindCommonTemplate("Common");
00226 if ($CommonHtmlFile) { include($CommonHtmlFile); }
00227
00228 # load UI functions
00229 $this->LoadUIFunctions();
00230
00231 # begin buffering content
00232 ob_start();
00233
00234 # signal HTML file load
00235 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array(
00236 "PageName" => $PageName));
00237
00238 # if signal handler returned new page name value
00239 $NewPageName = $PageName;
00240 $PageContentFile = NULL;
00241 if (($SignalResult["PageName"] != $PageName)
00242 && strlen($SignalResult["PageName"]))
00243 {
00244 # if new page name value is HTML file
00245 if (file_exists($SignalResult["PageName"]))
00246 {
00247 # use new value for HTML file name
00248 $PageContentFile = $SignalResult["PageName"];
00249 }
00250 else
00251 {
00252 # use new value for page name
00253 $NewPageName = $SignalResult["PageName"];
00254 }
00255 }
00256
00257 # load page content HTML file if available
00258 if ($PageContentFile === NULL)
00259 {
00260 $PageContentFile = $this->FindTemplate(
00261 $this->ContentTemplateList, $NewPageName);
00262 }
00263 if ($PageContentFile)
00264 {
00265 include($PageContentFile);
00266 }
00267 else
00268 {
00269 print "<h2>ERROR: No HTML/TPL template found"
00270 ." for this page.</h2>";
00271 }
00272
00273 # signal HTML file load complete
00274 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE");
00275
00276 # stop buffering and save output
00277 $PageContentOutput = ob_get_contents();
00278 ob_end_clean();
00279
00280 # load page start HTML file if available
00281 ob_start();
00282 $PageStartFile = $this->FindCommonTemplate("Start");
00283 if ($PageStartFile) { include($PageStartFile); }
00284 $PageStartOutput = ob_get_contents();
00285 ob_end_clean();
00286
00287 # load page end HTML file if available
00288 ob_start();
00289 $PageEndFile = $this->FindCommonTemplate("End");
00290 if ($PageEndFile) { include($PageEndFile); }
00291 $PageEndOutput = ob_get_contents();
00292 ob_end_clean();
00293
00294 # get list of any required files not loaded
00295 $RequiredFiles = $this->GetRequiredFilesNotYetLoaded($PageContentFile);
00296
00297 # if a browser detection function has been made available
00298 if (is_callable($this->BrowserDetectFunc))
00299 {
00300 # call function to get browser list
00301 $Browsers = call_user_func($this->BrowserDetectFunc);
00302
00303 # for each required file
00304 $NewRequiredFiles = array();
00305 foreach ($RequiredFiles as $File)
00306 {
00307 # if file name includes browser keyword
00308 if (preg_match("/%BROWSER%/", $File))
00309 {
00310 # for each browser
00311 foreach ($Browsers as $Browser)
00312 {
00313 # substitute in browser name and add to new file list
00314 $NewRequiredFiles[] = preg_replace(
00315 "/%BROWSER%/", $Browser, $File);
00316 }
00317 }
00318 else
00319 {
00320 # add to new file list
00321 $NewRequiredFiles[] = $File;
00322 }
00323 }
00324 $RequiredFiles = $NewRequiredFiles;
00325 }
00326
00327 # for each required file
00328 foreach ($RequiredFiles as $File)
00329 {
00330 # locate specific file to use
00331 $FilePath = $this->GUIFile($File);
00332
00333 # if file was found
00334 if ($FilePath)
00335 {
00336 # determine file type
00337 $NamePieces = explode(".", $File);
00338 $FileSuffix = strtolower(array_pop($NamePieces));
00339
00340 # add file to HTML output based on file type
00341 $FilePath = htmlspecialchars($FilePath);
00342 switch ($FileSuffix)
00343 {
00344 case "js":
00345 $Tag = '<script type="text/javascript" src="'
00346 .$FilePath.'"></script>';
00347 $PageEndOutput = preg_replace(
00348 "#</body>#i", $Tag."\n</body>", $PageEndOutput, 1);
00349 break;
00350
00351 case "css":
00352 $Tag = '<link rel="stylesheet" type="text/css"'
00353 .' media="all" href="'.$FilePath.'">';
00354 $PageStartOutput = preg_replace(
00355 "#</head>#i", $Tag."\n</head>", $PageStartOutput, 1);
00356 break;
00357 }
00358 }
00359 }
00360
00361 # write out page
00362 print $PageStartOutput.$PageContentOutput.$PageEndOutput;
00363 }
00364
00365 # run any post-processing routines
00366 foreach ($this->PostProcessingFuncs as $Func)
00367 {
00368 call_user_func_array($Func["FunctionName"], $Func["Arguments"]);
00369 }
00370
00371 # write out any output buffered from page code execution
00372 if (strlen($PageOutput))
00373 {
00374 if (!$this->SuppressHTML)
00375 {
00376 ?><table width="100%" cellpadding="5"
00377 style="border: 2px solid #666666; background: #CCCCCC;
00378 font-family: Courier New, Courier, monospace;
00379 margin-top: 10px;"><tr><td><?PHP
00380 }
00381 if ($this->JumpToPage)
00382 {
00383 ?><div style="color: #666666;"><span style="font-size: 150%;">
00384 <b>Page Jump Aborted</b></span>
00385 (because of error or other unexpected output)<br />
00386 <b>Jump Target:</b>
00387 <i><?PHP print($this->JumpToPage); ?></i></div><?PHP
00388 }
00389 print($PageOutput);
00390 if (!$this->SuppressHTML)
00391 {
00392 ?></td></tr></table><?PHP
00393 }
00394 }
00395
00396 # execute callbacks that should not have their output buffered
00397 foreach ($this->UnbufferedCallbacks as $Callback)
00398 {
00399 call_user_func_array($Callback[0], $Callback[1]);
00400 }
00401
00402 # terminate and stay resident (TSR!) if indicated and HTML has been output
00403 # (only TSR if HTML has been output because otherwise browsers will misbehave)
00404 if ($ShouldTSR) { $this->LaunchTSR(); }
00405 }
00406
00413 function SetJumpToPage($Page)
00414 {
00415 if ((strpos($Page, "?") === FALSE)
00416 && ((strpos($Page, "=") !== FALSE)
00417 || ((stripos($Page, ".php") === FALSE)
00418 && (stripos($Page, ".htm") === FALSE)
00419 && (strpos($Page, "/") === FALSE)))
00420 && (stripos($Page, "http://") !== 0)
00421 && (stripos($Page, "https://") !== 0))
00422 {
00423 $this->JumpToPage = "index.php?P=".$Page;
00424 }
00425 else
00426 {
00427 $this->JumpToPage = $Page;
00428 }
00429 }
00430
00435 function JumpToPageIsSet()
00436 {
00437 return ($this->JumpToPage === NULL) ? FALSE : TRUE;
00438 }
00439
00449 function HtmlCharset($NewSetting = NULL)
00450 {
00451 if ($NewSetting !== NULL) { $this->HtmlCharset = $NewSetting; }
00452 return $this->HtmlCharset;
00453 }
00454
00461 function SuppressHTMLOutput($NewSetting = TRUE)
00462 {
00463 $this->SuppressHTML = $NewSetting;
00464 }
00465
00472 function ActiveUserInterface($UIName = NULL)
00473 {
00474 if ($UIName !== NULL)
00475 {
00476 $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
00477 }
00478 return $this->ActiveUI;
00479 }
00480
00496 function AddPostProcessingCall($FunctionName,
00497 &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
00498 &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
00499 &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
00500 {
00501 $FuncIndex = count($this->PostProcessingFuncs);
00502 $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
00503 $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
00504 $Index = 1;
00505 while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
00506 {
00507 $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
00508 =& ${"Arg".$Index};
00509 $Index++;
00510 }
00511 }
00512
00518 function AddEnvInclude($FileName)
00519 {
00520 $this->EnvIncludes[] = $FileName;
00521 }
00522
00529 function GUIFile($FileName)
00530 {
00531 # pull off file name suffix
00532 $NamePieces = explode(".", $FileName);
00533 $Suffix = strtolower(array_pop($NamePieces));
00534
00535 # determine which location to search based on file suffix
00536 $ImageSuffixes = array("gif", "jpg", "png");
00537 $FileList = in_array($Suffix, $ImageSuffixes)
00538 ? $this->ImageFileList : $this->CommonTemplateList;
00539
00540 # search for file
00541 $FoundFileName = $this->FindTemplate($FileList, $FileName);
00542
00543 # add non-image files to list of found files
00544 if (!in_array($Suffix, $ImageSuffixes))
00545 { $this->FoundUIFiles[] = basename($FoundFileName); }
00546
00547 # return file name to caller
00548 return $FoundFileName;
00549 }
00550
00560 function PUIFile($FileName)
00561 {
00562 $FullFileName = $this->GUIFile($FileName);
00563 if ($FullFileName) { print($FullFileName); }
00564 }
00565
00570 function FindCommonTemplate($PageName)
00571 {
00572 return $this->FindTemplate(
00573 array_merge($this->CommonTemplateList, $this->ContentTemplateList),
00574 $PageName);
00575 }
00576
00585 function LoadFunction($Callback)
00586 {
00587 if (!is_callable($Callback) && is_string($Callback))
00588 {
00589 $Locations = $this->FunctionFileList;
00590 foreach (self::$ObjectDirectories as $Location => $Prefix)
00591 {
00592 $Locations[] = $Location."%PAGENAME%.php";
00593 $Locations[] = $Location."%PAGENAME%.html";
00594 }
00595 $FunctionFileName = $this->FindTemplate($Locations, "F-".$Callback);
00596 if ($FunctionFileName)
00597 {
00598 include_once($FunctionFileName);
00599 }
00600 }
00601 return is_callable($Callback);
00602 }
00603
00608 function GetElapsedExecutionTime()
00609 {
00610 return microtime(TRUE) - $this->ExecutionStartTime;
00611 }
00612
00617 function GetSecondsBeforeTimeout()
00618 {
00619 return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
00620 }
00621
00626 function HtaccessSupport()
00627 {
00628 # HTACCESS_SUPPORT is set in the .htaccess file
00629 return isset($_SERVER["HTACCESS_SUPPORT"]);
00630 }
00631
00632
00633
00634 # ---- Event Handling ----------------------------------------------------
00635
00637
00641 const EVENTTYPE_DEFAULT = 1;
00647 const EVENTTYPE_CHAIN = 2;
00653 const EVENTTYPE_FIRST = 3;
00661 const EVENTTYPE_NAMED = 4;
00662
00664 const ORDER_FIRST = 1;
00666 const ORDER_MIDDLE = 2;
00668 const ORDER_LAST = 3;
00669
00678 function RegisterEvent($EventsOrEventName, $EventType = NULL)
00679 {
00680 # convert parameters to array if not already in that form
00681 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00682 : array($EventsOrEventName => $Type);
00683
00684 # for each event
00685 foreach ($Events as $Name => $Type)
00686 {
00687 # store event information
00688 $this->RegisteredEvents[$Name]["Type"] = $Type;
00689 $this->RegisteredEvents[$Name]["Hooks"] = array();
00690 }
00691 }
00692
00706 function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
00707 {
00708 # convert parameters to array if not already in that form
00709 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00710 : array($EventsOrEventName => $Callback);
00711
00712 # for each event
00713 $Success = TRUE;
00714 foreach ($Events as $EventName => $EventCallback)
00715 {
00716 # if callback is valid
00717 if (is_callable($EventCallback))
00718 {
00719 # if this is a periodic event we process internally
00720 if (isset($this->PeriodicEvents[$EventName]))
00721 {
00722 # process event now
00723 $this->ProcessPeriodicEvent($EventName, $EventCallback);
00724 }
00725 # if specified event has been registered
00726 elseif (isset($this->RegisteredEvents[$EventName]))
00727 {
00728 # add callback for event
00729 $this->RegisteredEvents[$EventName]["Hooks"][]
00730 = array("Callback" => $EventCallback, "Order" => $Order);
00731
00732 # sort callbacks by order
00733 if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
00734 {
00735 usort($this->RegisteredEvents[$EventName]["Hooks"],
00736 array("ApplicationFramework", "HookEvent_OrderCompare"));
00737 }
00738 }
00739 else
00740 {
00741 $Success = FALSE;
00742 }
00743 }
00744 else
00745 {
00746 $Success = FALSE;
00747 }
00748 }
00749
00750 # report to caller whether all callbacks were hooked
00751 return $Success;
00752 }
00753 private static function HookEvent_OrderCompare($A, $B)
00754 {
00755 if ($A["Order"] == $B["Order"]) { return 0; }
00756 return ($A["Order"] < $B["Order"]) ? -1 : 1;
00757 }
00758
00767 function SignalEvent($EventName, $Parameters = NULL)
00768 {
00769 $ReturnValue = NULL;
00770
00771 # if event has been registered
00772 if (isset($this->RegisteredEvents[$EventName]))
00773 {
00774 # set up default return value (if not NULL)
00775 switch ($this->RegisteredEvents[$EventName]["Type"])
00776 {
00777 case self::EVENTTYPE_CHAIN:
00778 $ReturnValue = $Parameters;
00779 break;
00780
00781 case self::EVENTTYPE_NAMED:
00782 $ReturnValue = array();
00783 break;
00784 }
00785
00786 # for each callback for this event
00787 foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
00788 {
00789 # invoke callback
00790 $Callback = $Hook["Callback"];
00791 $Result = ($Parameters !== NULL)
00792 ? call_user_func_array($Callback, $Parameters)
00793 : call_user_func($Callback);
00794
00795 # process return value based on event type
00796 switch ($this->RegisteredEvents[$EventName]["Type"])
00797 {
00798 case self::EVENTTYPE_CHAIN:
00799 $ReturnValue = $Result;
00800 $Parameters = $Result;
00801 break;
00802
00803 case self::EVENTTYPE_FIRST:
00804 if ($Result !== NULL)
00805 {
00806 $ReturnValue = $Result;
00807 break 2;
00808 }
00809 break;
00810
00811 case self::EVENTTYPE_NAMED:
00812 $CallbackName = is_array($Callback)
00813 ? (is_object($Callback[0])
00814 ? get_class($Callback[0])
00815 : $Callback[0])."::".$Callback[1]
00816 : $Callback;
00817 $ReturnValue[$CallbackName] = $Result;
00818 break;
00819
00820 default:
00821 break;
00822 }
00823 }
00824 }
00825
00826 # return value if any to caller
00827 return $ReturnValue;
00828 }
00829
00835 function IsStaticOnlyEvent($EventName)
00836 {
00837 return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
00838 }
00839
00840
00841
00842 # ---- Task Management ---------------------------------------------------
00843
00845
00847 const PRIORITY_HIGH = 1;
00849 const PRIORITY_MEDIUM = 2;
00851 const PRIORITY_LOW = 3;
00853 const PRIORITY_BACKGROUND = 4;
00854
00867 function QueueTask($Callback, $Parameters = NULL,
00868 $Priority = self::PRIORITY_MEDIUM, $Description = "")
00869 {
00870 # pack task info and write to database
00871 if ($Parameters === NULL) { $Parameters = array(); }
00872 $this->DB->Query("INSERT INTO TaskQueue"
00873 ." (Callback, Parameters, Priority, Description)"
00874 ." VALUES ('".addslashes(serialize($Callback))."', '"
00875 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
00876 .addslashes($Description)."')");
00877 }
00878
00896 function QueueUniqueTask($Callback, $Parameters = NULL,
00897 $Priority = self::PRIORITY_MEDIUM, $Description = "")
00898 {
00899 if ($this->TaskIsInQueue($Callback, $Parameters))
00900 {
00901 $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
00902 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00903 .($Parameters ? " AND Parameters = '"
00904 .addslashes(serialize($Parameters))."'" : ""));
00905 if ($QueryResult !== FALSE)
00906 {
00907 $Record = $this->DB->FetchRow();
00908 if ($Record["Priority"] > $Priority)
00909 {
00910 $this->DB->Query("UPDATE TaskQueue"
00911 ." SET Priority = ".intval($Priority)
00912 ." WHERE TaskId = ".intval($Record["TaskId"]));
00913 }
00914 }
00915 return FALSE;
00916 }
00917 else
00918 {
00919 $this->QueueTask($Callback, $Parameters, $Priority, $Description);
00920 return TRUE;
00921 }
00922 }
00923
00933 function TaskIsInQueue($Callback, $Parameters = NULL)
00934 {
00935 $FoundCount = $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM TaskQueue"
00936 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00937 .($Parameters ? " AND Parameters = '"
00938 .addslashes(serialize($Parameters))."'" : ""),
00939 "FoundCount")
00940 + $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM RunningTasks"
00941 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00942 .($Parameters ? " AND Parameters = '"
00943 .addslashes(serialize($Parameters))."'" : ""),
00944 "FoundCount");
00945 return ($FoundCount ? TRUE : FALSE);
00946 }
00947
00953 function GetTaskQueueSize($Priority = NULL)
00954 {
00955 return $this->DB->Query("SELECT COUNT(*) AS QueueSize FROM TaskQueue"
00956 .($Priority ? " WHERE Priority = ".intval($Priority) : ""),
00957 "QueueSize");
00958 }
00959
00967 function GetQueuedTaskList($Count = 100, $Offset = 0)
00968 {
00969 return $this->GetTaskList("SELECT * FROM TaskQueue"
00970 ." ORDER BY Priority, TaskId ", $Count, $Offset);
00971 }
00972
00980 function GetRunningTaskList($Count = 100, $Offset = 0)
00981 {
00982 return $this->GetTaskList("SELECT * FROM RunningTasks"
00983 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
00984 (time() - ini_get("max_execution_time")))."'"
00985 ." ORDER BY StartedAt", $Count, $Offset);
00986 }
00987
00995 function GetOrphanedTaskList($Count = 100, $Offset = 0)
00996 {
00997 return $this->GetTaskList("SELECT * FROM RunningTasks"
00998 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
00999 (time() - ini_get("max_execution_time")))."'"
01000 ." ORDER BY StartedAt", $Count, $Offset);
01001 }
01002
01007 function ReQueueOrphanedTask($TaskId)
01008 {
01009 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
01010 $this->DB->Query("INSERT INTO TaskQueue"
01011 ." (Callback,Parameters,Priority,Description) "
01012 ."SELECT Callback, Parameters, Priority, Description"
01013 ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
01014 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
01015 $this->DB->Query("UNLOCK TABLES");
01016 }
01017
01022 function DeleteTask($TaskId)
01023 {
01024 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
01025 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
01026 }
01027
01035 function GetTask($TaskId)
01036 {
01037 # assume task will not be found
01038 $Task = NULL;
01039
01040 # look for task in task queue
01041 $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
01042
01043 # if task was not found in queue
01044 if (!$this->DB->NumRowsSelected())
01045 {
01046 # look for task in running task list
01047 $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = "
01048 .intval($TaskId));
01049 }
01050
01051 # if task was found
01052 if ($this->DB->NumRowsSelected())
01053 {
01054 # if task was periodic
01055 $Row = $this->DB->FetchRow();
01056 if ($Row["Callback"] ==
01057 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
01058 {
01059 # unpack periodic task callback
01060 $WrappedCallback = unserialize($Row["Parameters"]);
01061 $Task["Callback"] = $WrappedCallback[1];
01062 $Task["Parameters"] = $WrappedCallback[2];
01063 }
01064 else
01065 {
01066 # unpack task callback and parameters
01067 $Task["Callback"] = unserialize($Row["Callback"]);
01068 $Task["Parameters"] = unserialize($Row["Parameters"]);
01069 }
01070 }
01071
01072 # return task to caller
01073 return $Task;
01074 }
01075
01081 function MaxTasks($NewValue = NULL)
01082 {
01083 if (func_num_args() && ($NewValue >= 1))
01084 {
01085 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01086 ." SET MaxTasksRunning = '".intval($NewValue)."'");
01087 $this->Settings["MaxTasksRunning"] = intval($NewValue);
01088 }
01089 return $this->Settings["MaxTasksRunning"];
01090 }
01091
01099 function MaxExecutionTime($NewValue = NULL)
01100 {
01101 if (func_num_args() && !ini_get("safe_mode"))
01102 {
01103 if ($NewValue != $this->Settings["MaxExecTime"])
01104 {
01105 $this->Settings["MaxExecTime"] = max($NewValue, 5);
01106 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01107 ." SET MaxExecTime = '"
01108 .intval($this->Settings["MaxExecTime"])."'");
01109 }
01110 ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
01111 set_time_limit($this->Settings["MaxExecTime"]);
01112 }
01113 return ini_get("max_execution_time");
01114 }
01115
01116
01117
01118 # ---- PRIVATE INTERFACE -------------------------------------------------
01119
01120 private $ActiveUI = "default";
01121 private $BrowserDetectFunc;
01122 private $DB;
01123 private $DefaultPage = "Home";
01124 private $EnvIncludes = array();
01125 private $ExecutionStartTime;
01126 private $FoundUIFiles = array();
01127 private $HtmlCharset = "UTF-8";
01128 private $JumpToPage = NULL;
01129 private $MaxRunningTasksToTrack = 250;
01130 private static $ObjectDirectories = array();
01131 private $PostProcessingFuncs = array();
01132 private $RunningTask;
01133 private $Settings;
01134 private $SuppressHTML = FALSE;
01135 private $SaveTemplateLocationCache = FALSE;
01136 private $UnbufferedCallbacks = array();
01137
01138 # set to TRUE to not close browser connection before running
01139 # background tasks (useful when debugging)
01140 private $NoTSR = FALSE;
01141
01142 private $PeriodicEvents = array(
01143 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
01144 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
01145 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
01146 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
01147 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
01148 );
01149 private $UIEvents = array(
01150 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
01151 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
01152 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
01153 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
01154 );
01155
01159 private function LoadSettings()
01160 {
01161 # read settings in from database
01162 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
01163 $this->Settings = $this->DB->FetchRow();
01164
01165 # if settings were not previously initialized
01166 if (!$this->Settings)
01167 {
01168 # initialize settings in database
01169 $this->DB->Query("INSERT INTO ApplicationFrameworkSettings"
01170 ." (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')");
01171
01172 # read new settings in from database
01173 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
01174 $this->Settings = $this->DB->FetchRow();
01175 }
01176
01177 # if template location cache has been saved to database
01178 if (isset($this->Settings["TemplateLocationCache"]))
01179 {
01180 # unserialize cache values into array
01181 $this->Settings["TemplateLocationCache"] =
01182 unserialize($this->Settings["TemplateLocationCache"]);
01183 }
01184 else
01185 {
01186 # start with empty cache
01187 $this->Settings["TemplateLocationCache"] = array();
01188 }
01189 }
01190
01198 private function FindTemplate($FileList, $PageName)
01199 {
01200 # generate template cache index for this page
01201 $CacheIndex = md5(serialize($FileList))
01202 .":".$this->ActiveUI.":".$PageName;
01203
01204 # if we have cached location and cache expiration time has not elapsed
01205 if (($this->Settings["TemplateLocationCacheInterval"] > 0)
01206 && array_key_exists($CacheIndex,
01207 $this->Settings["TemplateLocationCache"])
01208 && (time() < strtotime(
01209 $this->Settings["TemplateLocationCacheExpiration"])))
01210 {
01211 # use template location from cache
01212 $FileNameFound = $this->Settings[
01213 "TemplateLocationCache"][$CacheIndex];
01214 }
01215 else
01216 {
01217 # for each possible template location
01218 $FileNameFound = NULL;
01219 foreach ($FileList as $FileName)
01220 {
01221 # substitute page name and active UI name into path
01222 $FileName = str_replace("%ACTIVEUI%",
01223 $this->ActiveUI, $FileName);
01224 $FileName = str_replace("%PAGENAME%", $PageName, $FileName);
01225
01226 # if template is found at location
01227 if (file_exists($FileName))
01228 {
01229 # save full template file name and stop looking
01230 $FileNameFound = $FileName;
01231 break;
01232 }
01233 }
01234
01235 # save location in cache
01236 $this->Settings["TemplateLocationCache"][$CacheIndex]
01237 = $FileNameFound;
01238
01239 # set flag indicating that cache should be saved
01240 $this->SaveTemplateLocationCache = TRUE;
01241 }
01242
01243 # return full template file name to caller
01244 return $FileNameFound;
01245 }
01246
01253 private function GetRequiredFilesNotYetLoaded($PageContentFile)
01254 {
01255 # start out assuming no files required
01256 $RequiredFiles = array();
01257
01258 # if page content file supplied
01259 if ($PageContentFile)
01260 {
01261 # if file containing list of required files is available
01262 $Path = dirname($PageContentFile);
01263 $RequireListFile = $Path."/REQUIRES";
01264 if (file_exists($RequireListFile))
01265 {
01266 # read in list of required files
01267 $RequestedFiles = file($RequireListFile);
01268
01269 # for each line in required file list
01270 foreach ($RequestedFiles as $Line)
01271 {
01272 # if line is not a comment
01273 $Line = trim($Line);
01274 if (!preg_match("/^#/", $Line))
01275 {
01276 # if file has not already been loaded
01277 if (!in_array($Line, $this->FoundUIFiles))
01278 {
01279 # add to list of required files
01280 $RequiredFiles[] = $Line;
01281 }
01282 }
01283 }
01284 }
01285 }
01286
01287 # return list of required files to caller
01288 return $RequiredFiles;
01289 }
01290
01291 private function SetUpObjectAutoloading()
01292 {
01293 function __autoload($ClassName)
01294 {
01295 ApplicationFramework::AutoloadObjects($ClassName);
01296 }
01297 }
01298
01300 static function AutoloadObjects($ClassName)
01301 {
01302 foreach (self::$ObjectDirectories as $Location => $Prefix)
01303 {
01304 $FileName = $Location.$Prefix.$ClassName.".php";
01305 if (file_exists($FileName))
01306 {
01307 require_once($FileName);
01308 break;
01309 }
01310 }
01311 }
01314 private function LoadUIFunctions()
01315 {
01316 $Dirs = array(
01317 "local/interface/%ACTIVEUI%/include",
01318 "interface/%ACTIVEUI%/include",
01319 "local/interface/default/include",
01320 "interface/default/include",
01321 );
01322 foreach ($Dirs as $Dir)
01323 {
01324 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
01325 if (is_dir($Dir))
01326 {
01327 $FileNames = scandir($Dir);
01328 foreach ($FileNames as $FileName)
01329 {
01330 if (preg_match("/^F-([A-Za-z_]+)\.php/", $FileName, $Matches)
01331 || preg_match("/^F-([A-Za-z_]+)\.html/", $FileName, $Matches))
01332 {
01333 if (!function_exists($Matches[1]))
01334 {
01335 include_once($Dir."/".$FileName);
01336 }
01337 }
01338 }
01339 }
01340 }
01341 }
01342
01343 private function ProcessPeriodicEvent($EventName, $Callback)
01344 {
01345 # retrieve last execution time for event if available
01346 $Signature = self::GetCallbackSignature($Callback);
01347 $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
01348 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
01349
01350 # determine whether enough time has passed for event to execute
01351 $EventPeriods = array(
01352 "EVENT_HOURLY" => 60*60,
01353 "EVENT_DAILY" => 60*60*24,
01354 "EVENT_WEEKLY" => 60*60*24*7,
01355 "EVENT_MONTHLY" => 60*60*24*30,
01356 "EVENT_PERIODIC" => 0,
01357 );
01358 $ShouldExecute = (($LastRun === NULL)
01359 || (time() > (strtotime($LastRun) + $EventPeriods[$EventName])))
01360 ? TRUE : FALSE;
01361
01362 # if event should run
01363 if ($ShouldExecute)
01364 {
01365 # add event to task queue
01366 $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
01367 $WrapperParameters = array(
01368 $EventName, $Callback, array("LastRunAt" => $LastRun));
01369 $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
01370 }
01371 }
01372
01373 private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
01374 {
01375 static $DB;
01376 if (!isset($DB)) { $DB = new Database(); }
01377
01378 # run event
01379 $ReturnVal = call_user_func_array($Callback, $Parameters);
01380
01381 # if event is already in database
01382 $Signature = self::GetCallbackSignature($Callback);
01383 if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
01384 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
01385 {
01386 # update last run time for event
01387 $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
01388 .(($EventName == "EVENT_PERIODIC")
01389 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01390 : "NOW()")
01391 ." WHERE Signature = '".addslashes($Signature)."'");
01392 }
01393 else
01394 {
01395 # add last run time for event to database
01396 $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
01397 ."('".addslashes($Signature)."', "
01398 .(($EventName == "EVENT_PERIODIC")
01399 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01400 : "NOW()").")");
01401 }
01402 }
01403
01404 private static function GetCallbackSignature($Callback)
01405 {
01406 return !is_array($Callback) ? $Callback
01407 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
01408 ."::".$Callback[1];
01409 }
01410
01411 private function PrepForTSR()
01412 {
01413 # if HTML has been output and it's time to launch another task
01414 # (only TSR if HTML has been output because otherwise browsers
01415 # may misbehave after connection is closed)
01416 if (($this->JumpToPage || !$this->SuppressHTML)
01417 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
01418 + (ini_get("max_execution_time")
01419 / $this->Settings["MaxTasksRunning"]) + 5))
01420 && $this->GetTaskQueueSize())
01421 {
01422 # begin buffering output for TSR
01423 ob_start();
01424
01425 # let caller know it is time to launch another task
01426 return TRUE;
01427 }
01428 else
01429 {
01430 # let caller know it is not time to launch another task
01431 return FALSE;
01432 }
01433 }
01434
01435 private function LaunchTSR()
01436 {
01437 # set needed headers and
01438 if (!$this->NoTSR)
01439 {
01440 ignore_user_abort(TRUE);
01441 header("Connection: close");
01442 header("Content-Length: ".ob_get_length());
01443 }
01444
01445 # output buffered content
01446 ob_end_flush();
01447 flush();
01448
01449 # write out any outstanding data and end HTTP session
01450 session_write_close();
01451
01452 # if there is still a task in the queue
01453 if ($this->GetTaskQueueSize())
01454 {
01455 # turn on output buffering to (hopefully) record any crash output
01456 ob_start();
01457
01458 # lock tables and grab last task run time to double check
01459 $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
01460 $this->LoadSettings();
01461
01462 # if still time to launch another task
01463 if (time() > (strtotime($this->Settings["LastTaskRunAt"])
01464 + (ini_get("max_execution_time")
01465 / $this->Settings["MaxTasksRunning"]) + 5))
01466 {
01467 # update the "last run" time and release tables
01468 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01469 ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
01470 $this->DB->Query("UNLOCK TABLES");
01471
01472 # run tasks while there is a task in the queue and enough time left
01473 do
01474 {
01475 # run the next task
01476 $this->RunNextTask();
01477 }
01478 while ($this->GetTaskQueueSize()
01479 && ($this->GetSecondsBeforeTimeout() > 65));
01480 }
01481 else
01482 {
01483 # release tables
01484 $this->DB->Query("UNLOCK TABLES");
01485 }
01486 }
01487 }
01488
01496 private function GetTaskList($DBQuery, $Count, $Offset)
01497 {
01498 $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
01499 $Tasks = array();
01500 while ($Row = $this->DB->FetchRow())
01501 {
01502 $Tasks[$Row["TaskId"]] = $Row;
01503 if ($Row["Callback"] ==
01504 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
01505 {
01506 $WrappedCallback = unserialize($Row["Parameters"]);
01507 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
01508 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
01509 }
01510 else
01511 {
01512 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
01513 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
01514 }
01515 }
01516 return $Tasks;
01517 }
01518
01522 private function RunNextTask()
01523 {
01524 # look for task at head of queue
01525 $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
01526 $Task = $this->DB->FetchRow();
01527
01528 # if there was a task available
01529 if ($Task)
01530 {
01531 # move task from queue to running tasks list
01532 $this->DB->Query("INSERT INTO RunningTasks "
01533 ."(TaskId,Callback,Parameters,Priority,Description) "
01534 ."SELECT * FROM TaskQueue WHERE TaskId = "
01535 .intval($Task["TaskId"]));
01536 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
01537 .intval($Task["TaskId"]));
01538
01539 # unpack stored task info
01540 $Callback = unserialize($Task["Callback"]);
01541 $Parameters = unserialize($Task["Parameters"]);
01542
01543 # attempt to load task callback if not already available
01544 $this->LoadFunction($Callback);
01545
01546 # run task
01547 $this->RunningTask = $Task;
01548 if ($Parameters)
01549 {
01550 call_user_func_array($Callback, $Parameters);
01551 }
01552 else
01553 {
01554 call_user_func($Callback);
01555 }
01556 unset($this->RunningTask);
01557
01558 # remove task from running tasks list
01559 $this->DB->Query("DELETE FROM RunningTasks"
01560 ." WHERE TaskId = ".intval($Task["TaskId"]));
01561
01562 # prune running tasks list if necessary
01563 $RunningTasksCount = $this->DB->Query(
01564 "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
01565 if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
01566 {
01567 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
01568 ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
01569 }
01570 }
01571 }
01572
01578 function OnCrash()
01579 {
01580 if (isset($this->RunningTask))
01581 {
01582 if (function_exists("error_get_last"))
01583 {
01584 $CrashInfo["LastError"] = error_get_last();
01585 }
01586 if (ob_get_length() !== FALSE)
01587 {
01588 $CrashInfo["OutputBuffer"] = ob_get_contents();
01589 }
01590 if (isset($CrashInfo))
01591 {
01592 $DB = new Database();
01593 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
01594 .addslashes(serialize($CrashInfo))
01595 ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
01596 }
01597 }
01598
01599 print("\n");
01600 return;
01601
01602 if (ob_get_length() !== FALSE)
01603 {
01604 ?>
01605 <table width="100%" cellpadding="5" style="border: 2px solid #666666; background: #FFCCCC; font-family: Courier New, Courier, monospace; margin-top: 10px; font-weight: bold;"><tr><td>
01606 <div style="font-size: 200%;">CRASH OUTPUT</div><?PHP
01607 ob_end_flush();
01608 ?></td></tr></table><?PHP
01609 }
01610 }
01611
01612 private $CommonTemplateList = array(
01613 "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01614 "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01615 "local/interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01616 "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01617 "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01618 "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01619 "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01620 "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01621 "local/interface/%ACTIVEUI%/include/%PAGENAME%",
01622 "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01623 "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01624 "interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01625 "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01626 "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01627 "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01628 "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01629 "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01630 "interface/%ACTIVEUI%/include/%PAGENAME%",
01631 "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01632 "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01633 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.tpl",
01634 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01635 "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01636 "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01637 "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01638 "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01639 "SPTUI--%ACTIVEUI%/include/%PAGENAME%",
01640 "%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01641 "%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01642 "%ACTIVEUI%/include/%PAGENAME%.tpl",
01643 "%ACTIVEUI%/include/%PAGENAME%.html",
01644 "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01645 "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01646 "%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01647 "%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01648 "%ACTIVEUI%/include/%PAGENAME%",
01649 "local/interface/default/include/StdPage%PAGENAME%.tpl",
01650 "local/interface/default/include/StdPage%PAGENAME%.html",
01651 "local/interface/default/include/%PAGENAME%.tpl",
01652 "local/interface/default/include/%PAGENAME%.html",
01653 "local/interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01654 "local/interface/default/include/SPT--StandardPage%PAGENAME%.html",
01655 "local/interface/default/include/SPT--%PAGENAME%.tpl",
01656 "local/interface/default/include/SPT--%PAGENAME%.html",
01657 "local/interface/default/include/%PAGENAME%",
01658 "interface/default/include/StdPage%PAGENAME%.tpl",
01659 "interface/default/include/StdPage%PAGENAME%.html",
01660 "interface/default/include/%PAGENAME%.tpl",
01661 "interface/default/include/%PAGENAME%.html",
01662 "interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01663 "interface/default/include/SPT--StandardPage%PAGENAME%.html",
01664 "interface/default/include/SPT--%PAGENAME%.tpl",
01665 "interface/default/include/SPT--%PAGENAME%.html",
01666 "interface/default/include/%PAGENAME%",
01667 );
01668 private $ContentTemplateList = array(
01669 "local/interface/%ACTIVEUI%/%PAGENAME%.tpl",
01670 "local/interface/%ACTIVEUI%/%PAGENAME%.html",
01671 "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01672 "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01673 "interface/%ACTIVEUI%/%PAGENAME%.tpl",
01674 "interface/%ACTIVEUI%/%PAGENAME%.html",
01675 "interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01676 "interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01677 "SPTUI--%ACTIVEUI%/%PAGENAME%.tpl",
01678 "SPTUI--%ACTIVEUI%/%PAGENAME%.html",
01679 "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01680 "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.html",
01681 "%ACTIVEUI%/%PAGENAME%.tpl",
01682 "%ACTIVEUI%/%PAGENAME%.html",
01683 "%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01684 "%ACTIVEUI%/SPT--%PAGENAME%.html",
01685 "local/interface/default/%PAGENAME%.tpl",
01686 "local/interface/default/%PAGENAME%.html",
01687 "local/interface/default/SPT--%PAGENAME%.tpl",
01688 "local/interface/default/SPT--%PAGENAME%.html",
01689 "interface/default/%PAGENAME%.tpl",
01690 "interface/default/%PAGENAME%.html",
01691 "interface/default/SPT--%PAGENAME%.tpl",
01692 "interface/default/SPT--%PAGENAME%.html",
01693 );
01694 private $ImageFileList = array(
01695 "local/interface/%ACTIVEUI%/images/%PAGENAME%",
01696 "interface/%ACTIVEUI%/images/%PAGENAME%",
01697 "SPTUI--%ACTIVEUI%/images/%PAGENAME%",
01698 "%ACTIVEUI%/images/%PAGENAME%",
01699 "local/interface/default/images/%PAGENAME%",
01700 "interface/default/images/%PAGENAME%",
01701 );
01702 private $FunctionFileList = array(
01703 "local/interface/%ACTIVEUI%/include/%PAGENAME%.php",
01704 "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01705 "interface/%ACTIVEUI%/include/%PAGENAME%.php",
01706 "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01707 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.php",
01708 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01709 "%ACTIVEUI%/include/%PAGENAME%.php",
01710 "%ACTIVEUI%/include/%PAGENAME%.html",
01711 "local/interface/default/include/%PAGENAME%.php",
01712 "local/interface/default/include/%PAGENAME%.html",
01713 "local/include/%PAGENAME%.php",
01714 "local/include/%PAGENAME%.html",
01715 "interface/default/include/%PAGENAME%.php",
01716 "interface/default/include/%PAGENAME%.html",
01717 "include/%PAGENAME%.php",
01718 "include/%PAGENAME%.html",
01719 );
01720
01721 const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
01722 };
01723
01724
01725 ?>