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 (NOW())");
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         # signal page load
00090         $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName));
00091 
00092         # signal PHP file load
00093         $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array(
00094                 "PageName" => $PageName));
00095 
00096         # if signal handler returned new page name value
00097         $NewPageName = $PageName;
00098         if (($SignalResult["PageName"] != $PageName)
00099                 && strlen($SignalResult["PageName"]))
00100         {
00101             # if new page name value is page file
00102             if (file_exists($SignalResult["PageName"]))
00103             {
00104                 # use new value for PHP file name
00105                 $PageFile = $SignalResult["PageName"];
00106             }
00107             else
00108             {
00109                 # use new value for page name
00110                 $NewPageName = $SignalResult["PageName"];
00111             }
00112         }
00113 
00114         # if we do not already have a PHP file
00115         if (!isset($PageFile))
00116         {
00117             # look for PHP file for page
00118             $OurPageFile = "pages/".$NewPageName.".php";
00119             $LocalPageFile = "local/pages/".$NewPageName.".php";
00120             $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
00121                     : (file_exists($OurPageFile) ? $OurPageFile
00122                     : "pages/".$this->DefaultPage.".php");
00123         }
00124 
00125         # load PHP file
00126         include($PageFile);
00127 
00128         # save buffered output to be displayed later after HTML file loads
00129         $PageOutput = ob_get_contents();
00130         ob_end_clean();
00131 
00132         # set up for possible TSR (Terminate and Stay Resident :))
00133         $ShouldTSR = $this->PrepForTSR();
00134 
00135         # if PHP file indicated we should autorefresh to somewhere else
00136         if ($this->JumpToPage)
00137         {
00138             if (!strlen(trim($PageOutput)))
00139             {
00140                 ?><html>
00141                 <head>
00142                     <meta http-equiv="refresh" content="0; URL=<?PHP
00143                             print($this->JumpToPage);  ?>">
00144                 </head>
00145                 <body bgcolor="white">
00146                 </body>
00147                 </html><?PHP
00148             }
00149         }
00150         # else if HTML loading is not suppressed
00151         elseif (!$this->SuppressHTML)
00152         {
00153             # set content-type to get rid of diacritic errors
00154             header("Content-Type: text/html; charset="
00155                 .$this->HtmlCharset, TRUE);
00156 
00157             # load common HTML file if available
00158             $HtmlFile = $this->FindCommonTemplate("Common");
00159             if ($HtmlFile) {  include($HtmlFile);  }
00160 
00161             # load UI functions
00162             $this->LoadUIFunctions();
00163 
00164             # begin buffering content
00165             ob_start();
00166 
00167             # signal HTML file load
00168             $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array(
00169                     "PageName" => $PageName));
00170 
00171             # if signal handler returned new page name value
00172             $NewPageName = $PageName;
00173             $HtmlFile = NULL;
00174             if (($SignalResult["PageName"] != $PageName)
00175                     && strlen($SignalResult["PageName"]))
00176             {
00177                 # if new page name value is HTML file
00178                 if (file_exists($SignalResult["PageName"]))
00179                 {
00180                     # use new value for HTML file name
00181                     $HtmlFile = $SignalResult["PageName"];
00182                 }
00183                 else
00184                 {
00185                     # use new value for page name
00186                     $NewPageName = $SignalResult["PageName"];
00187                 }
00188             }
00189 
00190             # load page content HTML file if available
00191             if ($HtmlFile === NULL)
00192             {
00193                 $HtmlFile = $this->FindTemplate($this->ContentTemplateList, $NewPageName);
00194             }
00195             if ($HtmlFile)
00196             {
00197                 include($HtmlFile);
00198             }
00199             else
00200             {
00201                 print("<h2>ERROR:  No HTML/TPL template found"
00202                         ." for this page.</h2>");
00203             }
00204 
00205             # signal HTML file load complete
00206             $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE");
00207 
00208             # stop buffering and save content
00209             $BufferedContent = ob_get_contents();
00210             ob_end_clean();
00211 
00212             # load page start HTML file if available
00213             $HtmlFile = $this->FindCommonTemplate("Start");
00214             if ($HtmlFile) {  include($HtmlFile);  }
00215 
00216             # write out page content
00217             print($BufferedContent);
00218 
00219             # load page end HTML file if available
00220             $HtmlFile = $this->FindCommonTemplate("End");
00221             if ($HtmlFile) {  include($HtmlFile);  }
00222         }
00223 
00224         # run any post-processing routines
00225         foreach ($this->PostProcessingFuncs as $Func)
00226         {
00227             call_user_func_array($Func["FunctionName"], $Func["Arguments"]);
00228         }
00229 
00230         # write out any output buffered from page code execution
00231         if (strlen($PageOutput))
00232         {
00233             if (!$this->SuppressHTML)
00234             {
00235                 ?><table width="100%" cellpadding="5"
00236                         style="border: 2px solid #666666;  background: #CCCCCC;
00237                         font-family: Courier New, Courier, monospace;
00238                         margin-top: 10px;"><tr><td><?PHP
00239             }
00240             if ($this->JumpToPage)
00241             {
00242                 ?><div style="color: #666666;"><span style="font-size: 150%;">
00243                 <b>Page Jump Aborted</b></span>
00244                 (because of error or other unexpected output)<br />
00245                 <b>Jump Target:</b>
00246                 <i><?PHP  print($this->JumpToPage);  ?></i></div><?PHP
00247             }
00248             print($PageOutput);
00249             if (!$this->SuppressHTML)
00250             {
00251                 ?></td></tr></table><?PHP
00252             }
00253         }
00254 
00255         # terminate and stay resident (TSR!) if indicated and HTML has been output
00256         # (only TSR if HTML has been output because otherwise browsers will misbehave)
00257         if ($ShouldTSR) {  $this->LaunchTSR();  }
00258     }
00259 
00266     function SetJumpToPage($Page)
00267     {
00268         if ((strpos($Page, "?") === FALSE)
00269                 && ((strpos($Page, "=") !== FALSE)
00270                     || ((strpos($Page, ".php") === FALSE)
00271                         && (strpos($Page, ".htm") === FALSE)
00272                         && (strpos($Page, "/") === FALSE))))
00273         {
00274             $this->JumpToPage = "index.php?P=".$Page;
00275         }
00276         else
00277         {
00278             $this->JumpToPage = $Page;
00279         }
00280     }
00281 
00286     function JumpToPageIsSet()
00287     {
00288         return ($this->JumpToPage === NULL) ? FALSE : TRUE;
00289     }
00290 
00300     function HtmlCharset($NewSetting = NULL)
00301     {
00302         if ($NewSetting !== NULL) {  $this->HtmlCharset = $NewSetting;  }
00303         return $this->HtmlCharset;
00304     }
00305 
00312     function SuppressHTMLOutput($NewSetting = TRUE)
00313     {
00314         $this->SuppressHTML = $NewSetting;
00315     }
00316 
00323     function ActiveUserInterface($UIName = NULL)
00324     {
00325         if ($UIName !== NULL)
00326         {
00327             $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
00328         }
00329         return $this->ActiveUI;
00330     }
00331 
00347     function AddPostProcessingCall($FunctionName,
00348             &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
00349             &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
00350             &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
00351     {
00352         $FuncIndex = count($this->PostProcessingFuncs);
00353         $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
00354         $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
00355         $Index = 1;
00356         while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
00357         {
00358             $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
00359                     =& ${"Arg".$Index};
00360             $Index++;
00361         }
00362     }
00363 
00369     function AddEnvInclude($FileName)
00370     {
00371         $this->EnvIncludes[] = $FileName;
00372     }
00373 
00379     function GUIFile($FileName)
00380     {
00381         # pull off file name suffix
00382         $NamePieces = explode(".", $FileName);
00383         $Suffix = strtolower(array_pop($NamePieces));
00384 
00385         # determine which location to search based on file suffix
00386         $ImageSuffixes = array("gif", "jpg", "png");
00387         $FileList = in_array($Suffix, $ImageSuffixes)
00388                 ? $this->ImageFileList : $this->CommonTemplateList;
00389 
00390         # search for file and return result to caller
00391         return $this->FindTemplate($FileList, $FileName);
00392     }
00393 
00403     function PUIFile($FileName)
00404     {
00405         $FullFileName = $this->GUIFile($FileName);
00406         if ($FullFileName) {  print($FullFileName);  }
00407     }
00408 
00413     function FindCommonTemplate($PageName)
00414     {
00415         return $this->FindTemplate(
00416                 array_merge($this->CommonTemplateList, $this->ContentTemplateList),
00417                 $PageName);
00418     }
00419 
00428     function LoadFunction($Callback)
00429     {
00430         if (!is_callable($Callback) && is_string($Callback))
00431         {
00432             $Locations = $this->FunctionFileList;
00433             foreach (self::$ObjectDirectories as $Location => $Prefix)
00434             {
00435                 $Locations[] = $Location."%PAGENAME%.php";
00436                 $Locations[] = $Location."%PAGENAME%.html";
00437             }
00438             $FunctionFileName = $this->FindTemplate($Locations, "F-".$Callback);
00439             if ($FunctionFileName)
00440             {
00441                 include_once($FunctionFileName);
00442             }
00443         }
00444         return is_callable($Callback);
00445     }
00446 
00451     function GetElapsedExecutionTime()
00452     {
00453         return microtime(TRUE) - $this->ExecutionStartTime;
00454     }
00455 
00460     function GetSecondsBeforeTimeout()
00461     {
00462         return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
00463     }
00464 
00465     /*@)*/ /* Application Framework */
00466 
00467     # ---- Event Handling ----------------------------------------------------
00468  /*@(*/
00470 
00474     const EVENTTYPE_DEFAULT = 1;
00480     const EVENTTYPE_CHAIN = 2;
00486     const EVENTTYPE_FIRST = 3;
00494     const EVENTTYPE_NAMED = 4;
00495 
00497     const ORDER_FIRST = 1;
00499     const ORDER_MIDDLE = 2;
00501     const ORDER_LAST = 3;
00502 
00511     function RegisterEvent($EventsOrEventName, $EventType = NULL)
00512     {
00513         # convert parameters to array if not already in that form
00514         $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00515                 : array($EventsOrEventName => $Type);
00516 
00517         # for each event
00518         foreach ($Events as $Name => $Type)
00519         {
00520             # store event information
00521             $this->RegisteredEvents[$Name]["Type"] = $Type;
00522             $this->RegisteredEvents[$Name]["Hooks"] = array();
00523         }
00524     }
00525 
00539     function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
00540     {
00541         # convert parameters to array if not already in that form
00542         $Events = is_array($EventsOrEventName) ? $EventsOrEventName
00543                 : array($EventsOrEventName => $Callback);
00544 
00545         # for each event
00546         $Success = TRUE;
00547         foreach ($Events as $EventName => $EventCallback)
00548         {
00549             # if callback is valid
00550             if (is_callable($EventCallback))
00551             {
00552                 # if this is a periodic event we process internally
00553                 if (isset($this->PeriodicEvents[$EventName]))
00554                 {
00555                     # process event now
00556                     $this->ProcessPeriodicEvent($EventName, $EventCallback);
00557                 }
00558                 # if specified event has been registered
00559                 elseif (isset($this->RegisteredEvents[$EventName]))
00560                 {
00561                     # add callback for event
00562                     $this->RegisteredEvents[$EventName]["Hooks"][]
00563                             = array("Callback" => $EventCallback, "Order" => $Order);
00564 
00565                     # sort callbacks by order
00566                     if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
00567                     {
00568                         usort($this->RegisteredEvents[$EventName]["Hooks"],
00569                                 array("ApplicationFramework", "HookEvent_OrderCompare"));
00570                     }
00571                 }
00572                 else
00573                 {
00574                     $Success = FALSE;
00575                 }
00576             }
00577             else
00578             {
00579                 $Success = FALSE;
00580             }
00581         }
00582 
00583         # report to caller whether all callbacks were hooked
00584         return $Success;
00585     }
00586     private static function HookEvent_OrderCompare($A, $B)
00587     {
00588         if ($A["Order"] == $B["Order"]) {  return 0;  }
00589         return ($A["Order"] < $B["Order"]) ? -1 : 1;
00590     }
00591 
00600     function SignalEvent($EventName, $Parameters = NULL)
00601     {
00602         $ReturnValue = NULL;
00603 
00604         # if event has been registered
00605         if (isset($this->RegisteredEvents[$EventName]))
00606         {
00607             # set up default return value (if not NULL)
00608             switch ($this->RegisteredEvents[$EventName]["Type"])
00609             {
00610                 case self::EVENTTYPE_CHAIN:
00611                     $ReturnValue = $Parameters;
00612                     break;
00613 
00614                 case self::EVENTTYPE_NAMED:
00615                     $ReturnValue = array();
00616                     break;
00617             }
00618 
00619             # for each callback for this event
00620             foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
00621             {
00622                 # invoke callback
00623                 $Callback = $Hook["Callback"];
00624                 $Result = ($Parameters !== NULL)
00625                         ? call_user_func_array($Callback, $Parameters)
00626                         : call_user_func($Callback);
00627 
00628                 # process return value based on event type
00629                 switch ($this->RegisteredEvents[$EventName]["Type"])
00630                 {
00631                     case self::EVENTTYPE_CHAIN:
00632                         $ReturnValue = $Result;
00633                         $Parameters = $Result;
00634                         break;
00635 
00636                     case self::EVENTTYPE_FIRST:
00637                         if ($Result !== NULL)
00638                         {
00639                             $ReturnValue = $Result;
00640                             break 2;
00641                         }
00642                         break;
00643 
00644                     case self::EVENTTYPE_NAMED:
00645                         $CallbackName = is_array($Callback)
00646                                 ? (is_object($Callback[0])
00647                                         ? get_class($Callback[0])
00648                                         : $Callback[0])."::".$Callback[1]
00649                                 : $Callback;
00650                         $ReturnValue[$CallbackName] = $Result;
00651                         break;
00652 
00653                     default:
00654                         break;
00655                 }
00656             }
00657         }
00658 
00659         # return value if any to caller
00660         return $ReturnValue;
00661     }
00662 
00668     function IsStaticOnlyEvent($EventName)
00669     {
00670         return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
00671     }
00672 
00673     /*@)*/ /* Event Handling */
00674 
00675     # ---- Task Management ---------------------------------------------------
00676  /*@(*/
00678 
00680     const PRIORITY_HIGH = 1;
00682     const PRIORITY_MEDIUM = 2;
00684     const PRIORITY_LOW = 3;
00686     const PRIORITY_BACKGROUND = 4;
00687 
00700     function QueueTask($Callback, $Parameters = NULL,
00701             $Priority = self::PRIORITY_MEDIUM, $Description = "")
00702     {
00703         # pack task info and write to database
00704         if ($Parameters === NULL) {  $Parameters = array();  }
00705         $this->DB->Query("INSERT INTO TaskQueue"
00706                 ." (Callback, Parameters, Priority, Description)"
00707                 ." VALUES ('".addslashes(serialize($Callback))."', '"
00708                 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
00709                 .addslashes($Description)."')");
00710     }
00711 
00729     function QueueUniqueTask($Callback, $Parameters = NULL,
00730             $Priority = self::PRIORITY_MEDIUM, $Description = "")
00731     {
00732         if ($this->TaskIsInQueue($Callback, $Parameters))
00733         {
00734             $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
00735                     ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00736                     .($Parameters ? " AND Parameters = '"
00737                             .addslashes(serialize($Parameters))."'" : ""));
00738             if ($QueryResult !== FALSE)
00739             {
00740                 $Record = $this->DB->FetchRow();
00741                 if ($Record["Priority"] > $Priority)
00742                 {
00743                     $this->DB->Query("UPDATE TaskQueue"
00744                             ." SET Priority = ".intval($Priority)
00745                             ." WHERE TaskId = ".intval($Record["TaskId"]));
00746                 }
00747             }
00748             return FALSE;
00749         }
00750         else
00751         {
00752             $this->QueueTask($Callback, $Parameters, $Priority, $Description);
00753             return TRUE;
00754         }
00755     }
00756 
00766     function TaskIsInQueue($Callback, $Parameters = NULL)
00767     {
00768         $FoundCount = $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM TaskQueue"
00769                 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00770                 .($Parameters ? " AND Parameters = '"
00771                         .addslashes(serialize($Parameters))."'" : ""),
00772                 "FoundCount")
00773                 + $this->DB->Query("SELECT COUNT(*) AS FoundCount FROM RunningTasks"
00774                 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
00775                 .($Parameters ? " AND Parameters = '"
00776                         .addslashes(serialize($Parameters))."'" : ""),
00777                 "FoundCount");
00778         return ($FoundCount ? TRUE : FALSE);
00779     }
00780 
00786     function GetTaskQueueSize($Priority = NULL)
00787     {
00788         return $this->DB->Query("SELECT COUNT(*) AS QueueSize FROM TaskQueue"
00789                 .($Priority ? " WHERE Priority = ".intval($Priority) : ""),
00790                 "QueueSize");
00791     }
00792 
00800     function GetQueuedTaskList($Count = 100, $Offset = 0)
00801     {
00802         return $this->GetTaskList("SELECT * FROM TaskQueue"
00803                 ." ORDER BY Priority, TaskId ", $Count, $Offset);
00804     }
00805 
00813     function GetRunningTaskList($Count = 100, $Offset = 0)
00814     {
00815         return $this->GetTaskList("SELECT * FROM RunningTasks"
00816                 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
00817                         (time() - ini_get("max_execution_time")))."'"
00818                 ." ORDER BY StartedAt", $Count, $Offset);
00819     }
00820 
00828     function GetOrphanedTaskList($Count = 100, $Offset = 0)
00829     {
00830         return $this->GetTaskList("SELECT * FROM RunningTasks"
00831                 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
00832                         (time() - ini_get("max_execution_time")))."'"
00833                 ." ORDER BY StartedAt", $Count, $Offset);
00834     }
00835 
00840     function ReQueueOrphanedTask($TaskId)
00841     {
00842         $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
00843         $this->DB->Query("INSERT INTO TaskQueue"
00844                          ." (Callback,Parameters,Priority,Description) "
00845                          ."SELECT Callback, Parameters, Priority, Description"
00846                          ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00847         $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00848         $this->DB->Query("UNLOCK TABLES");
00849     }
00850 
00855     function DeleteOrphanedTask($TaskId)
00856     {
00857         $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
00858     }
00859 
00865     function MaxTasks($NewValue = NULL)
00866     {
00867         if (func_num_args() && ($NewValue >= 1))
00868         {
00869             $this->DB->Query("UPDATE ApplicationFrameworkSettings"
00870                     ." SET MaxTasksRunning = '".intval($NewValue)."'");
00871             $this->Settings["MaxTasksRunning"] = intval($NewValue);
00872         }
00873         return $this->Settings["MaxTasksRunning"];
00874     }
00875 
00883     function MaxExecutionTime($NewValue = NULL)
00884     {
00885         if (func_num_args())
00886         {
00887             if ($NewValue != $this->Settings["MaxExecTime"])
00888             {
00889                 $this->Settings["MaxExecTime"] = max($NewValue, 5);
00890                 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
00891                         ." SET MaxExecTime = '"
00892                                 .intval($this->Settings["MaxExecTime"])."'");
00893             }
00894             ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
00895             set_time_limit($this->Settings["MaxExecTime"]);
00896         }
00897         return ini_get("max_execution_time");
00898     }
00899 
00900     /*@)*/ /* Task Management */
00901 
00902     # ---- PRIVATE INTERFACE -------------------------------------------------
00903 
00904     private $JumpToPage = NULL;
00905     private $SuppressHTML = FALSE;
00906     private $DefaultPage = "Home";
00907     private $ActiveUI = "default";
00908     private $HtmlCharset = "UTF-8";
00909     private $PostProcessingFuncs = array();
00910     private $EnvIncludes = array();
00911     private $DB;
00912     private $Settings;
00913     private $ExecutionStartTime;
00914     private static $ObjectDirectories = array();
00915     private $MaxRunningTasksToTrack = 250;
00916     private $RunningTask;
00917 
00918     private $PeriodicEvents = array(
00919                 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
00920                 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
00921                 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
00922                 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
00923                 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
00924                 );
00925     private $UIEvents = array(
00926                 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
00927                 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
00928                 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
00929                 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
00930                 );
00931 
00932     private function FindTemplate($FileList, $PageName)
00933     {
00934         $FileNameFound = NULL;
00935         foreach ($FileList as $FileName)
00936         {
00937             $FileName = str_replace("%ACTIVEUI%", $this->ActiveUI, $FileName);
00938             $FileName = str_replace("%PAGENAME%", $PageName, $FileName);
00939             if (file_exists($FileName))
00940             {
00941                 $FileNameFound = $FileName;
00942                 break;
00943             }
00944         }
00945         return $FileNameFound;
00946     }
00947 
00948     private function SetUpObjectAutoloading()
00949     {
00950         function __autoload($ClassName)
00951         {
00952             ApplicationFramework::AutoloadObjects($ClassName);
00953         }
00954     }
00955 
00957     static function AutoloadObjects($ClassName)
00958     {
00959         foreach (self::$ObjectDirectories as $Location => $Prefix)
00960         {
00961             $FileName = $Location.$Prefix.$ClassName.".php";
00962             if (file_exists($FileName))
00963             {
00964                 require_once($FileName);
00965                 break;
00966             }
00967         }
00968     }
00971     private function LoadUIFunctions()
00972     {
00973         $Dirs = array(
00974                 "local/interface/%ACTIVEUI%/include",
00975                 "interface/%ACTIVEUI%/include",
00976                 "local/interface/default/include",
00977                 "interface/default/include",
00978                 );
00979         foreach ($Dirs as $Dir)
00980         {
00981             $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
00982             if (is_dir($Dir))
00983             {
00984                 $FileNames = scandir($Dir);
00985                 foreach ($FileNames as $FileName)
00986                 {
00987                     if (preg_match("/^F-([A-Za-z_]+)\.php/", $FileName, $Matches)
00988                             || preg_match("/^F-([A-Za-z_]+)\.html/", $FileName, $Matches))
00989                     {
00990                         if (!function_exists($Matches[1]))
00991                         {
00992                             include_once($Dir."/".$FileName);
00993                         }
00994                     }
00995                 }
00996             }
00997         }
00998     }
00999 
01000     private function ProcessPeriodicEvent($EventName, $Callback)
01001     {
01002         # retrieve last execution time for event if available
01003         $Signature = self::GetCallbackSignature($Callback);
01004         $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
01005                 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
01006 
01007         # determine whether enough time has passed for event to execute
01008         $EventPeriods = array(
01009                 "EVENT_HOURLY" => 60*60,
01010                 "EVENT_DAILY" => 60*60*24,
01011                 "EVENT_WEEKLY" => 60*60*24*7,
01012                 "EVENT_MONTHLY" => 60*60*24*30,
01013                 "EVENT_PERIODIC" => 0,
01014                 );
01015         $ShouldExecute = (($LastRun === NULL)
01016                 || (time() > (strtotime($LastRun) + $EventPeriods[$EventName])))
01017                 ? TRUE : FALSE;
01018 
01019         # if event should run
01020         if ($ShouldExecute)
01021         {
01022             # add event to task queue
01023             $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
01024             $WrapperParameters = array(
01025                     $EventName, $Callback, array("LastRunAt" => $LastRun));
01026             $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
01027         }
01028     }
01029 
01030     private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
01031     {
01032         static $DB;
01033         if (!isset($DB)) {  $DB = new Database();  }
01034 
01035         # run event
01036         $ReturnVal = call_user_func_array($Callback, $Parameters);
01037 
01038         # if event is already in database
01039         $Signature = self::GetCallbackSignature($Callback);
01040         if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
01041                 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
01042         {
01043             # update last run time for event
01044             $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
01045                     .(($EventName == "EVENT_PERIODIC")
01046                             ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01047                             : "NOW()")
01048                     ." WHERE Signature = '".addslashes($Signature)."'");
01049         }
01050         else
01051         {
01052             # add last run time for event to database
01053             $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
01054                     ."('".addslashes($Signature)."', "
01055                     .(($EventName == "EVENT_PERIODIC")
01056                             ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
01057                             : "NOW()").")");
01058         }
01059     }
01060 
01061     private static function GetCallbackSignature($Callback)
01062     {
01063         return !is_array($Callback) ? $Callback
01064                 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
01065                         ."::".$Callback[1];
01066     }
01067 
01068     private function PrepForTSR()
01069     {
01070         # if HTML has been output and it's time to launch another task
01071         # (only TSR if HTML has been output because otherwise browsers
01072         #       may misbehave after connection is closed)
01073         if (($this->JumpToPage || !$this->SuppressHTML)
01074                 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
01075                         + (ini_get("max_execution_time")
01076                                 / $this->Settings["MaxTasksRunning"]) + 5))
01077                 && $this->GetTaskQueueSize())
01078         {
01079             # begin buffering output for TSR
01080             ob_start();
01081 
01082             # let caller know it is time to launch another task
01083             return TRUE;
01084         }
01085         else
01086         {
01087             # let caller know it is not time to launch another task
01088             return FALSE;
01089         }
01090     }
01091 
01092     private function LaunchTSR()
01093     {
01094         # set needed headers and
01095         ignore_user_abort(TRUE);
01096         header("Connection: close");
01097         header("Content-Length: ".ob_get_length());
01098 
01099         # output buffered content
01100         ob_end_flush();
01101         flush();
01102 
01103         # write out any outstanding data and end HTTP session
01104         session_write_close();
01105 
01106         # if there is still a task in the queue
01107         if ($this->GetTaskQueueSize())
01108         {
01109             # turn on output buffering to (hopefully) record any crash output
01110             ob_start();
01111 
01112             # lock tables and grab last task run time to double check
01113             $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
01114             $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
01115             $this->Settings = $this->DB->FetchRow();
01116 
01117             # if still time to launch another task
01118             if (time() > (strtotime($this->Settings["LastTaskRunAt"])
01119                         + (ini_get("max_execution_time")
01120                                 / $this->Settings["MaxTasksRunning"]) + 5))
01121             {
01122                 # update the "last run" time and release tables
01123                 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
01124                         ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
01125                 $this->DB->Query("UNLOCK TABLES");
01126 
01127                 # run tasks while there is a task in the queue and enough time left
01128                 do
01129                 {
01130                     # run the next task
01131                     $this->RunNextTask();
01132                 }
01133                 while ($this->GetTaskQueueSize()
01134                         && ($this->GetSecondsBeforeTimeout() > 65));
01135             }
01136             else
01137             {
01138                 # release tables
01139                 $this->DB->Query("UNLOCK TABLES");
01140             }
01141         }
01142     }
01143 
01151     private function GetTaskList($DBQuery, $Count, $Offset)
01152     {
01153         $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
01154         $Tasks = array();
01155         while ($Row = $this->DB->FetchRow())
01156         {
01157             $Tasks[$Row["TaskId"]] = $Row;
01158             if ($Row["Callback"] ==
01159                     serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
01160             {
01161                 $WrappedCallback = unserialize($Row["Parameters"]);
01162                 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
01163                 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
01164             }
01165             else
01166             {
01167                 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
01168                 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
01169             }
01170         }
01171         return $Tasks;
01172     }
01173 
01177     private function RunNextTask()
01178     {
01179         # look for task at head of queue
01180         $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
01181         $Task = $this->DB->FetchRow();
01182 
01183         # if there was a task available
01184         if ($Task)
01185         {
01186             # move task from queue to running tasks list
01187             $this->DB->Query("INSERT INTO RunningTasks "
01188                              ."(TaskId,Callback,Parameters,Priority,Description) "
01189                              ."SELECT * FROM TaskQueue WHERE TaskId = "
01190                                     .intval($Task["TaskId"]));
01191             $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
01192                     .intval($Task["TaskId"]));
01193 
01194             # unpack stored task info
01195             $Callback = unserialize($Task["Callback"]);
01196             $Parameters = unserialize($Task["Parameters"]);
01197 
01198             # attempt to load task callback if not already available
01199             $this->LoadFunction($Callback);
01200 
01201             # run task
01202             $this->RunningTask = $Task;
01203             call_user_func_array($Callback, $Parameters);
01204             unset($this->RunningTask);
01205 
01206             # remove task from running tasks list
01207             $this->DB->Query("DELETE FROM RunningTasks"
01208                     ." WHERE TaskId = ".intval($Task["TaskId"]));
01209 
01210             # prune running tasks list if necessary
01211             $RunningTaskCount = $this->DB->Query(
01212                     "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
01213             if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
01214             {
01215                 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
01216                         ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
01217             }
01218         }
01219     }
01220 
01226     function OnCrash()
01227     {
01228         if (isset($this->RunningTask))
01229         {
01230             if (function_exists("error_get_last"))
01231             {
01232                 $CrashInfo["LastError"] = error_get_last();
01233             }
01234             if (ob_get_length() !== FALSE)
01235             {
01236                 $CrashInfo["OutputBuffer"] = ob_get_contents();
01237             }
01238             if (isset($CrashInfo))
01239             {
01240                 $DB = new Database();
01241                 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
01242                         .addslashes(serialize($CrashInfo))
01243                         ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
01244             }
01245         }
01246 
01247         print("\n");
01248         return;
01249 
01250         if (ob_get_length() !== FALSE)
01251         {
01252             ?>
01253             <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>
01254             <div style="font-size: 200%;">CRASH OUTPUT</div><?PHP
01255             ob_end_flush();
01256             ?></td></tr></table><?PHP
01257         }
01258     }
01259 
01260     private $CommonTemplateList = array(
01261             "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01262             "local/interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01263             "local/interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01264             "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01265             "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01266             "local/interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01267             "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01268             "local/interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01269             "local/interface/%ACTIVEUI%/include/%PAGENAME%",
01270             "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01271             "interface/%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01272             "interface/%ACTIVEUI%/include/%PAGENAME%.tpl",
01273             "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01274             "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01275             "interface/%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01276             "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01277             "interface/%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01278             "interface/%ACTIVEUI%/include/%PAGENAME%",
01279             "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01280             "SPTUI--%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01281             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.tpl",
01282             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01283             "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01284             "SPTUI--%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01285             "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01286             "SPTUI--%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01287             "SPTUI--%ACTIVEUI%/include/%PAGENAME%",
01288             "%ACTIVEUI%/include/StdPage%PAGENAME%.tpl",
01289             "%ACTIVEUI%/include/StdPage%PAGENAME%.html",
01290             "%ACTIVEUI%/include/%PAGENAME%.tpl",
01291             "%ACTIVEUI%/include/%PAGENAME%.html",
01292             "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.tpl",
01293             "%ACTIVEUI%/include/SPT--StandardPage%PAGENAME%.html",
01294             "%ACTIVEUI%/include/SPT--%PAGENAME%.tpl",
01295             "%ACTIVEUI%/include/SPT--%PAGENAME%.html",
01296             "%ACTIVEUI%/include/%PAGENAME%",
01297             "local/interface/default/include/StdPage%PAGENAME%.tpl",
01298             "local/interface/default/include/StdPage%PAGENAME%.html",
01299             "local/interface/default/include/%PAGENAME%.tpl",
01300             "local/interface/default/include/%PAGENAME%.html",
01301             "local/interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01302             "local/interface/default/include/SPT--StandardPage%PAGENAME%.html",
01303             "local/interface/default/include/SPT--%PAGENAME%.tpl",
01304             "local/interface/default/include/SPT--%PAGENAME%.html",
01305             "local/interface/default/include/%PAGENAME%",
01306             "interface/default/include/StdPage%PAGENAME%.tpl",
01307             "interface/default/include/StdPage%PAGENAME%.html",
01308             "interface/default/include/%PAGENAME%.tpl",
01309             "interface/default/include/%PAGENAME%.html",
01310             "interface/default/include/SPT--StandardPage%PAGENAME%.tpl",
01311             "interface/default/include/SPT--StandardPage%PAGENAME%.html",
01312             "interface/default/include/SPT--%PAGENAME%.tpl",
01313             "interface/default/include/SPT--%PAGENAME%.html",
01314             "interface/default/include/%PAGENAME%",
01315             );
01316     private $ContentTemplateList = array(
01317             "local/interface/%ACTIVEUI%/%PAGENAME%.tpl",
01318             "local/interface/%ACTIVEUI%/%PAGENAME%.html",
01319             "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01320             "local/interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01321             "interface/%ACTIVEUI%/%PAGENAME%.tpl",
01322             "interface/%ACTIVEUI%/%PAGENAME%.html",
01323             "interface/%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01324             "interface/%ACTIVEUI%/SPT--%PAGENAME%.html",
01325             "SPTUI--%ACTIVEUI%/%PAGENAME%.tpl",
01326             "SPTUI--%ACTIVEUI%/%PAGENAME%.html",
01327             "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01328             "SPTUI--%ACTIVEUI%/SPT--%PAGENAME%.html",
01329             "%ACTIVEUI%/%PAGENAME%.tpl",
01330             "%ACTIVEUI%/%PAGENAME%.html",
01331             "%ACTIVEUI%/SPT--%PAGENAME%.tpl",
01332             "%ACTIVEUI%/SPT--%PAGENAME%.html",
01333             "local/interface/default/%PAGENAME%.tpl",
01334             "local/interface/default/%PAGENAME%.html",
01335             "local/interface/default/SPT--%PAGENAME%.tpl",
01336             "local/interface/default/SPT--%PAGENAME%.html",
01337             "interface/default/%PAGENAME%.tpl",
01338             "interface/default/%PAGENAME%.html",
01339             "interface/default/SPT--%PAGENAME%.tpl",
01340             "interface/default/SPT--%PAGENAME%.html",
01341             );
01342     private $ImageFileList = array(
01343             "local/interface/%ACTIVEUI%/images/%PAGENAME%",
01344             "interface/%ACTIVEUI%/images/%PAGENAME%",
01345             "SPTUI--%ACTIVEUI%/images/%PAGENAME%",
01346             "%ACTIVEUI%/images/%PAGENAME%",
01347             "local/interface/default/images/%PAGENAME%",
01348             "interface/default/images/%PAGENAME%",
01349             );
01350     private $FunctionFileList = array(
01351             "local/interface/%ACTIVEUI%/include/%PAGENAME%.php",
01352             "local/interface/%ACTIVEUI%/include/%PAGENAME%.html",
01353             "interface/%ACTIVEUI%/include/%PAGENAME%.php",
01354             "interface/%ACTIVEUI%/include/%PAGENAME%.html",
01355             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.php",
01356             "SPTUI--%ACTIVEUI%/include/%PAGENAME%.html",
01357             "%ACTIVEUI%/include/%PAGENAME%.php",
01358             "%ACTIVEUI%/include/%PAGENAME%.html",
01359             "local/interface/default/include/%PAGENAME%.php",
01360             "local/interface/default/include/%PAGENAME%.html",
01361             "local/include/%PAGENAME%.php",
01362             "local/include/%PAGENAME%.html",
01363             "interface/default/include/%PAGENAME%.php",
01364             "interface/default/include/%PAGENAME%.html",
01365             "include/%PAGENAME%.php",
01366             "include/%PAGENAME%.html",
01367             );
01368 
01369     const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
01370 };
01371 
01372 
01373 ?>

CWIS logo doxygen
Copyright 2010 Internet Scout