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