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                     || ((strpos($Page, ".php") === FALSE)
00366                         && (strpos($Page, ".htm") === FALSE)
00367                         && (strpos($Page, "/") === FALSE))))
00368         {
00369             $this->JumpToPage = "index.php?P=".$Page;
00370         }
00371         else
00372         {
00373             $this->JumpToPage = $Page;
00374         }
00375     }
00376 
00381     function JumpToPageIsSet()
00382     {
00383         return ($this->JumpToPage === NULL) ? FALSE : TRUE;
00384     }
00385 
00395     function HtmlCharset($NewSetting = NULL)
00396     {
00397         if ($NewSetting !== NULL) {  $this->HtmlCharset = $NewSetting;  }
00398         return $this->HtmlCharset;
00399     }
00400 
00407     function SuppressHTMLOutput($NewSetting = TRUE)
00408     {
00409         $this->SuppressHTML = $NewSetting;
00410     }
00411 
00418     function ActiveUserInterface($UIName = NULL)
00419     {
00420         if ($UIName !== NULL)
00421         {
00422             $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
00423         }
00424         return $this->ActiveUI;
00425     }
00426 
00442     function AddPostProcessingCall($FunctionName,
00443             &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
00444             &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
00445             &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
00446     {
00447         $FuncIndex = count($this->PostProcessingFuncs);
00448         $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
00449         $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
00450         $Index = 1;
00451         while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
00452         {
00453             $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
00454                     =& ${"Arg".$Index};
00455             $Index++;
00456         }
00457     }
00458 
00464     function AddEnvInclude($FileName)
00465     {
00466         $this->EnvIncludes[] = $FileName;
00467     }
00468 
00475     function GUIFile($FileName)
00476     {
00477         # pull off file name suffix
00478         $NamePieces = explode(".", $FileName);
00479         $Suffix = strtolower(array_pop($NamePieces));
00480 
00481         # determine which location to search based on file suffix
00482         $ImageSuffixes = array("gif", "jpg", "png");
00483         $FileList = in_array($Suffix, $ImageSuffixes)
00484                 ? $this->ImageFileList : $this->CommonTemplateList;
00485 
00486         # search for file
00487         $FoundFileName = $this->FindTemplate($FileList, $FileName);
00488 
00489         # add non-image files to list of found files
00490         if (!in_array($Suffix, $ImageSuffixes)) 
00491                 {  $this->FoundUIFiles[] = basename($FoundFileName);  }
00492 
00493         # return file name to caller
00494         return $FoundFileName;
00495     }
00496 
00506     function PUIFile($FileName)
00507     {
00508         $FullFileName = $this->GUIFile($FileName);
00509         if ($FullFileName) {  print($FullFileName);  }
00510     }
00511 
00516     function FindCommonTemplate($PageName)
00517     {
00518         return $this->FindTemplate(
00519                 array_merge($this->CommonTemplateList, $this->ContentTemplateList),
00520                 $PageName);
00521     }
00522 
00531     function LoadFunction($Callback)
00532     {
00533         if (!is_callable($Callback) && is_string($Callback))
00534         {
00535             $Locations = $this->FunctionFileList;
00536             foreach (self::$ObjectDirectories as $Location => $Prefix)
00537             {
00538                 $Locations[] = $Location."%PAGENAME%.php";
00539                 $Locations[] = $Location."%PAGENAME%.html";
00540             }
00541             $FunctionFileName = $this->FindTemplate($Locations, "F-".$Callback);
00542             if ($FunctionFileName)
00543             {
00544                 include_once($FunctionFileName);
00545             }
00546         }
00547         return is_callable($Callback);
00548     }
00549 
00554     function GetElapsedExecutionTime()
00555     {
00556         return microtime(TRUE) - $this->ExecutionStartTime;
00557     }
00558 
00563     function GetSecondsBeforeTimeout()
00564     {
00565         return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
00566     }
00567 
00568     /*@)*/ /* Application Framework */
00569 
00570     # ---- Event Handling ----------------------------------------------------
00571  /*@(*/
00573 
00577     const EVENTTYPE_DEFAULT = 1;
00583     const EVENTTYPE_CHAIN = 2;
00589     const EVENTTYPE_FIRST = 3;
00597     const EVENTTYPE_NAMED = 4;
00598 
00600     const ORDER_FIRST = 1;
00602     const ORDER_MIDDLE = 2;
00604     const ORDER_LAST = 3;
00605 
00614     function RegisterEvent($EventsOrEventName, $EventType = NULL)
00615     {
00616         # convert parameters to array if not already in that form
00617         $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00618                 : array($EventsOrEventName => $Type);
00619 
00620         # for each event
00621         foreach ($Events as $Name => $Type)
00622         {
00623             # store event information
00624             $this->RegisteredEvents[$Name]["Type"] = $Type;
00625             $this->RegisteredEvents[$Name]["Hooks"] = array();
00626         }
00627     }
00628 
00642     function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
00643     {
00644         # convert parameters to array if not already in that form
00645         $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00646                 : array($EventsOrEventName => $Callback);
00647 
00648         # for each event
00649         $Success = TRUE;
00650         foreach ($Events as $EventName => $EventCallback)
00651         {
00652             # if callback is valid
00653             if (is_callable($EventCallback))
00654             {
00655                 # if this is a periodic event we process internally
00656                 if (isset($this->PeriodicEvents[$EventName]))
00657                 {
00658                     # process event now
00659                     $this->ProcessPeriodicEvent($EventName, $EventCallback);
00660                 }
00661                 # if specified event has been registered
00662                 elseif (isset($this->RegisteredEvents[$EventName]))
00663                 {
00664                     # add callback for event
00665                     $this->RegisteredEvents[$EventName]["Hooks"][]
00666                             = array("Callback" => $EventCallback, "Order" => $Order);
00667 
00668                     # sort callbacks by order
00669                     if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
00670                     {
00671                         usort($this->RegisteredEvents[$EventName]["Hooks"],
00672                                 array("ApplicationFramework", "HookEvent_OrderCompare"));
00673                     }
00674                 }
00675                 else
00676                 {
00677                     $Success = FALSE;
00678                 }
00679             }
00680             else
00681             {
00682                 $Success = FALSE;
00683             }
00684         }
00685 
00686         # report to caller whether all callbacks were hooked
00687         return $Success;
00688     }
00689     private static function HookEvent_OrderCompare($A, $B)
00690     {
00691         if ($A["Order"] == $B["Order"]) {  return 0;  }
00692         return ($A["Order"] < $B["Order"]) ? -1 : 1;
00693     }
00694 
00703     function SignalEvent($EventName, $Parameters = NULL)
00704     {
00705         $ReturnValue = NULL;
00706 
00707         # if event has been registered
00708         if (isset($this->RegisteredEvents[$EventName]))
00709         {
00710             # set up default return value (if not NULL)
00711             switch ($this->RegisteredEvents[$EventName]["Type"])
00712             {
00713                 case self::EVENTTYPE_CHAIN:
00714                     $ReturnValue = $Parameters;
00715                     break;
00716 
00717                 case self::EVENTTYPE_NAMED:
00718                     $ReturnValue = array();
00719                     break;
00720             }
00721 
00722             # for each callback for this event
00723             foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
00724             {
00725                 # invoke callback
00726                 $Callback = $Hook["Callback"];
00727                 $Result = ($Parameters !== NULL)
00728                         ? call_user_func_array($Callback, $Parameters)
00729                         : call_user_func($Callback);
00730 
00731                 # process return value based on event type
00732                 switch ($this->RegisteredEvents[$EventName]["Type"])
00733                 {
00734                     case self::EVENTTYPE_CHAIN:
00735                         $ReturnValue = $Result;
00736                         $Parameters = $Result;
00737                         break;
00738 
00739                     case self::EVENTTYPE_FIRST:
00740                         if ($Result !== NULL)
00741                         {
00742                             $ReturnValue = $Result;
00743                             break 2;
00744                         }
00745                         break;
00746 
00747                     case self::EVENTTYPE_NAMED:
00748                         $CallbackName = is_array($Callback)
00749                                 ? (is_object($Callback[0])
00750                                         ? get_class($Callback[0])
00751                                         : $Callback[0])."::".$Callback[1]
00752                                 : $Callback;
00753                         $ReturnValue[$CallbackName] = $Result;
00754                         break;
00755 
00756                     default:
00757                         break;
00758                 }
00759             }
00760         }
00761 
00762         # return value if any to caller
00763         return $ReturnValue;
00764     }
00765 
00771     function IsStaticOnlyEvent($EventName)
00772     {
00773         return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
00774     }
00775 
00776     /*@)*/ /* Event Handling */
00777 
00778     # ---- Task Management ---------------------------------------------------
00779  /*@(*/
00781 
00783     const PRIORITY_HIGH = 1;
00785     const PRIORITY_MEDIUM = 2;
00787     const PRIORITY_LOW = 3;
00789     const PRIORITY_BACKGROUND = 4;
00790 
00803     function QueueTask($Callback, $Parameters = NULL,
00804             $Priority = self::PRIORITY_MEDIUM, $Description = "")
00805     {
00806         # pack task info and write to database
00807         if ($Parameters === NULL) {  $Parameters = array();  }
00808         $this->DB->Query("INSERT INTO TaskQueue"
00809                 ." (Callback, Parameters, Priority, Description)"
00810                 ." VALUES ('".addslashes(serialize($Callback))."', '"
00811                 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
00812                 .addslashes($Description)."')");
00813     }
00814 
00832     function QueueUniqueTask($Callback, $Parameters = NULL,
00833             $Priority = self::PRIORITY_MEDIUM, $Description = "")
00834     {
00835         if ($this->TaskIsInQueue($Callback, $Parameters))
00836         {
00837             $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
00838                     ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00839                     .($Parameters ? " AND Parameters = '"
00840                             .addslashes(serialize($Parameters))."'" : ""));
00841             if ($QueryResult !== FALSE)
00842             {
00843                 $Record = $this->DB->FetchRow();
00844                 if ($Record["Priority"] > $Priority)
00845                 {
00846                     $this->DB->Query("UPDATE TaskQueue"
00847                             ." SET Priority = ".intval($Priority)
00848                             ." WHERE TaskId = ".intval($Record["TaskId"]));
00849                 }
00850             }
00851             return FALSE;
00852         }
00853         else
00854         {
00855             $this->QueueTask($Callback, $Parameters, $Priority, $Description);
00856             return TRUE;
00857         }
00858     }
00859 
00869     function TaskIsInQueue($Callback, $Parameters = NULL)
00870     {
00871         $FoundCount = $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM TaskQueue"
00872                 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00873                 .($Parameters ? " AND Parameters = '"
00874                         .addslashes(serialize($Parameters))."'" : ""),
00875                 "FoundCount")
00876                 + $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM RunningTasks"
00877                 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00878                 .($Parameters ? " AND Parameters = '"
00879                         .addslashes(serialize($Parameters))."'" : ""),
00880                 "FoundCount");
00881         return ($FoundCount ? TRUE : FALSE);
00882     }
00883 
00889     function GetTaskQueueSize($Priority = NULL)
00890     {
00891         return $this->DB->Query("SELECT COUNT(*) AS QueueSize FROM TaskQueue"
00892                 .($Priority ? " WHERE Priority = ".intval($Priority) : ""),
00893                 "QueueSize");
00894     }
00895 
00903     function GetQueuedTaskList($Count = 100, $Offset = 0)
00904     {
00905         return $this->GetTaskList("SELECT * FROM TaskQueue"
00906                 ." ORDER BY Priority, TaskId ", $Count, $Offset);
00907     }
00908 
00916     function GetRunningTaskList($Count = 100, $Offset = 0)
00917     {
00918         return $this->GetTaskList("SELECT * FROM RunningTasks"
00919                 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
00920                         (time() - ini_get("max_execution_time")))."'"
00921                 ." ORDER BY StartedAt", $Count, $Offset);
00922     }
00923 
00931     function GetOrphanedTaskList($Count = 100, $Offset = 0)
00932     {
00933         return $this->GetTaskList("SELECT * FROM RunningTasks"
00934                 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
00935                         (time() - ini_get("max_execution_time")))."'"
00936                 ." ORDER BY StartedAt", $Count, $Offset);
00937     }
00938 
00943     function ReQueueOrphanedTask($TaskId)
00944     {
00945         $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
00946         $this->DB->Query("INSERT INTO TaskQueue"
00947                          ." (Callback,Parameters,Priority,Description) "
00948                          ."SELECT Callback, Parameters, Priority, Description"
00949                          ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00950         $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00951         $this->DB->Query("UNLOCK TABLES");
00952     }
00953 
00958     function DeleteTask($TaskId)
00959     {
00960         $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
00961         $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00962     }
00963 
00971     function GetTask($TaskId)
00972     {
00973         # assume task will not be found
00974         $Task = NULL;
00975 
00976         # look for task in task queue
00977         $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
00978 
00979         # if task was not found in queue
00980         if (!$this->DB->NumRowsSelected())
00981         {
00982             # look for task in running task list
00983             $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = "
00984                     .intval($TaskId));
00985         }
00986 
00987         # if task was found
00988         if ($this->DB->NumRowsSelected())
00989         {
00990             # if task was periodic
00991             $Row = $this->DB->FetchRow();
00992             if ($Row["Callback"] ==
00993                     serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
00994             {
00995                 # unpack periodic task callback
00996                 $WrappedCallback = unserialize($Row["Parameters"]);
00997                 $Task["Callback"] = $WrappedCallback[1];
00998                 $Task["Parameters"] = NULL;
00999             }
01000             else
01001             {
01002                 # unpack task callback and parameters
01003                 $Task["Callback"] = unserialize($Row["Callback"]);
01004                 $Task["Parameters"] = unserialize($Row["Parameters"]);
01005             }
01006         }
01007 
01008         # return task to caller
01009         return $Task;
01010     }
01011 
01017     function MaxTasks($NewValue = NULL)
01018     {
01019         if (func_num_args() && ($NewValue >= 1))
01020         {
01021             $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01022                     ." SET MaxTasksRunning = '".intval($NewValue)."'");
01023             $this->Settings["MaxTasksRunning"] = intval($NewValue);
01024         }
01025         return $this->Settings["MaxTasksRunning"];
01026     }
01027 
01035     function MaxExecutionTime($NewValue = NULL)
01036     {
01037         if (func_num_args() && !ini_get("safe_mode"))
01038         {
01039             if ($NewValue != $this->Settings["MaxExecTime"])
01040             {
01041                 $this->Settings["MaxExecTime"] = max($NewValue, 5);
01042                 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01043                         ." SET MaxExecTime = '"
01044                                 .intval($this->Settings["MaxExecTime"])."'");
01045             }
01046             ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
01047             set_time_limit($this->Settings["MaxExecTime"]);
01048         }
01049         return ini_get("max_execution_time");
01050     }
01051 
01052     /*@)*/ /* Task Management */
01053 
01054     # ---- PRIVATE INTERFACE -------------------------------------------------
01055 
01056     private $ActiveUI = "default";
01057     private $BrowserDetectFunc;
01058     private $DB;
01059     private $DefaultPage = "Home";
01060     private $EnvIncludes = array();
01061     private $ExecutionStartTime;
01062     private $FoundUIFiles = array();
01063     private $HtmlCharset = "UTF-8";
01064     private $JumpToPage = NULL;
01065     private $MaxRunningTasksToTrack = 250;
01066     private static $ObjectDirectories = array();
01067     private $PostProcessingFuncs = array();
01068     private $RunningTask;
01069     private $Settings;
01070     private $SuppressHTML = FALSE;
01071 
01072     private $PeriodicEvents = array(
01073                 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
01074                 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
01075                 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
01076                 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
01077                 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
01078                 );
01079     private $UIEvents = array(
01080                 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
01081                 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
01082                 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
01083                 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
01084                 );
01085 
01086     private function FindTemplate($FileList, $PageName)
01087     {
01088         $FileNameFound = NULL;
01089         foreach ($FileList as $FileName)
01090         {
01091             $FileName = str_replace("%ACTIVEUI%", $this->ActiveUI, $FileName);
01092             $FileName = str_replace("%PAGENAME%", $PageName, $FileName);
01093             if (file_exists($FileName))
01094             {
01095                 $FileNameFound = $FileName;
01096                 break;
01097             }
01098         }
01099         return $FileNameFound;
01100     }
01101 
01108     private function GetRequiredFilesNotYetLoaded($PageContentFile)
01109     {
01110         # start out assuming no files required
01111         $RequiredFiles = array();
01112 
01113         # if page content file supplied
01114         if ($PageContentFile)
01115         {
01116             # if file containing list of required files is available
01117             $Path = dirname($PageContentFile);
01118             $RequireListFile = $Path."/REQUIRES";
01119             if (file_exists($RequireListFile))
01120             {
01121                 # read in list of required files
01122                 $RequestedFiles = file($RequireListFile);
01123 
01124                 # for each line in required file list
01125                 foreach ($RequestedFiles as $Line)
01126                 {
01127                     # if line is not a comment
01128                     $Line = trim($Line);
01129                     if (!preg_match("/^#/", $Line))
01130                     {
01131                         # if file has not already been loaded
01132                         if (!in_array($Line, $this->FoundUIFiles))
01133                         {
01134                             # add to list of required files
01135                             $RequiredFiles[] = $Line;
01136                         }
01137                     }
01138                 }
01139             }
01140         }
01141 
01142         # return list of required files to caller
01143         return $RequiredFiles;
01144     }
01145 
01146     private function SetUpObjectAutoloading()
01147     {
01148         function __autoload($ClassName)
01149         {
01150             ApplicationFramework::AutoloadObjects($ClassName);
01151         }
01152     }
01153 
01155     static function AutoloadObjects($ClassName)
01156     {
01157         foreach (self::$ObjectDirectories as $Location => $Prefix)
01158         {
01159             $FileName = $Location.$Prefix.$ClassName.".php";
01160             if (file_exists($FileName))
01161             {
01162                 require_once($FileName);
01163                 break;
01164             }
01165         }
01166     }
01169     private function LoadUIFunctions()
01170     {
01171         $Dirs = array(
01172                 "local/interface/%ACTIVEUI%/include",
01173                 "interface/%ACTIVEUI%/include",
01174                 "local/interface/default/include",
01175                 "interface/default/include",
01176                 );
01177         foreach ($Dirs as $Dir)
01178         {
01179             $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
01180             if (is_dir($Dir))
01181             {
01182                 $FileNames = scandir($Dir);
01183                 foreach ($FileNames as $FileName)
01184                 {
01185                     if (preg_match("/^F-([A-Za-z_]+)\.php/", $FileName, $Matches)
01186                             || preg_match("/^F-([A-Za-z_]+)\.html/", $FileName, $Matches))
01187                     {
01188                         if (!function_exists($Matches[1]))
01189                         {
01190                             include_once($Dir."/".$FileName);
01191                         }
01192                     }
01193                 }
01194             }
01195         }
01196     }
01197 
01198     private function ProcessPeriodicEvent($EventName, $Callback)
01199     {
01200         # retrieve last execution time for event if available
01201         $Signature = self::GetCallbackSignature($Callback);
01202         $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
01203                 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
01204 
01205         # determine whether enough time has passed for event to execute
01206         $EventPeriods = array(
01207                 "EVENT_HOURLY" => 60*60,
01208                 "EVENT_DAILY" => 60*60*24,
01209                 "EVENT_WEEKLY" => 60*60*24*7,
01210                 "EVENT_MONTHLY" => 60*60*24*30,
01211                 "EVENT_PERIODIC" => 0,
01212                 );
01213         $ShouldExecute = (($LastRun === NULL)
01214                 || (time() > (strtotime($LastRun) + $EventPeriods[$EventName])))
01215                 ? TRUE : FALSE;
01216 
01217         # if event should run
01218         if ($ShouldExecute)
01219         {
01220             # add event to task queue
01221             $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
01222             $WrapperParameters = array(
01223                     $EventName, $Callback, array("LastRunAt" => $LastRun));
01224             $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
01225         }
01226     }
01227 
01228     private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
01229     {
01230         static $DB;
01231         if (!isset($DB)) {  $DB = new Database();  }
01232 
01233         # run event
01234         $ReturnVal = call_user_func_array($Callback, $Parameters);
01235 
01236         # if event is already in database
01237         $Signature = self::GetCallbackSignature($Callback);
01238         if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
01239                 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
01240         {
01241             # update last run time for event
01242             $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
01243                     .(($EventName == "EVENT_PERIODIC")
01244                             ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01245                             : "NOW()")
01246                     ." WHERE Signature = '".addslashes($Signature)."'");
01247         }
01248         else
01249         {
01250             # add last run time for event to database
01251             $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
01252                     ."('".addslashes($Signature)."', "
01253                     .(($EventName == "EVENT_PERIODIC")
01254                             ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01255                             : "NOW()").")");
01256         }
01257     }
01258 
01259     private static function GetCallbackSignature($Callback)
01260     {
01261         return !is_array($Callback) ? $Callback
01262                 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
01263                         ."::".$Callback[1];
01264     }
01265 
01266     private function PrepForTSR()
01267     {
01268         # if HTML has been output and it's time to launch another task
01269         # (only TSR if HTML has been output because otherwise browsers
01270         #       may misbehave after connection is closed)
01271         if (($this->JumpToPage || !$this->SuppressHTML)
01272                 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
01273                         + (ini_get("max_execution_time")
01274                                 / $this->Settings["MaxTasksRunning"]) + 5))
01275                 && $this->GetTaskQueueSize())
01276         {
01277             # begin buffering output for TSR
01278             ob_start();
01279 
01280             # let caller know it is time to launch another task
01281             return TRUE;
01282         }
01283         else
01284         {
01285             # let caller know it is not time to launch another task
01286             return FALSE;
01287         }
01288     }
01289 
01290     private function LaunchTSR()
01291     {
01292         # set needed headers and
01293         ignore_user_abort(TRUE);
01294         header("Connection: close");
01295         header("Content-Length: ".ob_get_length());
01296 
01297         # output buffered content
01298         ob_end_flush();
01299         flush();
01300 
01301         # write out any outstanding data and end HTTP session
01302         session_write_close();
01303 
01304         # if there is still a task in the queue
01305         if ($this->GetTaskQueueSize())
01306         {
01307             # turn on output buffering to (hopefully) record any crash output
01308             ob_start();
01309 
01310             # lock tables and grab last task run time to double check
01311             $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
01312             $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
01313             $this->Settings = $this->DB->FetchRow();
01314 
01315             # if still time to launch another task
01316             if (time() > (strtotime($this->Settings["LastTaskRunAt"])
01317                         + (ini_get("max_execution_time")
01318                                 / $this->Settings["MaxTasksRunning"]) + 5))
01319             {
01320                 # update the "last run" time and release tables
01321                 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01322                         ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
01323                 $this->DB->Query("UNLOCK TABLES");
01324 
01325                 # run tasks while there is a task in the queue and enough time left
01326                 do
01327                 {
01328                     # run the next task
01329                     $this->RunNextTask();
01330                 }
01331                 while ($this->GetTaskQueueSize()
01332                         && ($this->GetSecondsBeforeTimeout() > 65));
01333             }
01334             else
01335             {
01336                 # release tables
01337                 $this->DB->Query("UNLOCK TABLES");
01338             }
01339         }
01340     }
01341 
01349     private function GetTaskList($DBQuery, $Count, $Offset)
01350     {
01351         $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
01352         $Tasks = array();
01353         while ($Row = $this->DB->FetchRow())
01354         {
01355             $Tasks[$Row["TaskId"]] = $Row;
01356             if ($Row["Callback"] ==
01357                     serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
01358             {
01359                 $WrappedCallback = unserialize($Row["Parameters"]);
01360                 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
01361                 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
01362             }
01363             else
01364             {
01365                 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
01366                 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
01367             }
01368         }
01369         return $Tasks;
01370     }
01371 
01375     private function RunNextTask()
01376     {
01377         # look for task at head of queue
01378         $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
01379         $Task = $this->DB->FetchRow();
01380 
01381         # if there was a task available
01382         if ($Task)
01383         {
01384             # move task from queue to running tasks list
01385             $this->DB->Query("INSERT INTO RunningTasks "
01386                              ."(TaskId,Callback,Parameters,Priority,Description) "
01387                              ."SELECT * FROM TaskQueue WHERE TaskId = "
01388                                     .intval($Task["TaskId"]));
01389             $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
01390                     .intval($Task["TaskId"]));
01391 
01392             # unpack stored task info
01393             $Callback = unserialize($Task["Callback"]);
01394             $Parameters = unserialize($Task["Parameters"]);
01395 
01396             # attempt to load task callback if not already available
01397             $this->LoadFunction($Callback);
01398 
01399             # run task
01400             $this->RunningTask = $Task;
01401             if ($Parameters)
01402             {
01403                 call_user_func_array($Callback, $Parameters);
01404             }
01405             else
01406             {
01407                 call_user_func($Callback);
01408             }
01409             unset($this->RunningTask);
01410 
01411             # remove task from running tasks list
01412             $this->DB->Query("DELETE FROM RunningTasks"
01413                     ." WHERE TaskId = ".intval($Task["TaskId"]));
01414 
01415             # prune running tasks list if necessary
01416             $RunningTasksCount = $this->DB->Query(
01417                     "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
01418             if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
01419             {
01420                 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
01421                         ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
01422             }
01423         }
01424     }
01425 
01431     function OnCrash()
01432     {
01433         if (isset($this->RunningTask))
01434         {
01435             if (function_exists("error_get_last"))
01436             {
01437                 $CrashInfo["LastError"] = error_get_last();
01438             }
01439             if (ob_get_length() !== FALSE)
01440             {
01441                 $CrashInfo["OutputBuffer"] = ob_get_contents();
01442             }
01443             if (isset($CrashInfo))
01444             {
01445                 $DB = new Database();
01446                 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
01447                         .addslashes(serialize($CrashInfo))
01448                         ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
01449             }
01450         }
01451 
01452         print("\n");
01453         return;
01454 
01455         if (ob_get_length() !== FALSE)
01456         {
01457             ?>
01458             <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>
01459             <div style="font-size: 200%;">CRASH OUTPUT</div><?PHP
01460             ob_end_flush();
01461             ?></td></tr></table><?PHP
01462         }
01463     }
01464 
01465     private $CommonTemplateList = array(
01466             "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01467             "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01468             "local/interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01469             "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01470             "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01471             "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01472             "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01473             "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01474             "local/interface/%ACTIVEUI%/include/%PAGENAME%",
01475             "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01476             "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01477             "interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01478             "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01479             "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01480             "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01481             "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01482             "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01483             "interface/%ACTIVEUI%/include/%PAGENAME%",
01484             "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01485             "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01486             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.tpl",
01487             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01488             "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01489             "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01490             "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01491             "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01492             "SPTUI--%ACTIVEUI%/include/%PAGENAME%",
01493             "%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01494             "%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01495             "%ACTIVEUI%/include/%PAGENAME%.tpl",
01496             "%ACTIVEUI%/include/%PAGENAME%.html",
01497             "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01498             "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01499             "%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01500             "%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01501             "%ACTIVEUI%/include/%PAGENAME%",
01502             "local/interface/default/include/StdPage%PAGENAME%.tpl",
01503             "local/interface/default/include/StdPage%PAGENAME%.html",
01504             "local/interface/default/include/%PAGENAME%.tpl",
01505             "local/interface/default/include/%PAGENAME%.html",
01506             "local/interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01507             "local/interface/default/include/SPT--StandardPage%PAGENAME%.html",
01508             "local/interface/default/include/SPT--%PAGENAME%.tpl",
01509             "local/interface/default/include/SPT--%PAGENAME%.html",
01510             "local/interface/default/include/%PAGENAME%",
01511             "interface/default/include/StdPage%PAGENAME%.tpl",
01512             "interface/default/include/StdPage%PAGENAME%.html",
01513             "interface/default/include/%PAGENAME%.tpl",
01514             "interface/default/include/%PAGENAME%.html",
01515             "interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01516             "interface/default/include/SPT--StandardPage%PAGENAME%.html",
01517             "interface/default/include/SPT--%PAGENAME%.tpl",
01518             "interface/default/include/SPT--%PAGENAME%.html",
01519             "interface/default/include/%PAGENAME%",
01520             );
01521     private $ContentTemplateList = array(
01522             "local/interface/%ACTIVEUI%/%PAGENAME%.tpl",
01523             "local/interface/%ACTIVEUI%/%PAGENAME%.html",
01524             "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01525             "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01526             "interface/%ACTIVEUI%/%PAGENAME%.tpl",
01527             "interface/%ACTIVEUI%/%PAGENAME%.html",
01528             "interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01529             "interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01530             "SPTUI--%ACTIVEUI%/%PAGENAME%.tpl",
01531             "SPTUI--%ACTIVEUI%/%PAGENAME%.html",
01532             "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01533             "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.html",
01534             "%ACTIVEUI%/%PAGENAME%.tpl",
01535             "%ACTIVEUI%/%PAGENAME%.html",
01536             "%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01537             "%ACTIVEUI%/SPT--%PAGENAME%.html",
01538             "local/interface/default/%PAGENAME%.tpl",
01539             "local/interface/default/%PAGENAME%.html",
01540             "local/interface/default/SPT--%PAGENAME%.tpl",
01541             "local/interface/default/SPT--%PAGENAME%.html",
01542             "interface/default/%PAGENAME%.tpl",
01543             "interface/default/%PAGENAME%.html",
01544             "interface/default/SPT--%PAGENAME%.tpl",
01545             "interface/default/SPT--%PAGENAME%.html",
01546             );
01547     private $ImageFileList = array(
01548             "local/interface/%ACTIVEUI%/images/%PAGENAME%",
01549             "interface/%ACTIVEUI%/images/%PAGENAME%",
01550             "SPTUI--%ACTIVEUI%/images/%PAGENAME%",
01551             "%ACTIVEUI%/images/%PAGENAME%",
01552             "local/interface/default/images/%PAGENAME%",
01553             "interface/default/images/%PAGENAME%",
01554             );
01555     private $FunctionFileList = array(
01556             "local/interface/%ACTIVEUI%/include/%PAGENAME%.php",
01557             "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01558             "interface/%ACTIVEUI%/include/%PAGENAME%.php",
01559             "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01560             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.php",
01561             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01562             "%ACTIVEUI%/include/%PAGENAME%.php",
01563             "%ACTIVEUI%/include/%PAGENAME%.html",
01564             "local/interface/default/include/%PAGENAME%.php",
01565             "local/interface/default/include/%PAGENAME%.html",
01566             "local/include/%PAGENAME%.php",
01567             "local/include/%PAGENAME%.html",
01568             "interface/default/include/%PAGENAME%.php",
01569             "interface/default/include/%PAGENAME%.html",
01570             "include/%PAGENAME%.php",
01571             "include/%PAGENAME%.html",
01572             );
01573 
01574     const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
01575 };
01576 
01577 
01578 ?>