ApplicationFramework.php
Go to the documentation of this file.
00001 <?PHP 00002 00003 # 00004 # FILE: ApplicationFramework.php 00005 # 00006 # Part of the ScoutLib application support library 00007 # Copyright 2009-2011 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->DB->Query("SELECT * FROM ApplicationFrameworkSettings"); 00047 $this->Settings = $this->DB->FetchRow(); 00048 if (!$this->Settings) 00049 { 00050 $this->DB->Query("INSERT INTO ApplicationFrameworkSettings" 00051 ." (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')"); 00052 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings"); 00053 $this->Settings = $this->DB->FetchRow(); 00054 } 00055 00056 # set PHP maximum execution time 00057 $this->MaxExecutionTime($this->Settings["MaxExecTime"]); 00058 00059 # register events we handle internally 00060 $this->RegisterEvent($this->PeriodicEvents); 00061 $this->RegisterEvent($this->UIEvents); 00062 } 00070 function AddObjectDirectories($Dirs) 00071 { 00072 foreach ($Dirs as $Location => $Prefix) 00073 { 00074 $Location = $Location 00075 .((substr($Location, -1) != "/") ? "/" : ""); 00076 self::$ObjectDirectories = array_merge( 00077 array($Location => $Prefix), 00078 self::$ObjectDirectories); 00079 } 00080 } 00081 00087 function SetBrowserDetectionFunc($DetectionFunc) 00088 { 00089 $this->BrowserDetectFunc = $DetectionFunc; 00090 } 00091 00096 function LoadPage($PageName) 00097 { 00098 # buffer any output from includes or PHP file 00099 ob_start(); 00100 00101 # include any files needed to set up execution environment 00102 foreach ($this->EnvIncludes as $IncludeFile) 00103 { 00104 include($IncludeFile); 00105 } 00106 00107 # sanitize incoming page name 00108 $PageName = preg_replace("/[^a-zA-Z0-9_.-]/", "", $PageName); 00109 00110 # signal page load 00111 $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName)); 00112 00113 # signal PHP file load 00114 $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array( 00115 "PageName" => $PageName)); 00116 00117 # if signal handler returned new page name value 00118 $NewPageName = $PageName; 00119 if (($SignalResult["PageName"] != $PageName) 00120 && strlen($SignalResult["PageName"])) 00121 { 00122 # if new page name value is page file 00123 if (file_exists($SignalResult["PageName"])) 00124 { 00125 # use new value for PHP file name 00126 $PageFile = $SignalResult["PageName"]; 00127 } 00128 else 00129 { 00130 # use new value for page name 00131 $NewPageName = $SignalResult["PageName"]; 00132 } 00133 } 00134 00135 # if we do not already have a PHP file 00136 if (!isset($PageFile)) 00137 { 00138 # look for PHP file for page 00139 $OurPageFile = "pages/".$NewPageName.".php"; 00140 $LocalPageFile = "local/pages/".$NewPageName.".php"; 00141 $PageFile = file_exists($LocalPageFile) ? $LocalPageFile 00142 : (file_exists($OurPageFile) ? $OurPageFile 00143 : "pages/".$this->DefaultPage.".php"); 00144 } 00145 00146 # load PHP file 00147 include($PageFile); 00148 00149 # save buffered output to be displayed later after HTML file loads 00150 $PageOutput = ob_get_contents(); 00151 ob_end_clean(); 00152 00153 # set up for possible TSR (Terminate and Stay Resident :)) 00154 $ShouldTSR = $this->PrepForTSR(); 00155 00156 # if PHP file indicated we should autorefresh to somewhere else 00157 if ($this->JumpToPage) 00158 { 00159 if (!strlen(trim($PageOutput))) 00160 { 00161 ?><html> 00162 <head> 00163 <meta http-equiv="refresh" content="0; URL=<?PHP 00164 print($this->JumpToPage); ?>"> 00165 </head> 00166 <body bgcolor="white"> 00167 </body> 00168 </html><?PHP 00169 } 00170 } 00171 # else if HTML loading is not suppressed 00172 elseif (!$this->SuppressHTML) 00173 { 00174 # set content-type to get rid of diacritic errors 00175 header("Content-Type: text/html; charset=" 00176 .$this->HtmlCharset, TRUE); 00177 00178 # load common HTML file (defines common functions) if available 00179 $CommonHtmlFile = $this->FindCommonTemplate("Common"); 00180 if ($CommonHtmlFile) { include($CommonHtmlFile); } 00181 00182 # load UI functions 00183 $this->LoadUIFunctions(); 00184 00185 # begin buffering content 00186 ob_start(); 00187 00188 # signal HTML file load 00189 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array( 00190 "PageName" => $PageName)); 00191 00192 # if signal handler returned new page name value 00193 $NewPageName = $PageName; 00194 $PageContentFile = NULL; 00195 if (($SignalResult["PageName"] != $PageName) 00196 && strlen($SignalResult["PageName"])) 00197 { 00198 # if new page name value is HTML file 00199 if (file_exists($SignalResult["PageName"])) 00200 { 00201 # use new value for HTML file name 00202 $PageContentFile = $SignalResult["PageName"]; 00203 } 00204 else 00205 { 00206 # use new value for page name 00207 $NewPageName = $SignalResult["PageName"]; 00208 } 00209 } 00210 00211 # load page content HTML file if available 00212 if ($PageContentFile === NULL) 00213 { 00214 $PageContentFile = $this->FindTemplate( 00215 $this->ContentTemplateList, $NewPageName); 00216 } 00217 if ($PageContentFile) 00218 { 00219 include($PageContentFile); 00220 } 00221 else 00222 { 00223 print "<h2>ERROR: No HTML/TPL template found" 00224 ." for this page.</h2>"; 00225 } 00226 00227 # signal HTML file load complete 00228 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE"); 00229 00230 # stop buffering and save output 00231 $PageContentOutput = ob_get_contents(); 00232 ob_end_clean(); 00233 00234 # load page start HTML file if available 00235 ob_start(); 00236 $PageStartFile = $this->FindCommonTemplate("Start"); 00237 if ($PageStartFile) { include($PageStartFile); } 00238 $PageStartOutput = ob_get_contents(); 00239 ob_end_clean(); 00240 00241 # load page end HTML file if available 00242 ob_start(); 00243 $PageEndFile = $this->FindCommonTemplate("End"); 00244 if ($PageEndFile) { include($PageEndFile); } 00245 $PageEndOutput = ob_get_contents(); 00246 ob_end_clean(); 00247 00248 # get list of any required files not loaded 00249 $RequiredFiles = $this->GetRequiredFilesNotYetLoaded($PageContentFile); 00250 00251 # if a browser detection function has been made available 00252 if (is_callable($this->BrowserDetectFunc)) 00253 { 00254 # call function to get browser list 00255 $Browsers = call_user_func($this->BrowserDetectFunc); 00256 00257 # for each required file 00258 $NewRequiredFiles = array(); 00259 foreach ($RequiredFiles as $File) 00260 { 00261 # if file name includes browser keyword 00262 if (preg_match("/%BROWSER%/", $File)) 00263 { 00264 # for each browser 00265 foreach ($Browsers as $Browser) 00266 { 00267 # substitute in browser name and add to new file list 00268 $NewRequiredFiles[] = preg_replace( 00269 "/%BROWSER%/", $Browser, $File); 00270 } 00271 } 00272 else 00273 { 00274 # add to new file list 00275 $NewRequiredFiles[] = $File; 00276 } 00277 } 00278 $RequiredFiles = $NewRequiredFiles; 00279 } 00280 00281 # for each required file 00282 foreach ($RequiredFiles as $File) 00283 { 00284 # locate specific file to use 00285 $FilePath = $this->GUIFile($File); 00286 00287 # if file was found 00288 if ($FilePath) 00289 { 00290 # determine file type 00291 $NamePieces = explode(".", $File); 00292 $FileSuffix = strtolower(array_pop($NamePieces)); 00293 00294 # add file to HTML output based on file type 00295 $FilePath = htmlspecialchars($FilePath); 00296 switch ($FileSuffix) 00297 { 00298 case "js": 00299 $Tag = '<script type="text/javascript" src="' 00300 .$FilePath.'"></script>'; 00301 $PageEndOutput = preg_replace( 00302 "#</body>#i", $Tag."\n</body>", $PageEndOutput, 1); 00303 break; 00304 00305 case "css": 00306 $Tag = '<link rel="stylesheet" type="text/css"' 00307 .' media="all" href="'.$FilePath.'">'; 00308 $PageStartOutput = preg_replace( 00309 "#</head>#i", $Tag."\n</head>", $PageStartOutput, 1); 00310 break; 00311 } 00312 } 00313 } 00314 00315 # write out page 00316 print $PageStartOutput.$PageContentOutput.$PageEndOutput; 00317 } 00318 00319 # run any post-processing routines 00320 foreach ($this->PostProcessingFuncs as $Func) 00321 { 00322 call_user_func_array($Func["FunctionName"], $Func["Arguments"]); 00323 } 00324 00325 # write out any output buffered from page code execution 00326 if (strlen($PageOutput)) 00327 { 00328 if (!$this->SuppressHTML) 00329 { 00330 ?><table width="100%" cellpadding="5" 00331 style="border: 2px solid #666666; background: #CCCCCC; 00332 font-family: Courier New, Courier, monospace; 00333 margin-top: 10px;"><tr><td><?PHP 00334 } 00335 if ($this->JumpToPage) 00336 { 00337 ?><div style="color: #666666;"><span style="font-size: 150%;"> 00338 <b>Page Jump Aborted</b></span> 00339 (because of error or other unexpected output)<br /> 00340 <b>Jump Target:</b> 00341 <i><?PHP print($this->JumpToPage); ?></i></div><?PHP 00342 } 00343 print($PageOutput); 00344 if (!$this->SuppressHTML) 00345 { 00346 ?></td></tr></table><?PHP 00347 } 00348 } 00349 00350 # terminate and stay resident (TSR!) if indicated and HTML has been output 00351 # (only TSR if HTML has been output because otherwise browsers will misbehave) 00352 if ($ShouldTSR) { $this->LaunchTSR(); } 00353 } 00354 00361 function SetJumpToPage($Page) 00362 { 00363 if ((strpos($Page, "?") === FALSE) 00364 && ((strpos($Page, "=") !== FALSE) 00365 || ((stripos($Page, ".php") === FALSE) 00366 && (stripos($Page, ".htm") === FALSE) 00367 && (strpos($Page, "/") === FALSE))) 00368 && (stripos($Page, "http://") !== 0) 00369 && (stripos($Page, "https://") !== 0)) 00370 { 00371 $this->JumpToPage = "index.php?P=".$Page; 00372 } 00373 else 00374 { 00375 $this->JumpToPage = $Page; 00376 } 00377 } 00378 00383 function JumpToPageIsSet() 00384 { 00385 return ($this->JumpToPage === NULL) ? FALSE : TRUE; 00386 } 00387 00397 function HtmlCharset($NewSetting = NULL) 00398 { 00399 if ($NewSetting !== NULL) { $this->HtmlCharset = $NewSetting; } 00400 return $this->HtmlCharset; 00401 } 00402 00409 function SuppressHTMLOutput($NewSetting = TRUE) 00410 { 00411 $this->SuppressHTML = $NewSetting; 00412 } 00413 00420 function ActiveUserInterface($UIName = NULL) 00421 { 00422 if ($UIName !== NULL) 00423 { 00424 $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName); 00425 } 00426 return $this->ActiveUI; 00427 } 00428 00444 function AddPostProcessingCall($FunctionName, 00445 &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE, 00446 &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE, 00447 &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE) 00448 { 00449 $FuncIndex = count($this->PostProcessingFuncs); 00450 $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName; 00451 $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array(); 00452 $Index = 1; 00453 while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE)) 00454 { 00455 $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index] 00456 =& ${"Arg".$Index}; 00457 $Index++; 00458 } 00459 } 00460 00466 function AddEnvInclude($FileName) 00467 { 00468 $this->EnvIncludes[] = $FileName; 00469 } 00470 00477 function GUIFile($FileName) 00478 { 00479 # pull off file name suffix 00480 $NamePieces = explode(".", $FileName); 00481 $Suffix = strtolower(array_pop($NamePieces)); 00482 00483 # determine which location to search based on file suffix 00484 $ImageSuffixes = array("gif", "jpg", "png"); 00485 $FileList = in_array($Suffix, $ImageSuffixes) 00486 ? $this->ImageFileList : $this->CommonTemplateList; 00487 00488 # search for file 00489 $FoundFileName = $this->FindTemplate($FileList, $FileName); 00490 00491 # add non-image files to list of found files 00492 if (!in_array($Suffix, $ImageSuffixes)) 00493 { $this->FoundUIFiles[] = basename($FoundFileName); } 00494 00495 # return file name to caller 00496 return $FoundFileName; 00497 } 00498 00508 function PUIFile($FileName) 00509 { 00510 $FullFileName = $this->GUIFile($FileName); 00511 if ($FullFileName) { print($FullFileName); } 00512 } 00513 00518 function FindCommonTemplate($PageName) 00519 { 00520 return $this->FindTemplate( 00521 array_merge($this->CommonTemplateList, $this->ContentTemplateList), 00522 $PageName); 00523 } 00524 00533 function LoadFunction($Callback) 00534 { 00535 if (!is_callable($Callback) && is_string($Callback)) 00536 { 00537 $Locations = $this->FunctionFileList; 00538 foreach (self::$ObjectDirectories as $Location => $Prefix) 00539 { 00540 $Locations[] = $Location."%PAGENAME%.php"; 00541 $Locations[] = $Location."%PAGENAME%.html"; 00542 } 00543 $FunctionFileName = $this->FindTemplate($Locations, "F-".$Callback); 00544 if ($FunctionFileName) 00545 { 00546 include_once($FunctionFileName); 00547 } 00548 } 00549 return is_callable($Callback); 00550 } 00551 00556 function GetElapsedExecutionTime() 00557 { 00558 return microtime(TRUE) - $this->ExecutionStartTime; 00559 } 00560 00565 function GetSecondsBeforeTimeout() 00566 { 00567 return ini_get("max_execution_time") - $this->GetElapsedExecutionTime(); 00568 } 00569 00570 /*@)*/ /* Application Framework */ 00571 00572 # ---- Event Handling ---------------------------------------------------- 00573 /*@(*/ 00575 00579 const EVENTTYPE_DEFAULT = 1; 00585 const EVENTTYPE_CHAIN = 2; 00591 const EVENTTYPE_FIRST = 3; 00599 const EVENTTYPE_NAMED = 4; 00600 00602 const ORDER_FIRST = 1; 00604 const ORDER_MIDDLE = 2; 00606 const ORDER_LAST = 3; 00607 00616 function RegisterEvent($EventsOrEventName, $EventType = NULL) 00617 { 00618 # convert parameters to array if not already in that form 00619 $Events = is_array($EventsOrEventName) ? $EventsOrEventName 00620 : array($EventsOrEventName => $Type); 00621 00622 # for each event 00623 foreach ($Events as $Name => $Type) 00624 { 00625 # store event information 00626 $this->RegisteredEvents[$Name]["Type"] = $Type; 00627 $this->RegisteredEvents[$Name]["Hooks"] = array(); 00628 } 00629 } 00630 00644 function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE) 00645 { 00646 # convert parameters to array if not already in that form 00647 $Events = is_array($EventsOrEventName) ? $EventsOrEventName 00648 : array($EventsOrEventName => $Callback); 00649 00650 # for each event 00651 $Success = TRUE; 00652 foreach ($Events as $EventName => $EventCallback) 00653 { 00654 # if callback is valid 00655 if (is_callable($EventCallback)) 00656 { 00657 # if this is a periodic event we process internally 00658 if (isset($this->PeriodicEvents[$EventName])) 00659 { 00660 # process event now 00661 $this->ProcessPeriodicEvent($EventName, $EventCallback); 00662 } 00663 # if specified event has been registered 00664 elseif (isset($this->RegisteredEvents[$EventName])) 00665 { 00666 # add callback for event 00667 $this->RegisteredEvents[$EventName]["Hooks"][] 00668 = array("Callback" => $EventCallback, "Order" => $Order); 00669 00670 # sort callbacks by order 00671 if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1) 00672 { 00673 usort($this->RegisteredEvents[$EventName]["Hooks"], 00674 array("ApplicationFramework", "HookEvent_OrderCompare")); 00675 } 00676 } 00677 else 00678 { 00679 $Success = FALSE; 00680 } 00681 } 00682 else 00683 { 00684 $Success = FALSE; 00685 } 00686 } 00687 00688 # report to caller whether all callbacks were hooked 00689 return $Success; 00690 } 00691 private static function HookEvent_OrderCompare($A, $B) 00692 { 00693 if ($A["Order"] == $B["Order"]) { return 0; } 00694 return ($A["Order"] < $B["Order"]) ? -1 : 1; 00695 } 00696 00705 function SignalEvent($EventName, $Parameters = NULL) 00706 { 00707 $ReturnValue = NULL; 00708 00709 # if event has been registered 00710 if (isset($this->RegisteredEvents[$EventName])) 00711 { 00712 # set up default return value (if not NULL) 00713 switch ($this->RegisteredEvents[$EventName]["Type"]) 00714 { 00715 case self::EVENTTYPE_CHAIN: 00716 $ReturnValue = $Parameters; 00717 break; 00718 00719 case self::EVENTTYPE_NAMED: 00720 $ReturnValue = array(); 00721 break; 00722 } 00723 00724 # for each callback for this event 00725 foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook) 00726 { 00727 # invoke callback 00728 $Callback = $Hook["Callback"]; 00729 $Result = ($Parameters !== NULL) 00730 ? call_user_func_array($Callback, $Parameters) 00731 : call_user_func($Callback); 00732 00733 # process return value based on event type 00734 switch ($this->RegisteredEvents[$EventName]["Type"]) 00735 { 00736 case self::EVENTTYPE_CHAIN: 00737 $ReturnValue = $Result; 00738 $Parameters = $Result; 00739 break; 00740 00741 case self::EVENTTYPE_FIRST: 00742 if ($Result !== NULL) 00743 { 00744 $ReturnValue = $Result; 00745 break 2; 00746 } 00747 break; 00748 00749 case self::EVENTTYPE_NAMED: 00750 $CallbackName = is_array($Callback) 00751 ? (is_object($Callback[0]) 00752 ? get_class($Callback[0]) 00753 : $Callback[0])."::".$Callback[1] 00754 : $Callback; 00755 $ReturnValue[$CallbackName] = $Result; 00756 break; 00757 00758 default: 00759 break; 00760 } 00761 } 00762 } 00763 00764 # return value if any to caller 00765 return $ReturnValue; 00766 } 00767 00773 function IsStaticOnlyEvent($EventName) 00774 { 00775 return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE; 00776 } 00777 00778 /*@)*/ /* Event Handling */ 00779 00780 # ---- Task Management --------------------------------------------------- 00781 /*@(*/ 00783 00785 const PRIORITY_HIGH = 1; 00787 const PRIORITY_MEDIUM = 2; 00789 const PRIORITY_LOW = 3; 00791 const PRIORITY_BACKGROUND = 4; 00792 00805 function QueueTask($Callback, $Parameters = NULL, 00806 $Priority = self::PRIORITY_MEDIUM, $Description = "") 00807 { 00808 # pack task info and write to database 00809 if ($Parameters === NULL) { $Parameters = array(); } 00810 $this->DB->Query("INSERT INTO TaskQueue" 00811 ." (Callback, Parameters, Priority, Description)" 00812 ." VALUES ('".addslashes(serialize($Callback))."', '" 00813 .addslashes(serialize($Parameters))."', ".intval($Priority).", '" 00814 .addslashes($Description)."')"); 00815 } 00816 00834 function QueueUniqueTask($Callback, $Parameters = NULL, 00835 $Priority = self::PRIORITY_MEDIUM, $Description = "") 00836 { 00837 if ($this->TaskIsInQueue($Callback, $Parameters)) 00838 { 00839 $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue" 00840 ." WHERE Callback = '".addslashes(serialize($Callback))."'" 00841 .($Parameters ? " AND Parameters = '" 00842 .addslashes(serialize($Parameters))."'" : "")); 00843 if ($QueryResult !== FALSE) 00844 { 00845 $Record = $this->DB->FetchRow(); 00846 if ($Record["Priority"] > $Priority) 00847 { 00848 $this->DB->Query("UPDATE TaskQueue" 00849 ." SET Priority = ".intval($Priority) 00850 ." WHERE TaskId = ".intval($Record["TaskId"])); 00851 } 00852 } 00853 return FALSE; 00854 } 00855 else 00856 { 00857 $this->QueueTask($Callback, $Parameters, $Priority, $Description); 00858 return TRUE; 00859 } 00860 } 00861 00871 function TaskIsInQueue($Callback, $Parameters = NULL) 00872 { 00873 $FoundCount = $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM TaskQueue" 00874 ." WHERE Callback = '".addslashes(serialize($Callback))."'" 00875 .($Parameters ? " AND Parameters = '" 00876 .addslashes(serialize($Parameters))."'" : ""), 00877 "FoundCount") 00878 + $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM RunningTasks" 00879 ." WHERE Callback = '".addslashes(serialize($Callback))."'" 00880 .($Parameters ? " AND Parameters = '" 00881 .addslashes(serialize($Parameters))."'" : ""), 00882 "FoundCount"); 00883 return ($FoundCount ? TRUE : FALSE); 00884 } 00885 00891 function GetTaskQueueSize($Priority = NULL) 00892 { 00893 return $this->DB->Query("SELECT COUNT(*) AS QueueSize FROM TaskQueue" 00894 .($Priority ? " WHERE Priority = ".intval($Priority) : ""), 00895 "QueueSize"); 00896 } 00897 00905 function GetQueuedTaskList($Count = 100, $Offset = 0) 00906 { 00907 return $this->GetTaskList("SELECT * FROM TaskQueue" 00908 ." ORDER BY Priority, TaskId ", $Count, $Offset); 00909 } 00910 00918 function GetRunningTaskList($Count = 100, $Offset = 0) 00919 { 00920 return $this->GetTaskList("SELECT * FROM RunningTasks" 00921 ." WHERE StartedAt >= '".date("Y-m-d H:i:s", 00922 (time() - ini_get("max_execution_time")))."'" 00923 ." ORDER BY StartedAt", $Count, $Offset); 00924 } 00925 00933 function GetOrphanedTaskList($Count = 100, $Offset = 0) 00934 { 00935 return $this->GetTaskList("SELECT * FROM RunningTasks" 00936 ." WHERE StartedAt < '".date("Y-m-d H:i:s", 00937 (time() - ini_get("max_execution_time")))."'" 00938 ." ORDER BY StartedAt", $Count, $Offset); 00939 } 00940 00945 function ReQueueOrphanedTask($TaskId) 00946 { 00947 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE"); 00948 $this->DB->Query("INSERT INTO TaskQueue" 00949 ." (Callback,Parameters,Priority,Description) " 00950 ."SELECT Callback, Parameters, Priority, Description" 00951 ." FROM RunningTasks WHERE TaskId = ".intval($TaskId)); 00952 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId)); 00953 $this->DB->Query("UNLOCK TABLES"); 00954 } 00955 00960 function DeleteTask($TaskId) 00961 { 00962 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId)); 00963 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId)); 00964 } 00965 00973 function GetTask($TaskId) 00974 { 00975 # assume task will not be found 00976 $Task = NULL; 00977 00978 # look for task in task queue 00979 $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId)); 00980 00981 # if task was not found in queue 00982 if (!$this->DB->NumRowsSelected()) 00983 { 00984 # look for task in running task list 00985 $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = " 00986 .intval($TaskId)); 00987 } 00988 00989 # if task was found 00990 if ($this->DB->NumRowsSelected()) 00991 { 00992 # if task was periodic 00993 $Row = $this->DB->FetchRow(); 00994 if ($Row["Callback"] == 00995 serialize(array("ApplicationFramework", "PeriodicEventWrapper"))) 00996 { 00997 # unpack periodic task callback 00998 $WrappedCallback = unserialize($Row["Parameters"]); 00999 $Task["Callback"] = $WrappedCallback[1]; 01000 $Task["Parameters"] = NULL; 01001 } 01002 else 01003 { 01004 # unpack task callback and parameters 01005 $Task["Callback"] = unserialize($Row["Callback"]); 01006 $Task["Parameters"] = unserialize($Row["Parameters"]); 01007 } 01008 } 01009 01010 # return task to caller 01011 return $Task; 01012 } 01013 01019 function MaxTasks($NewValue = NULL) 01020 { 01021 if (func_num_args() && ($NewValue >= 1)) 01022 { 01023 $this->DB->Query("UPDATE ApplicationFrameworkSettings" 01024 ." SET MaxTasksRunning = '".intval($NewValue)."'"); 01025 $this->Settings["MaxTasksRunning"] = intval($NewValue); 01026 } 01027 return $this->Settings["MaxTasksRunning"]; 01028 } 01029 01037 function MaxExecutionTime($NewValue = NULL) 01038 { 01039 if (func_num_args() && !ini_get("safe_mode")) 01040 { 01041 if ($NewValue != $this->Settings["MaxExecTime"]) 01042 { 01043 $this->Settings["MaxExecTime"] = max($NewValue, 5); 01044 $this->DB->Query("UPDATE ApplicationFrameworkSettings" 01045 ." SET MaxExecTime = '" 01046 .intval($this->Settings["MaxExecTime"])."'"); 01047 } 01048 ini_set("max_execution_time", $this->Settings["MaxExecTime"]); 01049 set_time_limit($this->Settings["MaxExecTime"]); 01050 } 01051 return ini_get("max_execution_time"); 01052 } 01053 01054 /*@)*/ /* Task Management */ 01055 01056 # ---- PRIVATE INTERFACE ------------------------------------------------- 01057 01058 private $ActiveUI = "default"; 01059 private $BrowserDetectFunc; 01060 private $DB; 01061 private $DefaultPage = "Home"; 01062 private $EnvIncludes = array(); 01063 private $ExecutionStartTime; 01064 private $FoundUIFiles = array(); 01065 private $HtmlCharset = "UTF-8"; 01066 private $JumpToPage = NULL; 01067 private $MaxRunningTasksToTrack = 250; 01068 private static $ObjectDirectories = array(); 01069 private $PostProcessingFuncs = array(); 01070 private $RunningTask; 01071 private $Settings; 01072 private $SuppressHTML = FALSE; 01073 01074 # set to TRUE to not close browser connection before running background tasks 01075 private $NoTSR = FALSE; 01076 01077 private $PeriodicEvents = array( 01078 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT, 01079 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT, 01080 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT, 01081 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT, 01082 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED, 01083 ); 01084 private $UIEvents = array( 01085 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT, 01086 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN, 01087 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN, 01088 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT, 01089 ); 01090 01091 private function FindTemplate($FileList, $PageName) 01092 { 01093 $FileNameFound = NULL; 01094 foreach ($FileList as $FileName) 01095 { 01096 $FileName = str_replace("%ACTIVEUI%", $this->ActiveUI, $FileName); 01097 $FileName = str_replace("%PAGENAME%", $PageName, $FileName); 01098 if (file_exists($FileName)) 01099 { 01100 $FileNameFound = $FileName; 01101 break; 01102 } 01103 } 01104 return $FileNameFound; 01105 } 01106 01113 private function GetRequiredFilesNotYetLoaded($PageContentFile) 01114 { 01115 # start out assuming no files required 01116 $RequiredFiles = array(); 01117 01118 # if page content file supplied 01119 if ($PageContentFile) 01120 { 01121 # if file containing list of required files is available 01122 $Path = dirname($PageContentFile); 01123 $RequireListFile = $Path."/REQUIRES"; 01124 if (file_exists($RequireListFile)) 01125 { 01126 # read in list of required files 01127 $RequestedFiles = file($RequireListFile); 01128 01129 # for each line in required file list 01130 foreach ($RequestedFiles as $Line) 01131 { 01132 # if line is not a comment 01133 $Line = trim($Line); 01134 if (!preg_match("/^#/", $Line)) 01135 { 01136 # if file has not already been loaded 01137 if (!in_array($Line, $this->FoundUIFiles)) 01138 { 01139 # add to list of required files 01140 $RequiredFiles[] = $Line; 01141 } 01142 } 01143 } 01144 } 01145 } 01146 01147 # return list of required files to caller 01148 return $RequiredFiles; 01149 } 01150 01151 private function SetUpObjectAutoloading() 01152 { 01153 function __autoload($ClassName) 01154 { 01155 ApplicationFramework::AutoloadObjects($ClassName); 01156 } 01157 } 01158 01160 static function AutoloadObjects($ClassName) 01161 { 01162 foreach (self::$ObjectDirectories as $Location => $Prefix) 01163 { 01164 $FileName = $Location.$Prefix.$ClassName.".php"; 01165 if (file_exists($FileName)) 01166 { 01167 require_once($FileName); 01168 break; 01169 } 01170 } 01171 } 01174 private function LoadUIFunctions() 01175 { 01176 $Dirs = array( 01177 "local/interface/%ACTIVEUI%/include", 01178 "interface/%ACTIVEUI%/include", 01179 "local/interface/default/include", 01180 "interface/default/include", 01181 ); 01182 foreach ($Dirs as $Dir) 01183 { 01184 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir); 01185 if (is_dir($Dir)) 01186 { 01187 $FileNames = scandir($Dir); 01188 foreach ($FileNames as $FileName) 01189 { 01190 if (preg_match("/^F-([A-Za-z_]+)\.php/", $FileName, $Matches) 01191 || preg_match("/^F-([A-Za-z_]+)\.html/", $FileName, $Matches)) 01192 { 01193 if (!function_exists($Matches[1])) 01194 { 01195 include_once($Dir."/".$FileName); 01196 } 01197 } 01198 } 01199 } 01200 } 01201 } 01202 01203 private function ProcessPeriodicEvent($EventName, $Callback) 01204 { 01205 # retrieve last execution time for event if available 01206 $Signature = self::GetCallbackSignature($Callback); 01207 $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents" 01208 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt"); 01209 01210 # determine whether enough time has passed for event to execute 01211 $EventPeriods = array( 01212 "EVENT_HOURLY" => 60*60, 01213 "EVENT_DAILY" => 60*60*24, 01214 "EVENT_WEEKLY" => 60*60*24*7, 01215 "EVENT_MONTHLY" => 60*60*24*30, 01216 "EVENT_PERIODIC" => 0, 01217 ); 01218 $ShouldExecute = (($LastRun === NULL) 01219 || (time() > (strtotime($LastRun) + $EventPeriods[$EventName]))) 01220 ? TRUE : FALSE; 01221 01222 # if event should run 01223 if ($ShouldExecute) 01224 { 01225 # add event to task queue 01226 $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper"); 01227 $WrapperParameters = array( 01228 $EventName, $Callback, array("LastRunAt" => $LastRun)); 01229 $this->QueueUniqueTask($WrapperCallback, $WrapperParameters); 01230 } 01231 } 01232 01233 private static function PeriodicEventWrapper($EventName, $Callback, $Parameters) 01234 { 01235 static $DB; 01236 if (!isset($DB)) { $DB = new Database(); } 01237 01238 # run event 01239 $ReturnVal = call_user_func_array($Callback, $Parameters); 01240 01241 # if event is already in database 01242 $Signature = self::GetCallbackSignature($Callback); 01243 if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents" 01244 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount")) 01245 { 01246 # update last run time for event 01247 $DB->Query("UPDATE PeriodicEvents SET LastRunAt = " 01248 .(($EventName == "EVENT_PERIODIC") 01249 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'" 01250 : "NOW()") 01251 ." WHERE Signature = '".addslashes($Signature)."'"); 01252 } 01253 else 01254 { 01255 # add last run time for event to database 01256 $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES " 01257 ."('".addslashes($Signature)."', " 01258 .(($EventName == "EVENT_PERIODIC") 01259 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'" 01260 : "NOW()").")"); 01261 } 01262 } 01263 01264 private static function GetCallbackSignature($Callback) 01265 { 01266 return !is_array($Callback) ? $Callback 01267 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0]) 01268 ."::".$Callback[1]; 01269 } 01270 01271 private function PrepForTSR() 01272 { 01273 # if HTML has been output and it's time to launch another task 01274 # (only TSR if HTML has been output because otherwise browsers 01275 # may misbehave after connection is closed) 01276 if (($this->JumpToPage || !$this->SuppressHTML) 01277 && (time() > (strtotime($this->Settings["LastTaskRunAt"]) 01278 + (ini_get("max_execution_time") 01279 / $this->Settings["MaxTasksRunning"]) + 5)) 01280 && $this->GetTaskQueueSize()) 01281 { 01282 # begin buffering output for TSR 01283 ob_start(); 01284 01285 # let caller know it is time to launch another task 01286 return TRUE; 01287 } 01288 else 01289 { 01290 # let caller know it is not time to launch another task 01291 return FALSE; 01292 } 01293 } 01294 01295 private function LaunchTSR() 01296 { 01297 # set needed headers and 01298 if (!$this->NoTSR) 01299 { 01300 ignore_user_abort(TRUE); 01301 header("Connection: close"); 01302 header("Content-Length: ".ob_get_length()); 01303 } 01304 01305 # output buffered content 01306 ob_end_flush(); 01307 flush(); 01308 01309 # write out any outstanding data and end HTTP session 01310 session_write_close(); 01311 01312 # if there is still a task in the queue 01313 if ($this->GetTaskQueueSize()) 01314 { 01315 # turn on output buffering to (hopefully) record any crash output 01316 ob_start(); 01317 01318 # lock tables and grab last task run time to double check 01319 $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE"); 01320 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings"); 01321 $this->Settings = $this->DB->FetchRow(); 01322 01323 # if still time to launch another task 01324 if (time() > (strtotime($this->Settings["LastTaskRunAt"]) 01325 + (ini_get("max_execution_time") 01326 / $this->Settings["MaxTasksRunning"]) + 5)) 01327 { 01328 # update the "last run" time and release tables 01329 $this->DB->Query("UPDATE ApplicationFrameworkSettings" 01330 ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'"); 01331 $this->DB->Query("UNLOCK TABLES"); 01332 01333 # run tasks while there is a task in the queue and enough time left 01334 do 01335 { 01336 # run the next task 01337 $this->RunNextTask(); 01338 } 01339 while ($this->GetTaskQueueSize() 01340 && ($this->GetSecondsBeforeTimeout() > 65)); 01341 } 01342 else 01343 { 01344 # release tables 01345 $this->DB->Query("UNLOCK TABLES"); 01346 } 01347 } 01348 } 01349 01357 private function GetTaskList($DBQuery, $Count, $Offset) 01358 { 01359 $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count)); 01360 $Tasks = array(); 01361 while ($Row = $this->DB->FetchRow()) 01362 { 01363 $Tasks[$Row["TaskId"]] = $Row; 01364 if ($Row["Callback"] == 01365 serialize(array("ApplicationFramework", "PeriodicEventWrapper"))) 01366 { 01367 $WrappedCallback = unserialize($Row["Parameters"]); 01368 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1]; 01369 $Tasks[$Row["TaskId"]]["Parameters"] = NULL; 01370 } 01371 else 01372 { 01373 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]); 01374 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]); 01375 } 01376 } 01377 return $Tasks; 01378 } 01379 01383 private function RunNextTask() 01384 { 01385 # look for task at head of queue 01386 $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1"); 01387 $Task = $this->DB->FetchRow(); 01388 01389 # if there was a task available 01390 if ($Task) 01391 { 01392 # move task from queue to running tasks list 01393 $this->DB->Query("INSERT INTO RunningTasks " 01394 ."(TaskId,Callback,Parameters,Priority,Description) " 01395 ."SELECT * FROM TaskQueue WHERE TaskId = " 01396 .intval($Task["TaskId"])); 01397 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = " 01398 .intval($Task["TaskId"])); 01399 01400 # unpack stored task info 01401 $Callback = unserialize($Task["Callback"]); 01402 $Parameters = unserialize($Task["Parameters"]); 01403 01404 # attempt to load task callback if not already available 01405 $this->LoadFunction($Callback); 01406 01407 # run task 01408 $this->RunningTask = $Task; 01409 if ($Parameters) 01410 { 01411 call_user_func_array($Callback, $Parameters); 01412 } 01413 else 01414 { 01415 call_user_func($Callback); 01416 } 01417 unset($this->RunningTask); 01418 01419 # remove task from running tasks list 01420 $this->DB->Query("DELETE FROM RunningTasks" 01421 ." WHERE TaskId = ".intval($Task["TaskId"])); 01422 01423 # prune running tasks list if necessary 01424 $RunningTasksCount = $this->DB->Query( 01425 "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount"); 01426 if ($RunningTasksCount > $this->MaxRunningTasksToTrack) 01427 { 01428 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt" 01429 ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack)); 01430 } 01431 } 01432 } 01433 01439 function OnCrash() 01440 { 01441 if (isset($this->RunningTask)) 01442 { 01443 if (function_exists("error_get_last")) 01444 { 01445 $CrashInfo["LastError"] = error_get_last(); 01446 } 01447 if (ob_get_length() !== FALSE) 01448 { 01449 $CrashInfo["OutputBuffer"] = ob_get_contents(); 01450 } 01451 if (isset($CrashInfo)) 01452 { 01453 $DB = new Database(); 01454 $DB->Query("UPDATE RunningTasks SET CrashInfo = '" 01455 .addslashes(serialize($CrashInfo)) 01456 ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"])); 01457 } 01458 } 01459 01460 print("\n"); 01461 return; 01462 01463 if (ob_get_length() !== FALSE) 01464 { 01465 ?> 01466 <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> 01467 <div style="font-size: 200%;">CRASH OUTPUT</div><?PHP 01468 ob_end_flush(); 01469 ?></td></tr></table><?PHP 01470 } 01471 } 01472 01473 private $CommonTemplateList = array( 01474 "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl", 01475 "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html", 01476 "local/interface/%ACTIVEUI%/include/%PAGENAME%.tpl", 01477 "local/interface/%ACTIVEUI%/include/%PAGENAME%.html", 01478 "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl", 01479 "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html", 01480 "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl", 01481 "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html", 01482 "local/interface/%ACTIVEUI%/include/%PAGENAME%", 01483 "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl", 01484 "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html", 01485 "interface/%ACTIVEUI%/include/%PAGENAME%.tpl", 01486 "interface/%ACTIVEUI%/include/%PAGENAME%.html", 01487 "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl", 01488 "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html", 01489 "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl", 01490 "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html", 01491 "interface/%ACTIVEUI%/include/%PAGENAME%", 01492 "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.tpl", 01493 "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.html", 01494 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.tpl", 01495 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html", 01496 "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl", 01497 "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html", 01498 "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.tpl", 01499 "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.html", 01500 "SPTUI--%ACTIVEUI%/include/%PAGENAME%", 01501 "%ACTIVEUI%/include/StdPage%PAGENAME%.tpl", 01502 "%ACTIVEUI%/include/StdPage%PAGENAME%.html", 01503 "%ACTIVEUI%/include/%PAGENAME%.tpl", 01504 "%ACTIVEUI%/include/%PAGENAME%.html", 01505 "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl", 01506 "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html", 01507 "%ACTIVEUI%/include/SPT--%PAGENAME%.tpl", 01508 "%ACTIVEUI%/include/SPT--%PAGENAME%.html", 01509 "%ACTIVEUI%/include/%PAGENAME%", 01510 "local/interface/default/include/StdPage%PAGENAME%.tpl", 01511 "local/interface/default/include/StdPage%PAGENAME%.html", 01512 "local/interface/default/include/%PAGENAME%.tpl", 01513 "local/interface/default/include/%PAGENAME%.html", 01514 "local/interface/default/include/SPT--StandardPage%PAGENAME%.tpl", 01515 "local/interface/default/include/SPT--StandardPage%PAGENAME%.html", 01516 "local/interface/default/include/SPT--%PAGENAME%.tpl", 01517 "local/interface/default/include/SPT--%PAGENAME%.html", 01518 "local/interface/default/include/%PAGENAME%", 01519 "interface/default/include/StdPage%PAGENAME%.tpl", 01520 "interface/default/include/StdPage%PAGENAME%.html", 01521 "interface/default/include/%PAGENAME%.tpl", 01522 "interface/default/include/%PAGENAME%.html", 01523 "interface/default/include/SPT--StandardPage%PAGENAME%.tpl", 01524 "interface/default/include/SPT--StandardPage%PAGENAME%.html", 01525 "interface/default/include/SPT--%PAGENAME%.tpl", 01526 "interface/default/include/SPT--%PAGENAME%.html", 01527 "interface/default/include/%PAGENAME%", 01528 ); 01529 private $ContentTemplateList = array( 01530 "local/interface/%ACTIVEUI%/%PAGENAME%.tpl", 01531 "local/interface/%ACTIVEUI%/%PAGENAME%.html", 01532 "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl", 01533 "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.html", 01534 "interface/%ACTIVEUI%/%PAGENAME%.tpl", 01535 "interface/%ACTIVEUI%/%PAGENAME%.html", 01536 "interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl", 01537 "interface/%ACTIVEUI%/SPT--%PAGENAME%.html", 01538 "SPTUI--%ACTIVEUI%/%PAGENAME%.tpl", 01539 "SPTUI--%ACTIVEUI%/%PAGENAME%.html", 01540 "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.tpl", 01541 "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.html", 01542 "%ACTIVEUI%/%PAGENAME%.tpl", 01543 "%ACTIVEUI%/%PAGENAME%.html", 01544 "%ACTIVEUI%/SPT--%PAGENAME%.tpl", 01545 "%ACTIVEUI%/SPT--%PAGENAME%.html", 01546 "local/interface/default/%PAGENAME%.tpl", 01547 "local/interface/default/%PAGENAME%.html", 01548 "local/interface/default/SPT--%PAGENAME%.tpl", 01549 "local/interface/default/SPT--%PAGENAME%.html", 01550 "interface/default/%PAGENAME%.tpl", 01551 "interface/default/%PAGENAME%.html", 01552 "interface/default/SPT--%PAGENAME%.tpl", 01553 "interface/default/SPT--%PAGENAME%.html", 01554 ); 01555 private $ImageFileList = array( 01556 "local/interface/%ACTIVEUI%/images/%PAGENAME%", 01557 "interface/%ACTIVEUI%/images/%PAGENAME%", 01558 "SPTUI--%ACTIVEUI%/images/%PAGENAME%", 01559 "%ACTIVEUI%/images/%PAGENAME%", 01560 "local/interface/default/images/%PAGENAME%", 01561 "interface/default/images/%PAGENAME%", 01562 ); 01563 private $FunctionFileList = array( 01564 "local/interface/%ACTIVEUI%/include/%PAGENAME%.php", 01565 "local/interface/%ACTIVEUI%/include/%PAGENAME%.html", 01566 "interface/%ACTIVEUI%/include/%PAGENAME%.php", 01567 "interface/%ACTIVEUI%/include/%PAGENAME%.html", 01568 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.php", 01569 "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html", 01570 "%ACTIVEUI%/include/%PAGENAME%.php", 01571 "%ACTIVEUI%/include/%PAGENAME%.html", 01572 "local/interface/default/include/%PAGENAME%.php", 01573 "local/interface/default/include/%PAGENAME%.html", 01574 "local/include/%PAGENAME%.php", 01575 "local/include/%PAGENAME%.html", 01576 "interface/default/include/%PAGENAME%.php", 01577 "interface/default/include/%PAGENAME%.html", 01578 "include/%PAGENAME%.php", 01579 "include/%PAGENAME%.html", 01580 ); 01581 01582 const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-."; 01583 }; 01584 01585 01586 ?>