Search:

# CWIS Developers Documentation

- Main Page
- Classes
- Files

- File List
- File Members

# 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 ?>