Search:

CWIS Developers Documentation

  • Main Page
  • Classes
  • Files
  • File List
  • File Members

ApplicationFramework.php

Go to the documentation of this file.
00001 <?PHP
00002 
00007 class ApplicationFramework {
00008 
00009     # ---- PUBLIC INTERFACE --------------------------------------------------
00010  /*@(*/
00012 
00020     function __construct($ObjectDirectories = NULL)
00021     {
00022         # save execution start time
00023         $this->ExecutionStartTime = microtime(TRUE);
00024 
00025         # save object directory search list
00026         if ($ObjectDirectories) {  $this->AddObjectDirectories($ObjectDirectories);  }
00027 
00028         # set up object file autoloader
00029         $this->SetUpObjectAutoloading();
00030 
00031         # set up function to output any buffered text in case of crash
00032         register_shutdown_function(array($this, "OnCrash"));
00033 
00034         # set up our internal environment
00035         $this->DB = new Database();
00036 
00037         # load our settings from database
00038         $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
00039         $this->Settings = $this->DB->FetchRow();
00040         if (!$this->Settings)
00041         {
00042             $this->DB->Query("INSERT INTO ApplicationFrameworkSettings"
00043                     ." (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')");
00044             $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
00045             $this->Settings = $this->DB->FetchRow();
00046         }
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     }
00062     function AddObjectDirectories($Dirs)
00063     {
00064         foreach ($Dirs as $Location => $Prefix)
00065         {
00066             $Location = $Location
00067                     .((substr($Location, -1) != "/") ? "/" : "");
00068             self::$ObjectDirectories = array_merge(
00069                     array($Location => $Prefix),
00070                     self::$ObjectDirectories);
00071         }
00072     }
00073 
00078     function LoadPage($PageName)
00079     {
00080         # buffer any output from includes or PHP file
00081         ob_start();
00082 
00083         # include any files needed to set up execution environment
00084         foreach ($this->EnvIncludes as $IncludeFile)
00085         {
00086             include($IncludeFile);
00087         }
00088 
00089         # sanitize incoming page name
00090         $PageName = preg_replace("/[^a-zA-Z0-9_.-]/", "", $PageName);
00091 
00092         # signal page load
00093         $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName));
00094 
00095         # signal PHP file load
00096         $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array(
00097                 "PageName" => $PageName));
00098 
00099         # if signal handler returned new page name value
00100         $NewPageName = $PageName;
00101         if (($SignalResult["PageName"] != $PageName)
00102                 && strlen($SignalResult["PageName"]))
00103         {
00104             # if new page name value is page file
00105             if (file_exists($SignalResult["PageName"]))
00106             {
00107                 # use new value for PHP file name
00108                 $PageFile = $SignalResult["PageName"];
00109             }
00110             else
00111             {
00112                 # use new value for page name
00113                 $NewPageName = $SignalResult["PageName"];
00114             }
00115         }
00116 
00117         # if we do not already have a PHP file
00118         if (!isset($PageFile))
00119         {
00120             # look for PHP file for page
00121             $OurPageFile = "pages/".$NewPageName.".php";
00122             $LocalPageFile = "local/pages/".$NewPageName.".php";
00123             $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
00124                     : (file_exists($OurPageFile) ? $OurPageFile
00125                     : "pages/".$this->DefaultPage.".php");
00126         }
00127 
00128         # load PHP file
00129         include($PageFile);
00130 
00131         # save buffered output to be displayed later after HTML file loads
00132         $PageOutput = ob_get_contents();
00133         ob_end_clean();
00134 
00135         # set up for possible TSR (Terminate and Stay Resident :))
00136         $ShouldTSR = $this->PrepForTSR();
00137 
00138         # if PHP file indicated we should autorefresh to somewhere else
00139         if ($this->JumpToPage)
00140         {
00141             if (!strlen(trim($PageOutput)))
00142             {
00143                 ?><html>
00144                 <head>
00145                     <meta http-equiv="refresh" content="0; URL=<?PHP
00146                             print($this->JumpToPage);  ?>">
00147                 </head>
00148                 <body bgcolor="white">
00149                 </body>
00150                 </html><?PHP
00151             }
00152         }
00153         # else if HTML loading is not suppressed
00154         elseif (!$this->SuppressHTML)
00155         {
00156             # set content-type to get rid of diacritic errors
00157             header("Content-Type: text/html; charset="
00158                 .$this->HtmlCharset, TRUE);
00159 
00160             # load common HTML file if available
00161             $HtmlFile = $this->FindCommonTemplate("Common");
00162             if ($HtmlFile) {  include($HtmlFile);  }
00163 
00164             # load UI functions
00165             $this->LoadUIFunctions();
00166 
00167             # begin buffering content
00168             ob_start();
00169 
00170             # signal HTML file load
00171             $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array(
00172                     "PageName" => $PageName));
00173 
00174             # if signal handler returned new page name value
00175             $NewPageName = $PageName;
00176             $HtmlFile = NULL;
00177             if (($SignalResult["PageName"] != $PageName)
00178                     && strlen($SignalResult["PageName"]))
00179             {
00180                 # if new page name value is HTML file
00181                 if (file_exists($SignalResult["PageName"]))
00182                 {
00183                     # use new value for HTML file name
00184                     $HtmlFile = $SignalResult["PageName"];
00185                 }
00186                 else
00187                 {
00188                     # use new value for page name
00189                     $NewPageName = $SignalResult["PageName"];
00190                 }
00191             }
00192 
00193             # load page content HTML file if available
00194             if ($HtmlFile === NULL)
00195             {
00196                 $HtmlFile = $this->FindTemplate($this->ContentTemplateList, $NewPageName);
00197             }
00198             if ($HtmlFile)
00199             {
00200                 include($HtmlFile);
00201             }
00202             else
00203             {
00204                 print("<h2>ERROR:  No HTML/TPL template found"
00205                         ." for this page.</h2>");
00206             }
00207 
00208             # signal HTML file load complete
00209             $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE");
00210 
00211             # stop buffering and save content
00212             $BufferedContent = ob_get_contents();
00213             ob_end_clean();
00214 
00215             # load page start HTML file if available
00216             $HtmlFile = $this->FindCommonTemplate("Start");
00217             if ($HtmlFile) {  include($HtmlFile);  }
00218 
00219             # write out page content
00220             print($BufferedContent);
00221 
00222             # load page end HTML file if available
00223             $HtmlFile = $this->FindCommonTemplate("End");
00224             if ($HtmlFile) {  include($HtmlFile);  }
00225         }
00226 
00227         # run any post-processing routines
00228         foreach ($this->PostProcessingFuncs as $Func)
00229         {
00230             call_user_func_array($Func["FunctionName"], $Func["Arguments"]);
00231         }
00232 
00233         # write out any output buffered from page code execution
00234         if (strlen($PageOutput))
00235         {
00236             if (!$this->SuppressHTML)
00237             {
00238                 ?><table width="100%" cellpadding="5"
00239                         style="border: 2px solid #666666;  background: #CCCCCC;
00240                         font-family: Courier New, Courier, monospace;
00241                         margin-top: 10px;"><tr><td><?PHP
00242             }
00243             if ($this->JumpToPage)
00244             {
00245                 ?><div style="color: #666666;"><span style="font-size: 150%;">
00246                 <b>Page Jump Aborted</b></span>
00247                 (because of error or other unexpected output)<br />
00248                 <b>Jump Target:</b>
00249                 <i><?PHP  print($this->JumpToPage);  ?></i></div><?PHP
00250             }
00251             print($PageOutput);
00252             if (!$this->SuppressHTML)
00253             {
00254                 ?></td></tr></table><?PHP
00255             }
00256         }
00257 
00258         # terminate and stay resident (TSR!) if indicated and HTML has been output
00259         # (only TSR if HTML has been output because otherwise browsers will misbehave)
00260         if ($ShouldTSR) {  $this->LaunchTSR();  }
00261     }
00262 
00269     function SetJumpToPage($Page)
00270     {
00271         if ((strpos($Page, "?") === FALSE)
00272                 && ((strpos($Page, "=") !== FALSE)
00273                     || ((strpos($Page, ".php") === FALSE)
00274                         && (strpos($Page, ".htm") === FALSE)
00275                         && (strpos($Page, "/") === FALSE))))
00276         {
00277             $this->JumpToPage = "index.php?P=".$Page;
00278         }
00279         else
00280         {
00281             $this->JumpToPage = $Page;
00282         }
00283     }
00284 
00289     function JumpToPageIsSet()
00290     {
00291         return ($this->JumpToPage === NULL) ? FALSE : TRUE;
00292     }
00293 
00303     function HtmlCharset($NewSetting = NULL)
00304     {
00305         if ($NewSetting !== NULL) {  $this->HtmlCharset = $NewSetting;  }
00306         return $this->HtmlCharset;
00307     }
00308 
00315     function SuppressHTMLOutput($NewSetting = TRUE)
00316     {
00317         $this->SuppressHTML = $NewSetting;
00318     }
00319 
00326     function ActiveUserInterface($UIName = NULL)
00327     {
00328         if ($UIName !== NULL)
00329         {
00330             $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
00331         }
00332         return $this->ActiveUI;
00333     }
00334 
00350     function AddPostProcessingCall($FunctionName,
00351             &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
00352             &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
00353             &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
00354     {
00355         $FuncIndex = count($this->PostProcessingFuncs);
00356         $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
00357         $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
00358         $Index = 1;
00359         while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
00360         {
00361             $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
00362                     =& ${"Arg".$Index};
00363             $Index++;
00364         }
00365     }
00366 
00372     function AddEnvInclude($FileName)
00373     {
00374         $this->EnvIncludes[] = $FileName;
00375     }
00376 
00382     function GUIFile($FileName)
00383     {
00384         # pull off file name suffix
00385         $NamePieces = explode(".", $FileName);
00386         $Suffix = strtolower(array_pop($NamePieces));
00387 
00388         # determine which location to search based on file suffix
00389         $ImageSuffixes = array("gif", "jpg", "png");
00390         $FileList = in_array($Suffix, $ImageSuffixes)
00391                 ? $this->ImageFileList : $this->CommonTemplateList;
00392 
00393         # search for file and return result to caller
00394         return $this->FindTemplate($FileList, $FileName);
00395     }
00396 
00406     function PUIFile($FileName)
00407     {
00408         $FullFileName = $this->GUIFile($FileName);
00409         if ($FullFileName) {  print($FullFileName);  }
00410     }
00411 
00416     function FindCommonTemplate($PageName)
00417     {
00418         return $this->FindTemplate(
00419                 array_merge($this->CommonTemplateList, $this->ContentTemplateList),
00420                 $PageName);
00421     }
00422 
00431     function LoadFunction($Callback)
00432     {
00433         if (!is_callable($Callback) && is_string($Callback))
00434         {
00435             $Locations = $this->FunctionFileList;
00436             foreach (self::$ObjectDirectories as $Location => $Prefix)
00437             {
00438                 $Locations[] = $Location."%PAGENAME%.php";
00439                 $Locations[] = $Location."%PAGENAME%.html";
00440             }
00441             $FunctionFileName = $this->FindTemplate($Locations, "F-".$Callback);
00442             if ($FunctionFileName)
00443             {
00444                 include_once($FunctionFileName);
00445             }
00446         }
00447         return is_callable($Callback);
00448     }
00449 
00454     function GetElapsedExecutionTime()
00455     {
00456         return microtime(TRUE) - $this->ExecutionStartTime;
00457     }
00458 
00463     function GetSecondsBeforeTimeout()
00464     {
00465         return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
00466     }
00467 
00468     /*@)*/ /* Application Framework */
00469 
00470     # ---- Event Handling ----------------------------------------------------
00471  /*@(*/
00473 
00477     const EVENTTYPE_DEFAULT = 1;
00483     const EVENTTYPE_CHAIN = 2;
00489     const EVENTTYPE_FIRST = 3;
00497     const EVENTTYPE_NAMED = 4;
00498 
00500     const ORDER_FIRST = 1;
00502     const ORDER_MIDDLE = 2;
00504     const ORDER_LAST = 3;
00505 
00514     function RegisterEvent($EventsOrEventName, $EventType = NULL)
00515     {
00516         # convert parameters to array if not already in that form
00517         $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00518                 : array($EventsOrEventName => $Type);
00519 
00520         # for each event
00521         foreach ($Events as $Name => $Type)
00522         {
00523             # store event information
00524             $this->RegisteredEvents[$Name]["Type"] = $Type;
00525             $this->RegisteredEvents[$Name]["Hooks"] = array();
00526         }
00527     }
00528 
00542     function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
00543     {
00544         # convert parameters to array if not already in that form
00545         $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00546                 : array($EventsOrEventName => $Callback);
00547 
00548         # for each event
00549         $Success = TRUE;
00550         foreach ($Events as $EventName => $EventCallback)
00551         {
00552             # if callback is valid
00553             if (is_callable($EventCallback))
00554             {
00555                 # if this is a periodic event we process internally
00556                 if (isset($this->PeriodicEvents[$EventName]))
00557                 {
00558                     # process event now
00559                     $this->ProcessPeriodicEvent($EventName, $EventCallback);
00560                 }
00561                 # if specified event has been registered
00562                 elseif (isset($this->RegisteredEvents[$EventName]))
00563                 {
00564                     # add callback for event
00565                     $this->RegisteredEvents[$EventName]["Hooks"][]
00566                             = array("Callback" => $EventCallback, "Order" => $Order);
00567 
00568                     # sort callbacks by order
00569                     if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
00570                     {
00571                         usort($this->RegisteredEvents[$EventName]["Hooks"],
00572                                 array("ApplicationFramework", "HookEvent_OrderCompare"));
00573                     }
00574                 }
00575                 else
00576                 {
00577                     $Success = FALSE;
00578                 }
00579             }
00580             else
00581             {
00582                 $Success = FALSE;
00583             }
00584         }
00585 
00586         # report to caller whether all callbacks were hooked
00587         return $Success;
00588     }
00589     private static function HookEvent_OrderCompare($A, $B)
00590     {
00591         if ($A["Order"] == $B["Order"]) {  return 0;  }
00592         return ($A["Order"] < $B["Order"]) ? -1 : 1;
00593     }
00594 
00603     function SignalEvent($EventName, $Parameters = NULL)
00604     {
00605         $ReturnValue = NULL;
00606 
00607         # if event has been registered
00608         if (isset($this->RegisteredEvents[$EventName]))
00609         {
00610             # set up default return value (if not NULL)
00611             switch ($this->RegisteredEvents[$EventName]["Type"])
00612             {
00613                 case self::EVENTTYPE_CHAIN:
00614                     $ReturnValue = $Parameters;
00615                     break;
00616 
00617                 case self::EVENTTYPE_NAMED:
00618                     $ReturnValue = array();
00619                     break;
00620             }
00621 
00622             # for each callback for this event
00623             foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
00624             {
00625                 # invoke callback
00626                 $Callback = $Hook["Callback"];
00627                 $Result = ($Parameters !== NULL)
00628                         ? call_user_func_array($Callback, $Parameters)
00629                         : call_user_func($Callback);
00630 
00631                 # process return value based on event type
00632                 switch ($this->RegisteredEvents[$EventName]["Type"])
00633                 {
00634                     case self::EVENTTYPE_CHAIN:
00635                         $ReturnValue = $Result;
00636                         $Parameters = $Result;
00637                         break;
00638 
00639                     case self::EVENTTYPE_FIRST:
00640                         if ($Result !== NULL)
00641                         {
00642                             $ReturnValue = $Result;
00643                             break 2;
00644                         }
00645                         break;
00646 
00647                     case self::EVENTTYPE_NAMED:
00648                         $CallbackName = is_array($Callback)
00649                                 ? (is_object($Callback[0])
00650                                         ? get_class($Callback[0])
00651                                         : $Callback[0])."::".$Callback[1]
00652                                 : $Callback;
00653                         $ReturnValue[$CallbackName] = $Result;
00654                         break;
00655 
00656                     default:
00657                         break;
00658                 }
00659             }
00660         }
00661 
00662         # return value if any to caller
00663         return $ReturnValue;
00664     }
00665 
00671     function IsStaticOnlyEvent($EventName)
00672     {
00673         return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
00674     }
00675 
00676     /*@)*/ /* Event Handling */
00677 
00678     # ---- Task Management ---------------------------------------------------
00679  /*@(*/
00681 
00683     const PRIORITY_HIGH = 1;
00685     const PRIORITY_MEDIUM = 2;
00687     const PRIORITY_LOW = 3;
00689     const PRIORITY_BACKGROUND = 4;
00690 
00703     function QueueTask($Callback, $Parameters = NULL,
00704             $Priority = self::PRIORITY_MEDIUM, $Description = "")
00705     {
00706         # pack task info and write to database
00707         if ($Parameters === NULL) {  $Parameters = array();  }
00708         $this->DB->Query("INSERT INTO TaskQueue"
00709                 ." (Callback, Parameters, Priority, Description)"
00710                 ." VALUES ('".addslashes(serialize($Callback))."', '"
00711                 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
00712                 .addslashes($Description)."')");
00713     }
00714 
00732     function QueueUniqueTask($Callback, $Parameters = NULL,
00733             $Priority = self::PRIORITY_MEDIUM, $Description = "")
00734     {
00735         if ($this->TaskIsInQueue($Callback, $Parameters))
00736         {
00737             $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
00738                     ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00739                     .($Parameters ? " AND Parameters = '"
00740                             .addslashes(serialize($Parameters))."'" : ""));
00741             if ($QueryResult !== FALSE)
00742             {
00743                 $Record = $this->DB->FetchRow();
00744                 if ($Record["Priority"] > $Priority)
00745                 {
00746                     $this->DB->Query("UPDATE TaskQueue"
00747                             ." SET Priority = ".intval($Priority)
00748                             ." WHERE TaskId = ".intval($Record["TaskId"]));
00749                 }
00750             }
00751             return FALSE;
00752         }
00753         else
00754         {
00755             $this->QueueTask($Callback, $Parameters, $Priority, $Description);
00756             return TRUE;
00757         }
00758     }
00759 
00769     function TaskIsInQueue($Callback, $Parameters = NULL)
00770     {
00771         $FoundCount = $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM TaskQueue"
00772                 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00773                 .($Parameters ? " AND Parameters = '"
00774                         .addslashes(serialize($Parameters))."'" : ""),
00775                 "FoundCount")
00776                 + $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM RunningTasks"
00777                 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00778                 .($Parameters ? " AND Parameters = '"
00779                         .addslashes(serialize($Parameters))."'" : ""),
00780                 "FoundCount");
00781         return ($FoundCount ? TRUE : FALSE);
00782     }
00783 
00789     function GetTaskQueueSize($Priority = NULL)
00790     {
00791         return $this->DB->Query("SELECT COUNT(*) AS QueueSize FROM TaskQueue"
00792                 .($Priority ? " WHERE Priority = ".intval($Priority) : ""),
00793                 "QueueSize");
00794     }
00795 
00803     function GetQueuedTaskList($Count = 100, $Offset = 0)
00804     {
00805         return $this->GetTaskList("SELECT * FROM TaskQueue"
00806                 ." ORDER BY Priority, TaskId ", $Count, $Offset);
00807     }
00808 
00816     function GetRunningTaskList($Count = 100, $Offset = 0)
00817     {
00818         return $this->GetTaskList("SELECT * FROM RunningTasks"
00819                 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
00820                         (time() - ini_get("max_execution_time")))."'"
00821                 ." ORDER BY StartedAt", $Count, $Offset);
00822     }
00823 
00831     function GetOrphanedTaskList($Count = 100, $Offset = 0)
00832     {
00833         return $this->GetTaskList("SELECT * FROM RunningTasks"
00834                 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
00835                         (time() - ini_get("max_execution_time")))."'"
00836                 ." ORDER BY StartedAt", $Count, $Offset);
00837     }
00838 
00843     function ReQueueOrphanedTask($TaskId)
00844     {
00845         $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
00846         $this->DB->Query("INSERT INTO TaskQueue"
00847                          ." (Callback,Parameters,Priority,Description) "
00848                          ."SELECT Callback, Parameters, Priority, Description"
00849                          ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00850         $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00851         $this->DB->Query("UNLOCK TABLES");
00852     }
00853 
00858     function DeleteTask($TaskId)
00859     {
00860         $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
00861         $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00862     }
00863 
00871     function GetTask($TaskId)
00872     {
00873         # assume task will not be found
00874         $Task = NULL;
00875 
00876         # look for task in task queue
00877         $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
00878 
00879         # if task was not found in queue
00880         if (!$this->DB->NumRowsSelected())
00881         {
00882             # look for task in running task list
00883             $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = "
00884                     .intval($TaskId));
00885         }
00886 
00887         # if task was found
00888         if ($this->DB->NumRowsSelected())
00889         {
00890             # if task was periodic
00891             $Row = $this->DB->FetchRow();
00892             if ($Row["Callback"] ==
00893                     serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
00894             {
00895                 # unpack periodic task callback
00896                 $WrappedCallback = unserialize($Row["Parameters"]);
00897                 $Task["Callback"] = $WrappedCallback[1];
00898                 $Task["Parameters"] = NULL;
00899             }
00900             else
00901             {
00902                 # unpack task callback and parameters
00903                 $Task["Callback"] = unserialize($Row["Callback"]);
00904                 $Task["Parameters"] = unserialize($Row["Parameters"]);
00905             }
00906         }
00907 
00908         # return task to caller
00909         return $Task;
00910     }
00911 
00917     function MaxTasks($NewValue = NULL)
00918     {
00919         if (func_num_args() && ($NewValue >= 1))
00920         {
00921             $this->DB->Query("UPDATE ApplicationFrameworkSettings"
00922                     ." SET MaxTasksRunning = '".intval($NewValue)."'");
00923             $this->Settings["MaxTasksRunning"] = intval($NewValue);
00924         }
00925         return $this->Settings["MaxTasksRunning"];
00926     }
00927 
00935     function MaxExecutionTime($NewValue = NULL)
00936     {
00937         if (func_num_args() && !ini_get("safe_mode"))
00938         {
00939             if ($NewValue != $this->Settings["MaxExecTime"])
00940             {
00941                 $this->Settings["MaxExecTime"] = max($NewValue, 5);
00942                 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
00943                         ." SET MaxExecTime = '"
00944                                 .intval($this->Settings["MaxExecTime"])."'");
00945             }
00946             ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
00947             set_time_limit($this->Settings["MaxExecTime"]);
00948         }
00949         return ini_get("max_execution_time");
00950     }
00951 
00952     /*@)*/ /* Task Management */
00953 
00954     # ---- PRIVATE INTERFACE -------------------------------------------------
00955 
00956     private $JumpToPage = NULL;
00957     private $SuppressHTML = FALSE;
00958     private $DefaultPage = "Home";
00959     private $ActiveUI = "default";
00960     private $HtmlCharset = "UTF-8";
00961     private $PostProcessingFuncs = array();
00962     private $EnvIncludes = array();
00963     private $DB;
00964     private $Settings;
00965     private $ExecutionStartTime;
00966     private static $ObjectDirectories = array();
00967     private $MaxRunningTasksToTrack = 250;
00968     private $RunningTask;
00969 
00970     private $PeriodicEvents = array(
00971                 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
00972                 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
00973                 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
00974                 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
00975                 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
00976                 );
00977     private $UIEvents = array(
00978                 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
00979                 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
00980                 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
00981                 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
00982                 );
00983 
00984     private function FindTemplate($FileList, $PageName)
00985     {
00986         $FileNameFound = NULL;
00987         foreach ($FileList as $FileName)
00988         {
00989             $FileName = str_replace("%ACTIVEUI%", $this->ActiveUI, $FileName);
00990             $FileName = str_replace("%PAGENAME%", $PageName, $FileName);
00991             if (file_exists($FileName))
00992             {
00993                 $FileNameFound = $FileName;
00994                 break;
00995             }
00996         }
00997         return $FileNameFound;
00998     }
00999 
01000     private function SetUpObjectAutoloading()
01001     {
01002         function __autoload($ClassName)
01003         {
01004             ApplicationFramework::AutoloadObjects($ClassName);
01005         }
01006     }
01007 
01009     static function AutoloadObjects($ClassName)
01010     {
01011         foreach (self::$ObjectDirectories as $Location => $Prefix)
01012         {
01013             $FileName = $Location.$Prefix.$ClassName.".php";
01014             if (file_exists($FileName))
01015             {
01016                 require_once($FileName);
01017                 break;
01018             }
01019         }
01020     }
01023     private function LoadUIFunctions()
01024     {
01025         $Dirs = array(
01026                 "local/interface/%ACTIVEUI%/include",
01027                 "interface/%ACTIVEUI%/include",
01028                 "local/interface/default/include",
01029                 "interface/default/include",
01030                 );
01031         foreach ($Dirs as $Dir)
01032         {
01033             $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
01034             if (is_dir($Dir))
01035             {
01036                 $FileNames = scandir($Dir);
01037                 foreach ($FileNames as $FileName)
01038                 {
01039                     if (preg_match("/^F-([A-Za-z_]+)\.php/", $FileName, $Matches)
01040                             || preg_match("/^F-([A-Za-z_]+)\.html/", $FileName, $Matches))
01041                     {
01042                         if (!function_exists($Matches[1]))
01043                         {
01044                             include_once($Dir."/".$FileName);
01045                         }
01046                     }
01047                 }
01048             }
01049         }
01050     }
01051 
01052     private function ProcessPeriodicEvent($EventName, $Callback)
01053     {
01054         # retrieve last execution time for event if available
01055         $Signature = self::GetCallbackSignature($Callback);
01056         $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
01057                 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
01058 
01059         # determine whether enough time has passed for event to execute
01060         $EventPeriods = array(
01061                 "EVENT_HOURLY" => 60*60,
01062                 "EVENT_DAILY" => 60*60*24,
01063                 "EVENT_WEEKLY" => 60*60*24*7,
01064                 "EVENT_MONTHLY" => 60*60*24*30,
01065                 "EVENT_PERIODIC" => 0,
01066                 );
01067         $ShouldExecute = (($LastRun === NULL)
01068                 || (time() > (strtotime($LastRun) + $EventPeriods[$EventName])))
01069                 ? TRUE : FALSE;
01070 
01071         # if event should run
01072         if ($ShouldExecute)
01073         {
01074             # add event to task queue
01075             $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
01076             $WrapperParameters = array(
01077                     $EventName, $Callback, array("LastRunAt" => $LastRun));
01078             $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
01079         }
01080     }
01081 
01082     private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
01083     {
01084         static $DB;
01085         if (!isset($DB)) {  $DB = new Database();  }
01086 
01087         # run event
01088         $ReturnVal = call_user_func_array($Callback, $Parameters);
01089 
01090         # if event is already in database
01091         $Signature = self::GetCallbackSignature($Callback);
01092         if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
01093                 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
01094         {
01095             # update last run time for event
01096             $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
01097                     .(($EventName == "EVENT_PERIODIC")
01098                             ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01099                             : "NOW()")
01100                     ." WHERE Signature = '".addslashes($Signature)."'");
01101         }
01102         else
01103         {
01104             # add last run time for event to database
01105             $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
01106                     ."('".addslashes($Signature)."', "
01107                     .(($EventName == "EVENT_PERIODIC")
01108                             ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01109                             : "NOW()").")");
01110         }
01111     }
01112 
01113     private static function GetCallbackSignature($Callback)
01114     {
01115         return !is_array($Callback) ? $Callback
01116                 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
01117                         ."::".$Callback[1];
01118     }
01119 
01120     private function PrepForTSR()
01121     {
01122         # if HTML has been output and it's time to launch another task
01123         # (only TSR if HTML has been output because otherwise browsers
01124         #       may misbehave after connection is closed)
01125         if (($this->JumpToPage || !$this->SuppressHTML)
01126                 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
01127                         + (ini_get("max_execution_time")
01128                                 / $this->Settings["MaxTasksRunning"]) + 5))
01129                 && $this->GetTaskQueueSize())
01130         {
01131             # begin buffering output for TSR
01132             ob_start();
01133 
01134             # let caller know it is time to launch another task
01135             return TRUE;
01136         }
01137         else
01138         {
01139             # let caller know it is not time to launch another task
01140             return FALSE;
01141         }
01142     }
01143 
01144     private function LaunchTSR()
01145     {
01146         # set needed headers and
01147         ignore_user_abort(TRUE);
01148         header("Connection: close");
01149         header("Content-Length: ".ob_get_length());
01150 
01151         # output buffered content
01152         ob_end_flush();
01153         flush();
01154 
01155         # write out any outstanding data and end HTTP session
01156         session_write_close();
01157 
01158         # if there is still a task in the queue
01159         if ($this->GetTaskQueueSize())
01160         {
01161             # turn on output buffering to (hopefully) record any crash output
01162             ob_start();
01163 
01164             # lock tables and grab last task run time to double check
01165             $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
01166             $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
01167             $this->Settings = $this->DB->FetchRow();
01168 
01169             # if still time to launch another task
01170             if (time() > (strtotime($this->Settings["LastTaskRunAt"])
01171                         + (ini_get("max_execution_time")
01172                                 / $this->Settings["MaxTasksRunning"]) + 5))
01173             {
01174                 # update the "last run" time and release tables
01175                 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01176                         ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
01177                 $this->DB->Query("UNLOCK TABLES");
01178 
01179                 # run tasks while there is a task in the queue and enough time left
01180                 do
01181                 {
01182                     # run the next task
01183                     $this->RunNextTask();
01184                 }
01185                 while ($this->GetTaskQueueSize()
01186                         && ($this->GetSecondsBeforeTimeout() > 65));
01187             }
01188             else
01189             {
01190                 # release tables
01191                 $this->DB->Query("UNLOCK TABLES");
01192             }
01193         }
01194     }
01195 
01203     private function GetTaskList($DBQuery, $Count, $Offset)
01204     {
01205         $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
01206         $Tasks = array();
01207         while ($Row = $this->DB->FetchRow())
01208         {
01209             $Tasks[$Row["TaskId"]] = $Row;
01210             if ($Row["Callback"] ==
01211                     serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
01212             {
01213                 $WrappedCallback = unserialize($Row["Parameters"]);
01214                 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
01215                 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
01216             }
01217             else
01218             {
01219                 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
01220                 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
01221             }
01222         }
01223         return $Tasks;
01224     }
01225 
01229     private function RunNextTask()
01230     {
01231         # look for task at head of queue
01232         $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
01233         $Task = $this->DB->FetchRow();
01234 
01235         # if there was a task available
01236         if ($Task)
01237         {
01238             # move task from queue to running tasks list
01239             $this->DB->Query("INSERT INTO RunningTasks "
01240                              ."(TaskId,Callback,Parameters,Priority,Description) "
01241                              ."SELECT * FROM TaskQueue WHERE TaskId = "
01242                                     .intval($Task["TaskId"]));
01243             $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
01244                     .intval($Task["TaskId"]));
01245 
01246             # unpack stored task info
01247             $Callback = unserialize($Task["Callback"]);
01248             $Parameters = unserialize($Task["Parameters"]);
01249 
01250             # attempt to load task callback if not already available
01251             $this->LoadFunction($Callback);
01252 
01253             # run task
01254             $this->RunningTask = $Task;
01255             if ($Parameters)
01256             {
01257                 call_user_func_array($Callback, $Parameters);
01258             }
01259             else
01260             {
01261                 call_user_func($Callback);
01262             }
01263             unset($this->RunningTask);
01264 
01265             # remove task from running tasks list
01266             $this->DB->Query("DELETE FROM RunningTasks"
01267                     ." WHERE TaskId = ".intval($Task["TaskId"]));
01268 
01269             # prune running tasks list if necessary
01270             $RunningTasksCount = $this->DB->Query(
01271                     "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
01272             if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
01273             {
01274                 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
01275                         ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
01276             }
01277         }
01278     }
01279 
01285     function OnCrash()
01286     {
01287         if (isset($this->RunningTask))
01288         {
01289             if (function_exists("error_get_last"))
01290             {
01291                 $CrashInfo["LastError"] = error_get_last();
01292             }
01293             if (ob_get_length() !== FALSE)
01294             {
01295                 $CrashInfo["OutputBuffer"] = ob_get_contents();
01296             }
01297             if (isset($CrashInfo))
01298             {
01299                 $DB = new Database();
01300                 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
01301                         .addslashes(serialize($CrashInfo))
01302                         ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
01303             }
01304         }
01305 
01306         print("\n");
01307         return;
01308 
01309         if (ob_get_length() !== FALSE)
01310         {
01311             ?>
01312             <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>
01313             <div style="font-size: 200%;">CRASH OUTPUT</div><?PHP
01314             ob_end_flush();
01315             ?></td></tr></table><?PHP
01316         }
01317     }
01318 
01319     private $CommonTemplateList = array(
01320             "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01321             "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01322             "local/interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01323             "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01324             "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01325             "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01326             "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01327             "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01328             "local/interface/%ACTIVEUI%/include/%PAGENAME%",
01329             "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01330             "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01331             "interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01332             "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01333             "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01334             "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01335             "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01336             "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01337             "interface/%ACTIVEUI%/include/%PAGENAME%",
01338             "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01339             "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01340             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.tpl",
01341             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01342             "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01343             "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01344             "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01345             "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01346             "SPTUI--%ACTIVEUI%/include/%PAGENAME%",
01347             "%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01348             "%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01349             "%ACTIVEUI%/include/%PAGENAME%.tpl",
01350             "%ACTIVEUI%/include/%PAGENAME%.html",
01351             "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01352             "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01353             "%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01354             "%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01355             "%ACTIVEUI%/include/%PAGENAME%",
01356             "local/interface/default/include/StdPage%PAGENAME%.tpl",
01357             "local/interface/default/include/StdPage%PAGENAME%.html",
01358             "local/interface/default/include/%PAGENAME%.tpl",
01359             "local/interface/default/include/%PAGENAME%.html",
01360             "local/interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01361             "local/interface/default/include/SPT--StandardPage%PAGENAME%.html",
01362             "local/interface/default/include/SPT--%PAGENAME%.tpl",
01363             "local/interface/default/include/SPT--%PAGENAME%.html",
01364             "local/interface/default/include/%PAGENAME%",
01365             "interface/default/include/StdPage%PAGENAME%.tpl",
01366             "interface/default/include/StdPage%PAGENAME%.html",
01367             "interface/default/include/%PAGENAME%.tpl",
01368             "interface/default/include/%PAGENAME%.html",
01369             "interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01370             "interface/default/include/SPT--StandardPage%PAGENAME%.html",
01371             "interface/default/include/SPT--%PAGENAME%.tpl",
01372             "interface/default/include/SPT--%PAGENAME%.html",
01373             "interface/default/include/%PAGENAME%",
01374             );
01375     private $ContentTemplateList = array(
01376             "local/interface/%ACTIVEUI%/%PAGENAME%.tpl",
01377             "local/interface/%ACTIVEUI%/%PAGENAME%.html",
01378             "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01379             "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01380             "interface/%ACTIVEUI%/%PAGENAME%.tpl",
01381             "interface/%ACTIVEUI%/%PAGENAME%.html",
01382             "interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01383             "interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01384             "SPTUI--%ACTIVEUI%/%PAGENAME%.tpl",
01385             "SPTUI--%ACTIVEUI%/%PAGENAME%.html",
01386             "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01387             "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.html",
01388             "%ACTIVEUI%/%PAGENAME%.tpl",
01389             "%ACTIVEUI%/%PAGENAME%.html",
01390             "%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01391             "%ACTIVEUI%/SPT--%PAGENAME%.html",
01392             "local/interface/default/%PAGENAME%.tpl",
01393             "local/interface/default/%PAGENAME%.html",
01394             "local/interface/default/SPT--%PAGENAME%.tpl",
01395             "local/interface/default/SPT--%PAGENAME%.html",
01396             "interface/default/%PAGENAME%.tpl",
01397             "interface/default/%PAGENAME%.html",
01398             "interface/default/SPT--%PAGENAME%.tpl",
01399             "interface/default/SPT--%PAGENAME%.html",
01400             );
01401     private $ImageFileList = array(
01402             "local/interface/%ACTIVEUI%/images/%PAGENAME%",
01403             "interface/%ACTIVEUI%/images/%PAGENAME%",
01404             "SPTUI--%ACTIVEUI%/images/%PAGENAME%",
01405             "%ACTIVEUI%/images/%PAGENAME%",
01406             "local/interface/default/images/%PAGENAME%",
01407             "interface/default/images/%PAGENAME%",
01408             );
01409     private $FunctionFileList = array(
01410             "local/interface/%ACTIVEUI%/include/%PAGENAME%.php",
01411             "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01412             "interface/%ACTIVEUI%/include/%PAGENAME%.php",
01413             "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01414             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.php",
01415             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01416             "%ACTIVEUI%/include/%PAGENAME%.php",
01417             "%ACTIVEUI%/include/%PAGENAME%.html",
01418             "local/interface/default/include/%PAGENAME%.php",
01419             "local/interface/default/include/%PAGENAME%.html",
01420             "local/include/%PAGENAME%.php",
01421             "local/include/%PAGENAME%.html",
01422             "interface/default/include/%PAGENAME%.php",
01423             "interface/default/include/%PAGENAME%.html",
01424             "include/%PAGENAME%.php",
01425             "include/%PAGENAME%.html",
01426             );
01427 
01428     const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
01429 };
01430 
01431 
01432 ?>

CWIS logo doxygen
Copyright 2010 Internet Scout