CWIS Developer Documentation

- Home
- Main Page
- Classes
- Files

- File List
- File Members

ApplicationFramework.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: ApplicationFramework.php
4 #
5 # Part of the ScoutLib application support library
6 # Copyright 2009-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu
8 #
9
14 class ApplicationFramework {
15
16 # ---- PUBLIC INTERFACE --------------------------------------------------
17 /*@(*/
19
24 function __construct()
25 {
26 # save execution start time
27 $this->ExecutionStartTime = microtime(TRUE);
28
29 # begin/restore PHP session
30 $SessionDomain = isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"]
31 : isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"]
32 : php_uname("n");
33 if (is_writable(session_save_path()))
34 {
35 $SessionStorage = session_save_path()
36 ."/".self::$AppName."_".md5($SessionDomain.dirname(__FILE__));
37 if (!is_dir($SessionStorage)) { mkdir($SessionStorage, 0700 ); }
38 if (is_writable($SessionStorage)) { session_save_path($SessionStorage); }
39 }
40 ini_set("session.gc_maxlifetime", self::$SessionLifetime);
41 session_set_cookie_params(
42 self::$SessionLifetime, "/", $SessionDomain);
43 session_start();
44
45 # set up object file autoloader
46 $this->SetUpObjectAutoloading();
47
48 # set up function to output any buffered text in case of crash
49 register_shutdown_function(array($this, "OnCrash"));
50
51 # set up our internal environment
52 $this->DB = new Database();
53
54 # set up our exception handler
55 set_exception_handler(array($this, "GlobalExceptionHandler"));
56
57 # perform any work needed to undo PHP magic quotes
58 $this->UndoMagicQuotes();
59
60 # load our settings from database
61 $this->LoadSettings();
62
63 # set PHP maximum execution time
64 $this->MaxExecutionTime($this->Settings["MaxExecTime"]);
65
66 # register events we handle internally
67 $this->RegisterEvent($this->PeriodicEvents);
68 $this->RegisterEvent($this->UIEvents);
69 }
76 function __destruct()
77 {
78 # if template location cache is flagged to be saved
79 if ($this->SaveTemplateLocationCache)
80 {
81 # write template location cache out and update cache expiration
82 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
83 ." SET TemplateLocationCache = '"
84 .addslashes(serialize(
85 $this->Settings["TemplateLocationCache"]))."',"
86 ." TemplateLocationCacheExpiration = "
87 ." NOW() + INTERVAL "
88 .$this->Settings["TemplateLocationCacheInterval"]
89 ." MINUTE");
90 }
91 }
98 function GlobalExceptionHandler($Exception)
99 {
100 # display exception info
101 $Location = $Exception->getFile()."[".$Exception->getLine()."]";
102 ?><table width="100%" cellpadding="5"
103 style="border: 2px solid #666666; background: #CCCCCC;
104 font-family: Courier New, Courier, monospace;
105 margin-top: 10px;"><tr><td>
106 <div style="color: #666666;">
107 <span style="font-size: 150%;">
108 <b>Uncaught Exception</b></span><br />
109 <b>Message:</b> <i><?PHP print $Exception->getMessage(); ?></i><br />
110 <b>Location:</b> <i><?PHP print $Location; ?></i><br />
111 <b>Trace:</b>
112 <blockquote><pre><?PHP print $Exception->getTraceAsString();
113 ?></pre></blockquote>
114 </div>
115 </td></tr></table><?PHP
116
117 # log exception if possible
118 $LogMsg = "Uncaught exception (".$Exception->getMessage().").";
119 $this->LogError(self::LOGLVL_ERROR, $LogMsg);
120 }
134 static function AddObjectDirectory(
135 $Dir, $Prefix = "", $ClassPattern = NULL, $ClassReplacement = NULL)
136 {
137 # make sure directory has trailing slash
138 $Dir = $Dir.((substr($Dir, -1) != "/") ? "/" : "");
139
140 # add directory to directory list
141 self::$ObjectDirectories = array_merge(
142 array($Dir => array(
143 "Prefix" => $Prefix,
144 "ClassPattern" => $ClassPattern,
145 "ClassReplacement" => $ClassReplacement,
146 )),
147 self::$ObjectDirectories);
148 }
149
169 function AddImageDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
170 {
171 # add directories to existing image directory list
172 $this->ImageDirList = $this->AddToDirList(
173 $this->ImageDirList, $Dir, $SearchLast, $SkipSlashCheck);
174 }
175
196 function AddIncludeDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
197 {
198 # add directories to existing image directory list
199 $this->IncludeDirList = $this->AddToDirList(
200 $this->IncludeDirList, $Dir, $SearchLast, $SkipSlashCheck);
201 }
202
222 function AddInterfaceDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
223 {
224 # add directories to existing image directory list
225 $this->InterfaceDirList = $this->AddToDirList(
226 $this->InterfaceDirList, $Dir, $SearchLast, $SkipSlashCheck);
227 }
228
248 function AddFunctionDirectories($Dir, $SearchLast = FALSE, $SkipSlashCheck = FALSE)
249 {
250 # add directories to existing image directory list
251 $this->FunctionDirList = $this->AddToDirList(
252 $this->FunctionDirList, $Dir, $SearchLast, $SkipSlashCheck);
253 }
254
260 function SetBrowserDetectionFunc($DetectionFunc)
261 {
262 $this->BrowserDetectFunc = $DetectionFunc;
263 }
264
271 function AddUnbufferedCallback($Callback, $Parameters=array())
272 {
273 if (is_callable($Callback))
274 {
275 $this->UnbufferedCallbacks[] = array($Callback, $Parameters);
276 }
277 }
278
285 function TemplateLocationCacheExpirationInterval($NewInterval = -1)
286 {
287 if ($NewInterval >= 0)
288 {
289 $this->Settings["TemplateLocationCacheInterval"] = $NewInterval;
290 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
291 ." SET TemplateLocationCacheInterval = '"
292 .intval($NewInterval)."'");
293 }
294 return $this->Settings["TemplateLocationCacheInterval"];
295 }
296
302 static function SessionLifetime($NewValue = NULL)
303 {
304 if ($NewValue !== NULL)
305 {
306 self::$SessionLifetime = $NewValue;
307 }
308 return self::$SessionLifetime;
309 }
310
337 function AddCleanUrl($Pattern, $Page, $GetVars = NULL, $Template = NULL)
338 {
339 # save clean URL mapping parameters
340 $this->CleanUrlMappings[] = array(
341 "Pattern" => $Pattern,
342 "Page" => $Page,
343 "GetVars" => $GetVars,
344 );
345
346 # if replacement template specified
347 if ($Template !== NULL)
348 {
349 # if GET parameters specified
350 if (count($GetVars))
351 {
352 # retrieve all possible permutations of GET parameters
353 $GetPerms = $this->ArrayPermutations(array_keys($GetVars));
354
355 # for each permutation of GET parameters
356 foreach ($GetPerms as $VarPermutation)
357 {
358 # construct search pattern for permutation
359 $SearchPattern = "/href=([\"'])index\\.php\\?P=".$Page;
360 $GetVarSegment = "";
361 foreach ($VarPermutation as $GetVar)
362 {
363 if (preg_match("%\\\$[0-9]+%", $GetVars[$GetVar]))
364 {
365 $GetVarSegment .= "&amp;".$GetVar."=((?:(?!\\1)[^&])+)";
366 }
367 else
368 {
369 $GetVarSegment .= "&amp;".$GetVar."=".$GetVars[$GetVar];
370 }
371 }
372 $SearchPattern .= $GetVarSegment."\\1/i";
373
374 # if template is actually a callback
375 if (is_callable($Template))
376 {
377 # add pattern to HTML output mod callbacks list
378 $this->OutputModificationCallbacks[] = array(
379 "Pattern" => $Pattern,
380 "Page" => $Page,
381 "SearchPattern" => $SearchPattern,
382 "Callback" => $Template,
383 );
384 }
385 else
386 {
387 # construct replacement string for permutation
388 $Replacement = $Template;
389 $Index = 2;
390 foreach ($VarPermutation as $GetVar)
391 {
392 $Replacement = str_replace(
393 "\$".$GetVar, "\$".$Index, $Replacement);
394 $Index++;
395 }
396 $Replacement = "href=\"".$Replacement."\"";
397
398 # add pattern to HTML output modifications list
399 $this->OutputModificationPatterns[] = $SearchPattern;
400 $this->OutputModificationReplacements[] = $Replacement;
401 }
402 }
403 }
404 else
405 {
406 # construct search pattern
407 $SearchPattern = "/href=\"index\\.php\\?P=".$Page."\"/i";
408
409 # if template is actually a callback
410 if (is_callable($Template))
411 {
412 # add pattern to HTML output mod callbacks list
413 $this->OutputModificationCallbacks[] = array(
414 "Pattern" => $Pattern,
415 "Page" => $Page,
416 "SearchPattern" => $SearchPattern,
417 "Callback" => $Template,
418 );
419 }
420 else
421 {
422 # add simple pattern to HTML output modifications list
423 $this->OutputModificationPatterns[] = $SearchPattern;
424 $this->OutputModificationReplacements[] = "href=\"".$Template."\"";
425 }
426 }
427 }
428 }
429
435 function CleanUrlIsMapped($Path)
436 {
437 foreach ($this->CleanUrlMappings as $Info)
438 {
439 if (preg_match($Info["Pattern"], $Path))
440 {
441 return TRUE;
442 }
443 }
444 return FALSE;
445 }
446
453 function GetCleanUrlForPath($Path)
454 {
455 # the search patterns and callbacks require a specific format
456 $Format = "href=\"".str_replace("&", "&amp;", $Path)."\"";
457 $Search = $Format;
458
459 # perform any regular expression replacements on the search string
460 $Search = preg_replace(
461 $this->OutputModificationPatterns,
462 $this->OutputModificationReplacements,
463 $Search);
464
465 # only run the callbacks if a replacement hasn't already been performed
466 if ($Search == $Format)
467 {
468 # perform any callback replacements on the search string
469 foreach ($this->OutputModificationCallbacks as $Info)
470 {
471 # make the information available to the callback
472 $this->OutputModificationCallbackInfo = $Info;
473
474 # execute the callback
475 $Search = preg_replace_callback(
476 $Info["SearchPattern"],
477 array($this, "OutputModificationCallbackShell"),
478 $Search);
479 }
480 }
481
482 # return the path untouched if no replacements were performed
483 if ($Search == $Format)
484 {
485 return $Path;
486 }
487
488 # remove the bits added to the search string to get it recognized by
489 # the replacement expressions and callbacks
490 $Result = substr($Search, 6, -1);
491
492 return $Result;
493 }
494
501 public function GetUncleanUrlForPath($Path)
502 {
503 # for each clean URL mapping
504 foreach ($this->CleanUrlMappings as $Info)
505 {
506 # if current path matches the clean URL pattern
507 if (preg_match($Info["Pattern"], $Path, $Matches))
508 {
509 # the GET parameters for the URL, starting with the page name
510 $GetVars = array("P" => $Info["Page"]);
511
512 # if additional $_GET variables specified for clean URL
513 if ($Info["GetVars"] !== NULL)
514 {
515 # for each $_GET variable specified for clean URL
516 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
517 {
518 # start with template for variable value
519 $Value = $VarTemplate;
520
521 # for each subpattern matched in current URL
522 foreach ($Matches as $Index => $Match)
523 {
524 # if not first (whole) match
525 if ($Index > 0)
526 {
527 # make any substitutions in template
528 $Value = str_replace("$".$Index, $Match, $Value);
529 }
530 }
531
532 # add the GET variable
533 $GetVars[$VarName] = $Value;
534 }
535 }
536
537 # return the unclean URL
538 return "index.php?" . http_build_query($GetVars);
539 }
540 }
541
542 # return the path unchanged
543 return $Path;
544 }
545
551 function GetCleanUrl()
552 {
553 return $this->GetCleanUrlForPath($this->GetUncleanUrl());
554 }
555
560 function GetUncleanUrl()
561 {
562 $GetVars = array("P" => $this->GetPageName()) + $_GET;
563 return "index.php?" . http_build_query($GetVars);
564 }
565
570 function LoadPage($PageName)
571 {
572 # perform any clean URL rewriting
573 $PageName = $this->RewriteCleanUrls($PageName);
574
575 # sanitize incoming page name and save local copy
576 $PageName = preg_replace("/[^a-zA-Z0-9_.-]/", "", $PageName);
577 $this->PageName = $PageName;
578
579 # buffer any output from includes or PHP file
580 ob_start();
581
582 # include any files needed to set up execution environment
583 foreach ($this->EnvIncludes as $IncludeFile)
584 {
585 include($IncludeFile);
586 }
587
588 # signal page load
589 $this->SignalEvent("EVENT_PAGE_LOAD", array("PageName" => $PageName));
590
591 # signal PHP file load
592 $SignalResult = $this->SignalEvent("EVENT_PHP_FILE_LOAD", array(
593 "PageName" => $PageName));
594
595 # if signal handler returned new page name value
596 $NewPageName = $PageName;
597 if (($SignalResult["PageName"] != $PageName)
598 && strlen($SignalResult["PageName"]))
599 {
600 # if new page name value is page file
601 if (file_exists($SignalResult["PageName"]))
602 {
603 # use new value for PHP file name
604 $PageFile = $SignalResult["PageName"];
605 }
606 else
607 {
608 # use new value for page name
609 $NewPageName = $SignalResult["PageName"];
610 }
611
612 # update local copy of page name
613 $this->PageName = $NewPageName;
614 }
615
616 # if we do not already have a PHP file
617 if (!isset($PageFile))
618 {
619 # look for PHP file for page
620 $OurPageFile = "pages/".$NewPageName.".php";
621 $LocalPageFile = "local/pages/".$NewPageName.".php";
622 $PageFile = file_exists($LocalPageFile) ? $LocalPageFile
623 : (file_exists($OurPageFile) ? $OurPageFile
624 : "pages/".$this->DefaultPage.".php");
625 }
626
627 # load PHP file
628 include($PageFile);
629
630 # save buffered output to be displayed later after HTML file loads
631 $PageOutput = ob_get_contents();
632 ob_end_clean();
633
634 # signal PHP file load is complete
635 ob_start();
636 $Context["Variables"] = get_defined_vars();
637 $this->SignalEvent("EVENT_PHP_FILE_LOAD_COMPLETE",
638 array("PageName" => $PageName, "Context" => $Context));
639 $PageCompleteOutput = ob_get_contents();
640 ob_end_clean();
641
642 # set up for possible TSR (Terminate and Stay Resident :))
643 $ShouldTSR = $this->PrepForTSR();
644
645 # if PHP file indicated we should autorefresh to somewhere else
646 if ($this->JumpToPage)
647 {
648 if (!strlen(trim($PageOutput)))
649 {
650 ?><html>
651 <head>
652 <meta http-equiv="refresh" content="0; URL=<?PHP
653 print($this->JumpToPage); ?>">
654 </head>
655 <body bgcolor="white">
656 </body>
657 </html><?PHP
658 }
659 }
660 # else if HTML loading is not suppressed
661 elseif (!$this->SuppressHTML)
662 {
663 # set content-type to get rid of diacritic errors
664 header("Content-Type: text/html; charset="
665 .$this->HtmlCharset, TRUE);
666
667 # load common HTML file (defines common functions) if available
668 $CommonHtmlFile = $this->FindFile($this->IncludeDirList,
669 "Common", array("tpl", "html"));
670 if ($CommonHtmlFile) { include($CommonHtmlFile); }
671
672 # load UI functions
673 $this->LoadUIFunctions();
674
675 # begin buffering content
676 ob_start();
677
678 # signal HTML file load
679 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD", array(
680 "PageName" => $PageName));
681
682 # if signal handler returned new page name value
683 $NewPageName = $PageName;
684 $PageContentFile = NULL;
685 if (($SignalResult["PageName"] != $PageName)
686 && strlen($SignalResult["PageName"]))
687 {
688 # if new page name value is HTML file
689 if (file_exists($SignalResult["PageName"]))
690 {
691 # use new value for HTML file name
692 $PageContentFile = $SignalResult["PageName"];
693 }
694 else
695 {
696 # use new value for page name
697 $NewPageName = $SignalResult["PageName"];
698 }
699 }
700
701 # load page content HTML file if available
702 if ($PageContentFile === NULL)
703 {
704 $PageContentFile = $this->FindFile(
705 $this->InterfaceDirList, $NewPageName,
706 array("tpl", "html"));
707 }
708 if ($PageContentFile)
709 {
710 include($PageContentFile);
711 }
712 else
713 {
714 print "<h2>ERROR: No HTML/TPL template found"
715 ." for this page.</h2>";
716 }
717
718 # signal HTML file load complete
719 $SignalResult = $this->SignalEvent("EVENT_HTML_FILE_LOAD_COMPLETE");
720
721 # stop buffering and save output
722 $PageContentOutput = ob_get_contents();
723 ob_end_clean();
724
725 # load page start HTML file if available
726 ob_start();
727 $PageStartFile = $this->FindFile($this->IncludeDirList, "Start",
728 array("tpl", "html"), array("StdPage", "StandardPage"));
729 if ($PageStartFile) { include($PageStartFile); }
730 $PageStartOutput = ob_get_contents();
731 ob_end_clean();
732
733 # load page end HTML file if available
734 ob_start();
735 $PageEndFile = $this->FindFile($this->IncludeDirList, "End",
736 array("tpl", "html"), array("StdPage", "StandardPage"));
737 if ($PageEndFile) { include($PageEndFile); }
738 $PageEndOutput = ob_get_contents();
739 ob_end_clean();
740
741 # get list of any required files not loaded
742 $RequiredFiles = $this->GetRequiredFilesNotYetLoaded($PageContentFile);
743
744 # if a browser detection function has been made available
745 if (is_callable($this->BrowserDetectFunc))
746 {
747 # call function to get browser list
748 $Browsers = call_user_func($this->BrowserDetectFunc);
749
750 # for each required file
751 $NewRequiredFiles = array();
752 foreach ($RequiredFiles as $File)
753 {
754 # if file name includes browser keyword
755 if (preg_match("/%BROWSER%/", $File))
756 {
757 # for each browser
758 foreach ($Browsers as $Browser)
759 {
760 # substitute in browser name and add to new file list
761 $NewRequiredFiles[] = preg_replace(
762 "/%BROWSER%/", $Browser, $File);
763 }
764 }
765 else
766 {
767 # add to new file list
768 $NewRequiredFiles[] = $File;
769 }
770 }
771 $RequiredFiles = $NewRequiredFiles;
772 }
773
774 # for each required file
775 foreach ($RequiredFiles as $File)
776 {
777 # locate specific file to use
778 $FilePath = $this->GUIFile($File);
779
780 # if file was found
781 if ($FilePath)
782 {
783 # determine file type
784 $NamePieces = explode(".", $File);
785 $FileSuffix = strtolower(array_pop($NamePieces));
786
787 # add file to HTML output based on file type
788 $FilePath = htmlspecialchars($FilePath);
789 switch ($FileSuffix)
790 {
791 case "js":
792 $Tag = '<script type="text/javascript" src="'
793 .$FilePath.'"></script>';
794 $PageEndOutput = preg_replace(
795 "#</body>#i", $Tag."\n</body>", $PageEndOutput, 1);
796 break;
797
798 case "css":
799 $Tag = '<link rel="stylesheet" type="text/css"'
800 .' media="all" href="'.$FilePath.'">';
801 $PageStartOutput = preg_replace(
802 "#</head>#i", $Tag."\n</head>", $PageStartOutput, 1);
803 break;
804 }
805 }
806 }
807
808 # assemble full page
809 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
810
811 # perform any regular expression replacements in output
812 $FullPageOutput = preg_replace($this->OutputModificationPatterns,
813 $this->OutputModificationReplacements, $FullPageOutput);
814
815 # perform any callback replacements in output
816 foreach ($this->OutputModificationCallbacks as $Info)
817 {
818 $this->OutputModificationCallbackInfo = $Info;
819 $FullPageOutput = preg_replace_callback($Info["SearchPattern"],
820 array($this, "OutputModificationCallbackShell"),
821 $FullPageOutput);
822 }
823
824 # if relative paths may not work because we were invoked via clean URL
825 if ($this->CleanUrlRewritePerformed || self::WasUrlRewritten())
826 {
827 # if using the <base> tag is okay
828 $BaseUrl = $this->BaseUrl();
829 if ($this->UseBaseTag)
830 {
831 # add <base> tag to header
832 $PageStartOutput = preg_replace("%<head>%",
833 "<head><base href=\"".$BaseUrl."\" />",
834 $PageStartOutput);
835
836 # re-assemble full page with new header
837 $FullPageOutput = $PageStartOutput.$PageContentOutput.$PageEndOutput;
838
839 # the absolute URL to the current page
840 $FullUrl = $BaseUrl . $this->GetPageLocation();
841
842 # make HREF attribute values with just a fragment ID
843 # absolute since they don't work with the <base> tag because
844 # they are relative to the current page/URL, not the site
845 # root
846 $FullPageOutput = preg_replace(
847 array("%href=\"(#[^:\" ]+)\"%i", "%href='(#[^:' ]+)'%i"),
848 array("href=\"".$FullUrl."$1\"", "href='".$FullUrl."$1'"),
849 $FullPageOutput);
850 }
851 else
852 {
853 # try to fix any relative paths throughout code
854 $FullPageOutput = preg_replace(array(
855 "%src=\"([^?*:;{}\\\\\" ]+)\.(js|css|gif|png|jpg)\"%i",
856 "%src='([^?*:;{}\\\\' ]+)\.(js|css|gif|png|jpg)'%i",
857 # don't rewrite HREF attributes that are just
858 # fragment IDs because they are relative to the
859 # current page/URL, not the site root
860 "%href=\"([^#][^:\" ]*)\"%i",
861 "%href='([^#][^:' ]*)'%i",
862 "%action=\"([^#][^:\" ]*)\"%i",
863 "%action='([^#][^:' ]*)'%i",
864 "%@import\s+url\(\"([^:\" ]+)\"\s*\)%i",
865 "%@import\s+url\('([^:\" ]+)'\s*\)%i",
866 "%@import\s+\"([^:\" ]+)\"\s*%i",
867 "%@import\s+'([^:\" ]+)'\s*%i",
868 ),
869 array(
870 "src=\"".$BaseUrl."$1.$2\"",
871 "src=\"".$BaseUrl."$1.$2\"",
872 "href=\"".$BaseUrl."$1\"",
873 "href=\"".$BaseUrl."$1\"",
874 "action=\"".$BaseUrl."$1\"",
875 "action=\"".$BaseUrl."$1\"",
876 "@import url(\"".$BaseUrl."$1\")",
877 "@import url('".$BaseUrl."$1')",
878 "@import \"".$BaseUrl."$1\"",
879 "@import '".$BaseUrl."$1'",
880 ),
881 $FullPageOutput);
882 }
883 }
884
885 # provide the opportunity to modify full page output
886 $SignalResult = $this->SignalEvent("EVENT_PAGE_OUTPUT_FILTER", array(
887 "PageOutput" => $FullPageOutput));
888 if (isset($SignalResult["PageOutput"])
889 && strlen($SignalResult["PageOutput"]))
890 {
891 $FullPageOutput = $SignalResult["PageOutput"];
892 }
893
894 # write out full page
895 print $FullPageOutput;
896 }
897
898 # run any post-processing routines
899 foreach ($this->PostProcessingFuncs as $Func)
900 {
901 call_user_func_array($Func["FunctionName"], $Func["Arguments"]);
902 }
903
904 # write out any output buffered from page code execution
905 if (strlen($PageOutput))
906 {
907 if (!$this->SuppressHTML)
908 {
909 ?><table width="100%" cellpadding="5"
910 style="border: 2px solid #666666; background: #CCCCCC;
911 font-family: Courier New, Courier, monospace;
912 margin-top: 10px;"><tr><td><?PHP
913 }
914 if ($this->JumpToPage)
915 {
916 ?><div style="color: #666666;"><span style="font-size: 150%;">
917 <b>Page Jump Aborted</b></span>
918 (because of error or other unexpected output)<br />
919 <b>Jump Target:</b>
920 <i><?PHP print($this->JumpToPage); ?></i></div><?PHP
921 }
922 print $PageOutput;
923 if (!$this->SuppressHTML)
924 {
925 ?></td></tr></table><?PHP
926 }
927 }
928
929 # write out any output buffered from the page code execution complete signal
930 if (!$this->JumpToPage && !$this->SuppressHTML && strlen($PageCompleteOutput))
931 {
932 print $PageCompleteOutput;
933 }
934
935 # execute callbacks that should not have their output buffered
936 foreach ($this->UnbufferedCallbacks as $Callback)
937 {
938 call_user_func_array($Callback[0], $Callback[1]);
939 }
940
941 # terminate and stay resident (TSR!) if indicated and HTML has been output
942 # (only TSR if HTML has been output because otherwise browsers will misbehave)
943 if ($ShouldTSR) { $this->LaunchTSR(); }
944 }
945
951 function GetPageName()
952 {
953 return $this->PageName;
954 }
955
961 function GetPageLocation()
962 {
963 # retrieve current URL
964 $Url = $this->GetScriptUrl();
965
966 # remove the base path if present
967 $BasePath = $this->Settings["BasePath"];
968 if (stripos($Url, $BasePath) === 0)
969 {
970 $Url = substr($Url, strlen($BasePath));
971 }
972
973 return $Url;
974 }
975
980 function GetPageUrl()
981 {
982 return self::BaseUrl() . $this->GetPageLocation();
983 }
984
993 function SetJumpToPage($Page, $IsLiteral = FALSE)
994 {
995 if (!is_null($Page)
996 && (!$IsLiteral)
997 && (strpos($Page, "?") === FALSE)
998 && ((strpos($Page, "=") !== FALSE)
999 || ((stripos($Page, ".php") === FALSE)
1000 && (stripos($Page, ".htm") === FALSE)
1001 && (strpos($Page, "/") === FALSE)))
1002 && (stripos($Page, "http://") !== 0)
1003 && (stripos($Page, "https://") !== 0))
1004 {
1005 $this->JumpToPage = self::BaseUrl() . "index.php?P=".$Page;
1006 }
1007 else
1008 {
1009 $this->JumpToPage = $Page;
1010 }
1011 }
1012
1017 function JumpToPageIsSet()
1018 {
1019 return ($this->JumpToPage === NULL) ? FALSE : TRUE;
1020 }
1021
1031 function HtmlCharset($NewSetting = NULL)
1032 {
1033 if ($NewSetting !== NULL) { $this->HtmlCharset = $NewSetting; }
1034 return $this->HtmlCharset;
1035 }
1036
1043 public function UseMinimizedJavascript($NewSetting = NULL)
1044 {
1045 if ($NewSetting !== NULL) { $this->UseMinimizedJavascript = $NewSetting; }
1046 return $this->UseMinimizedJavascript;
1047 }
1048
1059 function UseBaseTag($NewValue = NULL)
1060 {
1061 if ($NewValue !== NULL) { $this->UseBaseTag = $NewValue ? TRUE : FALSE; }
1062 return $this->UseBaseTag;
1063 }
1064
1071 function SuppressHTMLOutput($NewSetting = TRUE)
1072 {
1073 $this->SuppressHTML = $NewSetting;
1074 }
1075
1082 function ActiveUserInterface($UIName = NULL)
1083 {
1084 if ($UIName !== NULL)
1085 {
1086 $this->ActiveUI = preg_replace("/^SPTUI--/", "", $UIName);
1087 }
1088 return $this->ActiveUI;
1089 }
1090
1096 function GetUserInterfaces()
1097 {
1098 # possible UI directories
1099 $InterfaceDirs = array(
1100 "interface",
1101 "local/interface");
1102
1103 # start out with an empty list
1104 $Interfaces = array();
1105
1106 # for each possible UI directory
1107 foreach ($InterfaceDirs as $InterfaceDir)
1108 {
1109 $Dir = dir($InterfaceDir);
1110
1111 # for each file in current directory
1112 while (($DirEntry = $Dir->read()) !== FALSE)
1113 {
1114 $InterfacePath = $InterfaceDir."/".$DirEntry;
1115
1116 # skip anything that doesn't have a name in the required format
1117 if (!preg_match('/^[a-zA-Z]+$/', $DirEntry))
1118 {
1119 continue;
1120 }
1121
1122 # skip anything that isn't a directory
1123 if (!is_dir($InterfacePath))
1124 {
1125 continue;
1126 }
1127
1128 # read the UI name (if available)
1129 $UIName = @file_get_contents($InterfacePath."/NAME");
1130
1131 # use the directory name if the UI name isn't available
1132 if ($UIName === FALSE || !strlen($UIName))
1133 {
1134 $UIName = $DirEntry;
1135 }
1136
1137 $Interfaces[$InterfacePath] = $UIName;
1138 }
1139
1140 $Dir->close();
1141 }
1142
1143 # return list to caller
1144 return $Interfaces;
1145 }
1146
1162 function AddPostProcessingCall($FunctionName,
1163 &$Arg1 = self::NOVALUE, &$Arg2 = self::NOVALUE, &$Arg3 = self::NOVALUE,
1164 &$Arg4 = self::NOVALUE, &$Arg5 = self::NOVALUE, &$Arg6 = self::NOVALUE,
1165 &$Arg7 = self::NOVALUE, &$Arg8 = self::NOVALUE, &$Arg9 = self::NOVALUE)
1166 {
1167 $FuncIndex = count($this->PostProcessingFuncs);
1168 $this->PostProcessingFuncs[$FuncIndex]["FunctionName"] = $FunctionName;
1169 $this->PostProcessingFuncs[$FuncIndex]["Arguments"] = array();
1170 $Index = 1;
1171 while (isset(${"Arg".$Index}) && (${"Arg".$Index} !== self::NOVALUE))
1172 {
1173 $this->PostProcessingFuncs[$FuncIndex]["Arguments"][$Index]
1174 =& ${"Arg".$Index};
1175 $Index++;
1176 }
1177 }
1178
1184 function AddEnvInclude($FileName)
1185 {
1186 $this->EnvIncludes[] = $FileName;
1187 }
1188
1195 function GUIFile($FileName)
1196 {
1197 # determine if the file is an image or JavaScript file
1198 $FileIsImage = preg_match("/\.(gif|jpg|png)$/", $FileName);
1199 $FileIsJavascript = preg_match("/\.js$/", $FileName);
1200
1201 # determine which location to search based on file suffix
1202 $DirList = $FileIsImage ? $this->ImageDirList : $this->IncludeDirList;
1203
1204 # if directed to get a minimized JavaScript file
1205 if ($FileIsJavascript && $this->UseMinimizedJavascript)
1206 {
1207 # first try to find the minimized JavaScript file
1208 $MinimizedFileName = substr_replace($FileName, ".min", -3, 0);
1209 $FoundFileName = $this->FindFile($DirList, $MinimizedFileName);
1210
1211 # search for the regular file if a minimized file wasn't found
1212 if (is_null($FoundFileName))
1213 {
1214 $FoundFileName = $this->FindFile($DirList, $FileName);
1215 }
1216 }
1217
1218 # otherwise just search for the file
1219 else
1220 {
1221 $FoundFileName = $this->FindFile($DirList, $FileName);
1222 }
1223
1224 # add non-image files to list of found files (used for required files loading)
1225 if (!$FileIsImage) { $this->FoundUIFiles[] = basename($FoundFileName); }
1226
1227 # return file name to caller
1228 return $FoundFileName;
1229 }
1230
1240 function PUIFile($FileName)
1241 {
1242 $FullFileName = $this->GUIFile($FileName);
1243 if ($FullFileName) { print($FullFileName); }
1244 }
1245
1253 function RequireUIFile($FileName)
1254 {
1255 $this->AdditionalRequiredUIFiles[] = $FileName;
1256 }
1257
1266 function LoadFunction($Callback)
1267 {
1268 # if specified function is not currently available
1269 if (!is_callable($Callback))
1270 {
1271 # if function info looks legal
1272 if (is_string($Callback) && strlen($Callback))
1273 {
1274 # start with function directory list
1275 $Locations = $this->FunctionDirList;
1276
1277 # add object directories to list
1278 $Locations = array_merge(
1279 $Locations, array_keys(self::$ObjectDirectories));
1280
1281 # look for function file
1282 $FunctionFileName = $this->FindFile($Locations, "F-".$Callback,
1283 array("php", "html"));
1284
1285 # if function file was found
1286 if ($FunctionFileName)
1287 {
1288 # load function file
1289 include_once($FunctionFileName);
1290 }
1291 else
1292 {
1293 # log error indicating function load failed
1294 $this->LogError(self::LOGLVL_ERROR, "Unable to load function"
1295 ." for callback \"".$Callback."\".");
1296 }
1297 }
1298 else
1299 {
1300 # log error indicating specified function info was bad
1301 $this->LogError(self::LOGLVL_ERROR, "Unloadable callback value"
1302 ." (".$Callback.")"
1303 ." passed to AF::LoadFunction().");
1304 }
1305 }
1306
1307 # report to caller whether function load succeeded
1308 return is_callable($Callback);
1309 }
1310
1315 function GetElapsedExecutionTime()
1316 {
1317 return microtime(TRUE) - $this->ExecutionStartTime;
1318 }
1319
1324 function GetSecondsBeforeTimeout()
1325 {
1326 return ini_get("max_execution_time") - $this->GetElapsedExecutionTime();
1327 }
1328
1334 function GetFreeMemory()
1335 {
1336 $Str = strtoupper(ini_get("memory_limit"));
1337 if (substr($Str, -1) == "B") { $Str = substr($Str, 0, strlen($Str) - 1); }
1338 switch (substr($Str, -1))
1339 {
1340 case "K": $MemoryLimit = (int)$Str * 1024; break;
1341 case "M": $MemoryLimit = (int)$Str * 1048576; break;
1342 case "G": $MemoryLimit = (int)$Str * 1073741824; break;
1343 default: $MemoryLimit = (int)$Str; break;
1344 }
1345
1346 return $MemoryLimit - memory_get_usage();
1347 }
1348
1353 function HtaccessSupport()
1354 {
1355 # HTACCESS_SUPPORT is set in the .htaccess file
1356 return isset($_SERVER["HTACCESS_SUPPORT"]);
1357 }
1358
1363 static function BaseUrl()
1364 {
1365 $Protocol = (isset($_SERVER["HTTPS"]) ? "https" : "http");
1366 $BaseUrl = $Protocol."://"
1367 .(($_SERVER["SERVER_NAME"] != "127.0.0.1")
1368 ? $_SERVER["SERVER_NAME"]
1369 : $_SERVER["HTTP_HOST"])
1370 .dirname($_SERVER["SCRIPT_NAME"]);
1371 if (substr($BaseUrl, -1) != "/") { $BaseUrl .= "/"; }
1372 return $BaseUrl;
1373 }
1374
1379 static function BasePath()
1380 {
1381 $BasePath = dirname($_SERVER["SCRIPT_NAME"]);
1382
1383 if (substr($BasePath, -1) != "/")
1384 {
1385 $BasePath .= "/";
1386 }
1387
1388 return $BasePath;
1389 }
1390
1396 static function GetScriptUrl()
1397 {
1398 if (array_key_exists("SCRIPT_URL", $_SERVER))
1399 {
1400 return $_SERVER["SCRIPT_URL"];
1401 }
1402 elseif (array_key_exists("REDIRECT_URL", $_SERVER))
1403 {
1404 return $_SERVER["REDIRECT_URL"];
1405 }
1406 elseif (array_key_exists("REQUEST_URI", $_SERVER))
1407 {
1408 $Pieces = parse_url($_SERVER["REQUEST_URI"]);
1409 return $Pieces["path"];
1410 }
1411 else
1412 {
1413 return NULL;
1414 }
1415 }
1416
1425 static function WasUrlRewritten($ScriptName="index.php")
1426 {
1427 # needed to get the path of the URL minus the query and fragment pieces
1428 $Components = parse_url(self::GetScriptUrl());
1429
1430 # if parsing was successful and a path is set
1431 if (is_array($Components) && isset($Components["path"]))
1432 {
1433 $BasePath = self::BasePath();
1434 $Path = $Components["path"];
1435
1436 # the URL was rewritten if the path isn't the base path, i.e., the
1437 # home page, and the file in the URL isn't the script generating the
1438 # page
1439 if ($BasePath != $Path && basename($Path) != $ScriptName)
1440 {
1441 return TRUE;
1442 }
1443 }
1444
1445 # the URL wasn't rewritten
1446 return FALSE;
1447 }
1448
1462 function LogError($Level, $Msg)
1463 {
1464 # if error level is at or below current logging level
1465 if ($this->Settings["LoggingLevel"] >= $Level)
1466 {
1467 # attempt to log error message
1468 $Result = $this->LogMessage($Level, $Msg);
1469
1470 # if logging attempt failed and level indicated significant error
1471 if (($Result === FALSE) && ($Level <= self::LOGLVL_ERROR))
1472 {
1473 # throw exception about inability to log error
1474 static $AlreadyThrewException = FALSE;
1475 if (!$AlreadyThrewException)
1476 {
1477 $AlreadyThrewException = TRUE;
1478 throw new Exception("Unable to log error (".$Level.": ".$Msg.").");
1479 }
1480 }
1481
1482 # report to caller whether message was logged
1483 return $Result;
1484 }
1485 else
1486 {
1487 # report to caller that message was not logged
1488 return FALSE;
1489 }
1490 }
1491
1503 function LogMessage($Level, $Msg)
1504 {
1505 # if message level is at or below current logging level
1506 if ($this->Settings["LoggingLevel"] >= $Level)
1507 {
1508 # attempt to open log file
1509 $FHndl = @fopen($this->LogFileName, "a");
1510
1511 # if log file could not be open
1512 if ($FHndl === FALSE)
1513 {
1514 # report to caller that message was not logged
1515 return FALSE;
1516 }
1517 else
1518 {
1519 # format log entry
1520 $ErrorAbbrevs = array(
1521 self::LOGLVL_FATAL => "FTL",
1522 self::LOGLVL_ERROR => "ERR",
1523 self::LOGLVL_WARNING => "WRN",
1524 self::LOGLVL_INFO => "INF",
1525 self::LOGLVL_DEBUG => "DBG",
1526 self::LOGLVL_TRACE => "TRC",
1527 );
1528 $LogEntry = date("Y-m-d H:i:s")
1529 ." ".($this->RunningInBackground ? "B" : "F")
1530 ." ".$ErrorAbbrevs[$Level]
1531 ." ".$Msg;
1532
1533 # write entry to log
1534 $Success = fputs($FHndl, $LogEntry."\n");
1535
1536 # close log file
1537 fclose($FHndl);
1538
1539 # report to caller whether message was logged
1540 return ($Success === FALSE) ? FALSE : TRUE;
1541 }
1542 }
1543 else
1544 {
1545 # report to caller that message was not logged
1546 return FALSE;
1547 }
1548 }
1549
1571 function LoggingLevel($NewValue = NULL)
1572 {
1573 # if new logging level was specified
1574 if ($NewValue !== NULL)
1575 {
1576 # constrain new level to within legal bounds and store locally
1577 $this->Settings["LoggingLevel"] = max(min($NewValue, 6), 1);
1578
1579 # save new logging level in database
1580 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
1581 ." SET LoggingLevel = "
1582 .intval($this->Settings["LoggingLevel"]));
1583 }
1584
1585 # report current logging level to caller
1586 return $this->Settings["LoggingLevel"];
1587 }
1588
1595 function LogFile($NewValue = NULL)
1596 {
1597 if ($NewValue !== NULL) { $this->LogFileName = $NewValue; }
1598 return $this->LogFileName;
1599 }
1600
1605 const LOGLVL_TRACE = 6;
1610 const LOGLVL_DEBUG = 5;
1616 const LOGLVL_INFO = 4;
1621 const LOGLVL_WARNING = 3;
1627 const LOGLVL_ERROR = 2;
1632 const LOGLVL_FATAL = 1;
1633
1634 /*@)*/ /* Application Framework */
1635
1636 # ---- Event Handling ----------------------------------------------------
1637 /*@(*/
1639
1643 const EVENTTYPE_DEFAULT = 1;
1649 const EVENTTYPE_CHAIN = 2;
1655 const EVENTTYPE_FIRST = 3;
1663 const EVENTTYPE_NAMED = 4;
1664
1666 const ORDER_FIRST = 1;
1668 const ORDER_MIDDLE = 2;
1670 const ORDER_LAST = 3;
1671
1680 function RegisterEvent($EventsOrEventName, $EventType = NULL)
1681 {
1682 # convert parameters to array if not already in that form
1683 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1684 : array($EventsOrEventName => $Type);
1685
1686 # for each event
1687 foreach ($Events as $Name => $Type)
1688 {
1689 # store event information
1690 $this->RegisteredEvents[$Name]["Type"] = $Type;
1691 $this->RegisteredEvents[$Name]["Hooks"] = array();
1692 }
1693 }
1694
1701 function IsRegisteredEvent($EventName)
1702 {
1703 return array_key_exists($EventName, $this->RegisteredEvents)
1704 ? TRUE : FALSE;
1705 }
1706
1713 function IsHookedEvent($EventName)
1714 {
1715 # the event isn't hooked to if it isn't even registered
1716 if (!$this->IsRegisteredEvent($EventName))
1717 {
1718 return FALSE;
1719 }
1720
1721 # return TRUE if there is at least one callback hooked to the event
1722 return count($this->RegisteredEvents[$EventName]["Hooks"]) > 0;
1723 }
1724
1738 function HookEvent($EventsOrEventName, $Callback = NULL, $Order = self::ORDER_MIDDLE)
1739 {
1740 # convert parameters to array if not already in that form
1741 $Events = is_array($EventsOrEventName) ? $EventsOrEventName
1742 : array($EventsOrEventName => $Callback);
1743
1744 # for each event
1745 $Success = TRUE;
1746 foreach ($Events as $EventName => $EventCallback)
1747 {
1748 # if callback is valid
1749 if (is_callable($EventCallback))
1750 {
1751 # if this is a periodic event we process internally
1752 if (isset($this->PeriodicEvents[$EventName]))
1753 {
1754 # process event now
1755 $this->ProcessPeriodicEvent($EventName, $EventCallback);
1756 }
1757 # if specified event has been registered
1758 elseif (isset($this->RegisteredEvents[$EventName]))
1759 {
1760 # add callback for event
1761 $this->RegisteredEvents[$EventName]["Hooks"][]
1762 = array("Callback" => $EventCallback, "Order" => $Order);
1763
1764 # sort callbacks by order
1765 if (count($this->RegisteredEvents[$EventName]["Hooks"]) > 1)
1766 {
1767 usort($this->RegisteredEvents[$EventName]["Hooks"],
1768 array("ApplicationFramework", "HookEvent_OrderCompare"));
1769 }
1770 }
1771 else
1772 {
1773 $Success = FALSE;
1774 }
1775 }
1776 else
1777 {
1778 $Success = FALSE;
1779 }
1780 }
1781
1782 # report to caller whether all callbacks were hooked
1783 return $Success;
1784 }
1786 private static function HookEvent_OrderCompare($A, $B)
1787 {
1788 if ($A["Order"] == $B["Order"]) { return 0; }
1789 return ($A["Order"] < $B["Order"]) ? -1 : 1;
1790 }
1791
1800 function SignalEvent($EventName, $Parameters = NULL)
1801 {
1802 $ReturnValue = NULL;
1803
1804 # if event has been registered
1805 if (isset($this->RegisteredEvents[$EventName]))
1806 {
1807 # set up default return value (if not NULL)
1808 switch ($this->RegisteredEvents[$EventName]["Type"])
1809 {
1810 case self::EVENTTYPE_CHAIN:
1811 $ReturnValue = $Parameters;
1812 break;
1813
1814 case self::EVENTTYPE_NAMED:
1815 $ReturnValue = array();
1816 break;
1817 }
1818
1819 # for each callback for this event
1820 foreach ($this->RegisteredEvents[$EventName]["Hooks"] as $Hook)
1821 {
1822 # invoke callback
1823 $Callback = $Hook["Callback"];
1824 $Result = ($Parameters !== NULL)
1825 ? call_user_func_array($Callback, $Parameters)
1826 : call_user_func($Callback);
1827
1828 # process return value based on event type
1829 switch ($this->RegisteredEvents[$EventName]["Type"])
1830 {
1831 case self::EVENTTYPE_CHAIN:
1832 if ($Result !== NULL)
1833 {
1834 foreach ($Parameters as $Index => $Value)
1835 {
1836 if (array_key_exists($Index, $Result))
1837 {
1838 $Parameters[$Index] = $Result[$Index];
1839 }
1840 }
1841 $ReturnValue = $Parameters;
1842 }
1843 break;
1844
1845 case self::EVENTTYPE_FIRST:
1846 if ($Result !== NULL)
1847 {
1848 $ReturnValue = $Result;
1849 break 2;
1850 }
1851 break;
1852
1853 case self::EVENTTYPE_NAMED:
1854 $CallbackName = is_array($Callback)
1855 ? (is_object($Callback[0])
1856 ? get_class($Callback[0])
1857 : $Callback[0])."::".$Callback[1]
1858 : $Callback;
1859 $ReturnValue[$CallbackName] = $Result;
1860 break;
1861
1862 default:
1863 break;
1864 }
1865 }
1866 }
1867 else
1868 {
1869 $this->LogError(self::LOGLVL_WARNING,
1870 "Unregistered event signaled (".$EventName.").");
1871 }
1872
1873 # return value if any to caller
1874 return $ReturnValue;
1875 }
1876
1882 function IsStaticOnlyEvent($EventName)
1883 {
1884 return isset($this->PeriodicEvents[$EventName]) ? TRUE : FALSE;
1885 }
1886
1897 function EventWillNextRunAt($EventName, $Callback)
1898 {
1899 # if event is not a periodic event report failure to caller
1900 if (!array_key_exists($EventName, $this->EventPeriods)) { return FALSE; }
1901
1902 # retrieve last execution time for event if available
1903 $Signature = self::GetCallbackSignature($Callback);
1904 $LastRunTime = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
1905 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
1906
1907 # if event was not found report failure to caller
1908 if ($LastRunTime === NULL) { return FALSE; }
1909
1910 # calculate next run time based on event period
1911 $NextRunTime = strtotime($LastRunTime) + $this->EventPeriods[$EventName];
1912
1913 # report next run time to caller
1914 return $NextRunTime;
1915 }
1916
1932 function GetKnownPeriodicEvents()
1933 {
1934 # retrieve last execution times
1935 $this->DB->Query("SELECT * FROM PeriodicEvents");
1936 $LastRunTimes = $this->DB->FetchColumn("LastRunAt", "Signature");
1937
1938 # for each known event
1939 $Events = array();
1940 foreach ($this->KnownPeriodicEvents as $Signature => $Info)
1941 {
1942 # if last run time for event is available
1943 if (array_key_exists($Signature, $LastRunTimes))
1944 {
1945 # calculate next run time for event
1946 $LastRun = strtotime($LastRunTimes[$Signature]);
1947 $NextRun = $LastRun + $this->EventPeriods[$Info["Period"]];
1948 if ($Info["Period"] == "EVENT_PERIODIC") { $LastRun = FALSE; }
1949 }
1950 else
1951 {
1952 # set info to indicate run times are not known
1953 $LastRun = FALSE;
1954 $NextRun = FALSE;
1955 }
1956
1957 # add event info to list
1958 $Events[$Signature] = $Info;
1959 $Events[$Signature]["LastRun"] = $LastRun;
1960 $Events[$Signature]["NextRun"] = $NextRun;
1961 $Events[$Signature]["Parameters"] = NULL;
1962 }
1963
1964 # return list of known events to caller
1965 return $Events;
1966 }
1967
1968 /*@)*/ /* Event Handling */
1969
1970 # ---- Task Management ---------------------------------------------------
1971 /*@(*/
1973
1975 const PRIORITY_HIGH = 1;
1977 const PRIORITY_MEDIUM = 2;
1979 const PRIORITY_LOW = 3;
1981 const PRIORITY_BACKGROUND = 4;
1982
1995 function QueueTask($Callback, $Parameters = NULL,
1996 $Priority = self::PRIORITY_LOW, $Description = "")
1997 {
1998 # pack task info and write to database
1999 if ($Parameters === NULL) { $Parameters = array(); }
2000 $this->DB->Query("INSERT INTO TaskQueue"
2001 ." (Callback, Parameters, Priority, Description)"
2002 ." VALUES ('".addslashes(serialize($Callback))."', '"
2003 .addslashes(serialize($Parameters))."', ".intval($Priority).", '"
2004 .addslashes($Description)."')");
2005 }
2006
2024 function QueueUniqueTask($Callback, $Parameters = NULL,
2025 $Priority = self::PRIORITY_LOW, $Description = "")
2026 {
2027 if ($this->TaskIsInQueue($Callback, $Parameters))
2028 {
2029 $QueryResult = $this->DB->Query("SELECT TaskId,Priority FROM TaskQueue"
2030 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
2031 .($Parameters ? " AND Parameters = '"
2032 .addslashes(serialize($Parameters))."'" : ""));
2033 if ($QueryResult !== FALSE)
2034 {
2035 $Record = $this->DB->FetchRow();
2036 if ($Record["Priority"] > $Priority)
2037 {
2038 $this->DB->Query("UPDATE TaskQueue"
2039 ." SET Priority = ".intval($Priority)
2040 ." WHERE TaskId = ".intval($Record["TaskId"]));
2041 }
2042 }
2043 return FALSE;
2044 }
2045 else
2046 {
2047 $this->QueueTask($Callback, $Parameters, $Priority, $Description);
2048 return TRUE;
2049 }
2050 }
2051
2061 function TaskIsInQueue($Callback, $Parameters = NULL)
2062 {
2063 $QueuedCount = $this->DB->Query(
2064 "SELECT COUNT(*) AS FoundCount FROM TaskQueue"
2065 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
2066 .($Parameters ? " AND Parameters = '"
2067 .addslashes(serialize($Parameters))."'" : ""),
2068 "FoundCount");
2069 $RunningCount = $this->DB->Query(
2070 "SELECT COUNT(*) AS FoundCount FROM RunningTasks"
2071 ." WHERE Callback = '".addslashes(serialize($Callback))."'"
2072 .($Parameters ? " AND Parameters = '"
2073 .addslashes(serialize($Parameters))."'" : ""),
2074 "FoundCount");
2075 $FoundCount = $QueuedCount + $RunningCount;
2076 return ($FoundCount ? TRUE : FALSE);
2077 }
2078
2084 function GetTaskQueueSize($Priority = NULL)
2085 {
2086 return $this->GetQueuedTaskCount(NULL, NULL, $Priority);
2087 }
2088
2096 function GetQueuedTaskList($Count = 100, $Offset = 0)
2097 {
2098 return $this->GetTaskList("SELECT * FROM TaskQueue"
2099 ." ORDER BY Priority, TaskId ", $Count, $Offset);
2100 }
2101
2115 function GetQueuedTaskCount($Callback = NULL,
2116 $Parameters = NULL, $Priority = NULL, $Description = NULL)
2117 {
2118 $Query = "SELECT COUNT(*) AS TaskCount FROM TaskQueue";
2119 $Sep = " WHERE";
2120 if ($Callback !== NULL)
2121 {
2122 $Query .= $Sep." Callback = '".addslashes(serialize($Callback))."'";
2123 $Sep = " AND";
2124 }
2125 if ($Parameters !== NULL)
2126 {
2127 $Query .= $Sep." Parameters = '".addslashes(serialize($Parameters))."'";
2128 $Sep = " AND";
2129 }
2130 if ($Priority !== NULL)
2131 {
2132 $Query .= $Sep." Priority = ".intval($Priority);
2133 $Sep = " AND";
2134 }
2135 if ($Description !== NULL)
2136 {
2137 $Query .= $Sep." Description = '".addslashes($Description)."'";
2138 }
2139 return $this->DB->Query($Query, "TaskCount");
2140 }
2141
2149 function GetRunningTaskList($Count = 100, $Offset = 0)
2150 {
2151 return $this->GetTaskList("SELECT * FROM RunningTasks"
2152 ." WHERE StartedAt >= '".date("Y-m-d H:i:s",
2153 (time() - ini_get("max_execution_time")))."'"
2154 ." ORDER BY StartedAt", $Count, $Offset);
2155 }
2156
2164 function GetOrphanedTaskList($Count = 100, $Offset = 0)
2165 {
2166 return $this->GetTaskList("SELECT * FROM RunningTasks"
2167 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
2168 (time() - ini_get("max_execution_time")))."'"
2169 ." ORDER BY StartedAt", $Count, $Offset);
2170 }
2171
2176 function GetOrphanedTaskCount()
2177 {
2178 return $this->DB->Query("SELECT COUNT(*) AS Count FROM RunningTasks"
2179 ." WHERE StartedAt < '".date("Y-m-d H:i:s",
2180 (time() - ini_get("max_execution_time")))."'",
2181 "Count");
2182 }
2183
2189 function ReQueueOrphanedTask($TaskId, $NewPriority = NULL)
2190 {
2191 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
2192 $this->DB->Query("INSERT INTO TaskQueue"
2193 ." (Callback,Parameters,Priority,Description) "
2194 ."SELECT Callback, Parameters, Priority, Description"
2195 ." FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2196 if ($NewPriority !== NULL)
2197 {
2198 $NewTaskId = $this->DB->LastInsertId("TaskQueue");
2199 $this->DB->Query("UPDATE TaskQueue SET Priority = "
2200 .intval($NewPriority)
2201 ." WHERE TaskId = ".intval($NewTaskId));
2202 }
2203 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2204 $this->DB->Query("UNLOCK TABLES");
2205 }
2206
2211 function DeleteTask($TaskId)
2212 {
2213 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2214 $this->DB->Query("DELETE FROM RunningTasks WHERE TaskId = ".intval($TaskId));
2215 }
2216
2224 function GetTask($TaskId)
2225 {
2226 # assume task will not be found
2227 $Task = NULL;
2228
2229 # look for task in task queue
2230 $this->DB->Query("SELECT * FROM TaskQueue WHERE TaskId = ".intval($TaskId));
2231
2232 # if task was not found in queue
2233 if (!$this->DB->NumRowsSelected())
2234 {
2235 # look for task in running task list
2236 $this->DB->Query("SELECT * FROM RunningTasks WHERE TaskId = "
2237 .intval($TaskId));
2238 }
2239
2240 # if task was found
2241 if ($this->DB->NumRowsSelected())
2242 {
2243 # if task was periodic
2244 $Row = $this->DB->FetchRow();
2245 if ($Row["Callback"] ==
2246 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
2247 {
2248 # unpack periodic task callback
2249 $WrappedCallback = unserialize($Row["Parameters"]);
2250 $Task["Callback"] = $WrappedCallback[1];
2251 $Task["Parameters"] = $WrappedCallback[2];
2252 }
2253 else
2254 {
2255 # unpack task callback and parameters
2256 $Task["Callback"] = unserialize($Row["Callback"]);
2257 $Task["Parameters"] = unserialize($Row["Parameters"]);
2258 }
2259 }
2260
2261 # return task to caller
2262 return $Task;
2263 }
2264
2272 function TaskExecutionEnabled($NewValue = NULL)
2273 {
2274 if ($NewValue !== NULL)
2275 {
2276 $this->Settings["TaskExecutionEnabled"] = $NewValue ? 1 : 0;
2277 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2278 ." SET TaskExecutionEnabled = "
2279 .$this->Settings["TaskExecutionEnabled"]);
2280 }
2281 return $this->Settings["TaskExecutionEnabled"];
2282 }
2283
2289 function MaxTasks($NewValue = NULL)
2290 {
2291 if (func_num_args() && ($NewValue >= 1))
2292 {
2293 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2294 ." SET MaxTasksRunning = ".intval($NewValue));
2295 $this->Settings["MaxTasksRunning"] = intval($NewValue);
2296 }
2297 return $this->Settings["MaxTasksRunning"];
2298 }
2299
2307 function MaxExecutionTime($NewValue = NULL)
2308 {
2309 if (func_num_args() && !ini_get("safe_mode"))
2310 {
2311 if ($NewValue != $this->Settings["MaxExecTime"])
2312 {
2313 $this->Settings["MaxExecTime"] = max($NewValue, 5);
2314 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2315 ." SET MaxExecTime = '"
2316 .intval($this->Settings["MaxExecTime"])."'");
2317 }
2318 ini_set("max_execution_time", $this->Settings["MaxExecTime"]);
2319 set_time_limit($this->Settings["MaxExecTime"]);
2320 }
2321 return ini_get("max_execution_time");
2322 }
2323
2324 /*@)*/ /* Task Management */
2325
2326 # ---- Backward Compatibility --------------------------------------------
2327 /*@(*/
2329
2334 function FindCommonTemplate($BaseName)
2335 {
2336 return $this->FindFile(
2337 $this->IncludeDirList, $BaseName, array("tpl", "html"));
2338 }
2339
2340 /*@)*/ /* Backward Compatibility */
2341
2342
2343 # ---- PRIVATE INTERFACE -------------------------------------------------
2344
2345 private $ActiveUI = "default";
2346 private $BrowserDetectFunc;
2347 private $DB;
2348 private $DefaultPage = "Home";
2349 private $EnvIncludes = array();
2350 private $ExecutionStartTime;
2351 private $FoundUIFiles = array();
2352 private $AdditionalRequiredUIFiles = array();
2353 private $HtmlCharset = "UTF-8";
2354 private $UseMinimizedJavascript = FALSE;
2355 private $JumpToPage = NULL;
2356 private $PageName;
2357 private $LogFileName = "local/logs/site.log";
2358 private $MaxRunningTasksToTrack = 250;
2359 private $PostProcessingFuncs = array();
2360 private $RunningInBackground = FALSE;
2361 private $RunningTask;
2362 private $Settings;
2363 private $SuppressHTML = FALSE;
2364 private $SaveTemplateLocationCache = FALSE;
2365 private $UnbufferedCallbacks = array();
2366 private $UseBaseTag = FALSE;
2367 private $CleanUrlMappings = array();
2368 private $CleanUrlRewritePerformed = FALSE;
2369 private $OutputModificationPatterns = array();
2370 private $OutputModificationReplacements = array();
2371 private $OutputModificationCallbacks = array();
2372 private $OutputModificationCallbackInfo;
2373
2374 private static $AppName = "ScoutAF";
2375 private static $ObjectDirectories = array();
2376 private static $SessionLifetime = 1440;
2377
2382 private $NoTSR = FALSE;
2383
2384 private $KnownPeriodicEvents = array();
2385 private $PeriodicEvents = array(
2386 "EVENT_HOURLY" => self::EVENTTYPE_DEFAULT,
2387 "EVENT_DAILY" => self::EVENTTYPE_DEFAULT,
2388 "EVENT_WEEKLY" => self::EVENTTYPE_DEFAULT,
2389 "EVENT_MONTHLY" => self::EVENTTYPE_DEFAULT,
2390 "EVENT_PERIODIC" => self::EVENTTYPE_NAMED,
2391 );
2392 private $EventPeriods = array(
2393 "EVENT_HOURLY" => 3600,
2394 "EVENT_DAILY" => 86400,
2395 "EVENT_WEEKLY" => 604800,
2396 "EVENT_MONTHLY" => 2592000,
2397 "EVENT_PERIODIC" => 0,
2398 );
2399 private $UIEvents = array(
2400 "EVENT_PAGE_LOAD" => self::EVENTTYPE_DEFAULT,
2401 "EVENT_PHP_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2402 "EVENT_PHP_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2403 "EVENT_HTML_FILE_LOAD" => self::EVENTTYPE_CHAIN,
2404 "EVENT_HTML_FILE_LOAD_COMPLETE" => self::EVENTTYPE_DEFAULT,
2405 "EVENT_PAGE_OUTPUT_FILTER" => self::EVENTTYPE_CHAIN,
2406 );
2407
2411 private function LoadSettings()
2412 {
2413 # read settings in from database
2414 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2415 $this->Settings = $this->DB->FetchRow();
2416
2417 # if settings were not previously initialized
2418 if (!$this->Settings)
2419 {
2420 # initialize settings in database
2421 $this->DB->Query("INSERT INTO ApplicationFrameworkSettings"
2422 ." (LastTaskRunAt) VALUES ('2000-01-02 03:04:05')");
2423
2424 # read new settings in from database
2425 $this->DB->Query("SELECT * FROM ApplicationFrameworkSettings");
2426 $this->Settings = $this->DB->FetchRow();
2427 }
2428
2429 # if base path was not previously set or we appear to have moved
2430 if (!array_key_exists("BasePath", $this->Settings)
2431 || (!strlen($this->Settings["BasePath"]))
2432 || (!array_key_exists("BasePathCheck", $this->Settings))
2433 || (__FILE__ != $this->Settings["BasePathCheck"]))
2434 {
2435 # attempt to extract base path from Apache .htaccess file
2436 if (is_readable(".htaccess"))
2437 {
2438 $Lines = file(".htaccess");
2439 foreach ($Lines as $Line)
2440 {
2441 if (preg_match("/\\s*RewriteBase\\s+/", $Line))
2442 {
2443 $Pieces = preg_split(
2444 "/\\s+/", $Line, NULL, PREG_SPLIT_NO_EMPTY);
2445 $BasePath = $Pieces[1];
2446 }
2447 }
2448 }
2449
2450 # if base path was found
2451 if (isset($BasePath))
2452 {
2453 # save base path locally
2454 $this->Settings["BasePath"] = $BasePath;
2455
2456 # save base path to database
2457 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2458 ." SET BasePath = '".addslashes($BasePath)."'"
2459 .", BasePathCheck = '".addslashes(__FILE__)."'");
2460 }
2461 }
2462
2463 # if template location cache has been saved to database
2464 if (isset($this->Settings["TemplateLocationCache"]))
2465 {
2466 # unserialize cache values into array and use if valid
2467 $Cache = unserialize($this->Settings["TemplateLocationCache"]);
2468 $this->Settings["TemplateLocationCache"] =
2469 count($Cache) ? $Cache : array();
2470 }
2471 else
2472 {
2473 # start with empty cache
2474 $this->Settings["TemplateLocationCache"] = array();
2475 }
2476 }
2477
2484 private function RewriteCleanUrls($PageName)
2485 {
2486 # if URL rewriting is supported by the server
2487 if ($this->HtaccessSupport())
2488 {
2489 # retrieve current URL and remove base path if present
2490 $Url = $this->GetPageLocation();
2491
2492 # for each clean URL mapping
2493 foreach ($this->CleanUrlMappings as $Info)
2494 {
2495 # if current URL matches clean URL pattern
2496 if (preg_match($Info["Pattern"], $Url, $Matches))
2497 {
2498 # set new page
2499 $PageName = $Info["Page"];
2500
2501 # if $_GET variables specified for clean URL
2502 if ($Info["GetVars"] !== NULL)
2503 {
2504 # for each $_GET variable specified for clean URL
2505 foreach ($Info["GetVars"] as $VarName => $VarTemplate)
2506 {
2507 # start with template for variable value
2508 $Value = $VarTemplate;
2509
2510 # for each subpattern matched in current URL
2511 foreach ($Matches as $Index => $Match)
2512 {
2513 # if not first (whole) match
2514 if ($Index > 0)
2515 {
2516 # make any substitutions in template
2517 $Value = str_replace("$".$Index, $Match, $Value);
2518 }
2519 }
2520
2521 # set $_GET variable
2522 $_GET[$VarName] = $Value;
2523 }
2524 }
2525
2526 # set flag indicating clean URL mapped
2527 $this->CleanUrlRewritePerformed = TRUE;
2528
2529 # stop looking for a mapping
2530 break;
2531 }
2532 }
2533 }
2534
2535 # return (possibly) updated page name to caller
2536 return $PageName;
2537 }
2538
2555 private function FindFile($DirectoryList, $BaseName,
2556 $PossibleSuffixes = NULL, $PossiblePrefixes = NULL)
2557 {
2558 # generate template cache index for this page
2559 $CacheIndex = md5(serialize($DirectoryList))
2560 .":".$this->ActiveUI.":".$BaseName;
2561
2562 # if we have cached location and cache expiration time has not elapsed
2563 if (($this->Settings["TemplateLocationCacheInterval"] > 0)
2564 && count($this->Settings["TemplateLocationCache"])
2565 && array_key_exists($CacheIndex,
2566 $this->Settings["TemplateLocationCache"])
2567 && (time() < strtotime(
2568 $this->Settings["TemplateLocationCacheExpiration"])))
2569 {
2570 # use template location from cache
2571 $FoundFileName = $this->Settings[
2572 "TemplateLocationCache"][$CacheIndex];
2573 }
2574 else
2575 {
2576 # if suffixes specified and base name does not include suffix
2577 if (count($PossibleSuffixes)
2578 && !preg_match("/\.[a-zA-Z0-9]+$/", $BaseName))
2579 {
2580 # add versions of file names with suffixes to file name list
2581 $FileNames = array();
2582 foreach ($PossibleSuffixes as $Suffix)
2583 {
2584 $FileNames[] = $BaseName.".".$Suffix;
2585 }
2586 }
2587 else
2588 {
2589 # use base name as file name
2590 $FileNames = array($BaseName);
2591 }
2592
2593 # if prefixes specified
2594 if (count($PossiblePrefixes))
2595 {
2596 # add versions of file names with prefixes to file name list
2597 $NewFileNames = array();
2598 foreach ($FileNames as $FileName)
2599 {
2600 foreach ($PossiblePrefixes as $Prefix)
2601 {
2602 $NewFileNames[] = $Prefix.$FileName;
2603 }
2604 }
2605 $FileNames = $NewFileNames;
2606 }
2607
2608 # for each possible location
2609 $FoundFileName = NULL;
2610 foreach ($DirectoryList as $Dir)
2611 {
2612 # substitute active UI name into path
2613 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
2614
2615 # for each possible file name
2616 foreach ($FileNames as $File)
2617 {
2618 # if template is found at location
2619 if (file_exists($Dir.$File))
2620 {
2621 # save full template file name and stop looking
2622 $FoundFileName = $Dir.$File;
2623 break 2;
2624 }
2625 }
2626 }
2627
2628 # save location in cache
2629 $this->Settings["TemplateLocationCache"][$CacheIndex]
2630 = $FoundFileName;
2631
2632 # set flag indicating that cache should be saved
2633 $this->SaveTemplateLocationCache = TRUE;
2634 }
2635
2636 # return full template file name to caller
2637 return $FoundFileName;
2638 }
2639
2646 private function GetRequiredFilesNotYetLoaded($PageContentFile)
2647 {
2648 # start out assuming no files required
2649 $RequiredFiles = array();
2650
2651 # if page content file supplied
2652 if ($PageContentFile)
2653 {
2654 # if file containing list of required files is available
2655 $Path = dirname($PageContentFile);
2656 $RequireListFile = $Path."/REQUIRES";
2657 if (file_exists($RequireListFile))
2658 {
2659 # read in list of required files
2660 $RequestedFiles = file($RequireListFile);
2661
2662 # for each line in required file list
2663 foreach ($RequestedFiles as $Line)
2664 {
2665 # if line is not a comment
2666 $Line = trim($Line);
2667 if (!preg_match("/^#/", $Line))
2668 {
2669 # if file has not already been loaded
2670 if (!in_array($Line, $this->FoundUIFiles))
2671 {
2672 # add to list of required files
2673 $RequiredFiles[] = $Line;
2674 }
2675 }
2676 }
2677 }
2678 }
2679
2680 # add in additional required files if any
2681 if (count($this->AdditionalRequiredUIFiles))
2682 {
2683 # make sure there are no duplicates
2684 $AdditionalRequiredUIFiles = array_unique(
2685 $this->AdditionalRequiredUIFiles);
2686
2687 $RequiredFiles = array_merge(
2688 $RequiredFiles, $AdditionalRequiredUIFiles);
2689 }
2690
2691 # return list of required files to caller
2692 return $RequiredFiles;
2693 }
2694
2698 private function SetUpObjectAutoloading()
2699 {
2701 function __autoload($ClassName)
2702 {
2703 ApplicationFramework::AutoloadObjects($ClassName);
2704 }
2705 }
2706
2712 static function AutoloadObjects($ClassName)
2713 {
2714 static $FileLists;
2715 foreach (self::$ObjectDirectories as $Location => $Info)
2716 {
2717 if (is_dir($Location))
2718 {
2719 $NewClassName = ($Info["ClassPattern"] && $Info["ClassReplacement"])
2720 ? preg_replace($Info["ClassPattern"],
2721 $Info["ClassReplacement"], $ClassName)
2722 : $ClassName;
2723 if (!isset($FileLists[$Location]))
2724 {
2725 $FileLists[$Location] = self::ReadDirectoryTree(
2726 $Location, '/^.+\.php$/i');
2727 }
2728 $FileNames = $FileLists[$Location];
2729 $TargetName = strtolower($Info["Prefix"].$NewClassName.".php");
2730 foreach ($FileNames as $FileName)
2731 {
2732 if (strtolower($FileName) == $TargetName)
2733 {
2734 require_once($Location.$FileName);
2735 break 2;
2736 }
2737 }
2738 }
2739 }
2740 }
2741
2749 private static function ReadDirectoryTree($Directory, $Pattern)
2750 {
2751 $CurrentDir = getcwd();
2752 chdir($Directory);
2753 $DirIter = new RecursiveDirectoryIterator(".");
2754 $IterIter = new RecursiveIteratorIterator($DirIter);
2755 $RegexResults = new RegexIterator($IterIter, $Pattern,
2756 RecursiveRegexIterator::GET_MATCH);
2757 $FileList = array();
2758 foreach ($RegexResults as $Result)
2759 {
2760 $FileList[] = substr($Result[0], 2);
2761 }
2762 chdir($CurrentDir);
2763 return $FileList;
2764 }
2770 private function UndoMagicQuotes()
2771 {
2772 # if this PHP version has magic quotes support
2773 if (version_compare(PHP_VERSION, "5.4.0", "<"))
2774 {
2775 # turn off runtime magic quotes if on
2776 if (get_magic_quotes_runtime())
2777 {
2778 set_magic_quotes_runtime(FALSE);
2779 }
2780
2781 # if magic quotes GPC is on
2782 if (get_magic_quotes_gpc())
2783 {
2784 # strip added slashes from incoming variables
2785 $GPC = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
2786 array_walk_recursive($GPC,
2787 array($this, "UndoMagicQuotes_StripCallback"));
2788 }
2789 }
2790 }
2791 private function UndoMagicQuotes_StripCallback(&$Value, $Key)
2792 {
2793 $Value = stripslashes($Value);
2794 }
2795
2800 private function LoadUIFunctions()
2801 {
2802 $Dirs = array(
2803 "local/interface/%ACTIVEUI%/include",
2804 "interface/%ACTIVEUI%/include",
2805 "local/interface/default/include",
2806 "interface/default/include",
2807 );
2808 foreach ($Dirs as $Dir)
2809 {
2810 $Dir = str_replace("%ACTIVEUI%", $this->ActiveUI, $Dir);
2811 if (is_dir($Dir))
2812 {
2813 $FileNames = scandir($Dir);
2814 foreach ($FileNames as $FileName)
2815 {
2816 if (preg_match("/^F-([A-Za-z_]+)\.php/", $FileName, $Matches)
2817 || preg_match("/^F-([A-Za-z_]+)\.html/", $FileName, $Matches))
2818 {
2819 if (!function_exists($Matches[1]))
2820 {
2821 include_once($Dir."/".$FileName);
2822 }
2823 }
2824 }
2825 }
2826 }
2827 }
2828
2834 private function ProcessPeriodicEvent($EventName, $Callback)
2835 {
2836 # retrieve last execution time for event if available
2837 $Signature = self::GetCallbackSignature($Callback);
2838 $LastRun = $this->DB->Query("SELECT LastRunAt FROM PeriodicEvents"
2839 ." WHERE Signature = '".addslashes($Signature)."'", "LastRunAt");
2840
2841 # determine whether enough time has passed for event to execute
2842 $ShouldExecute = (($LastRun === NULL)
2843 || (time() > (strtotime($LastRun) + $this->EventPeriods[$EventName])))
2844 ? TRUE : FALSE;
2845
2846 # if event should run
2847 if ($ShouldExecute)
2848 {
2849 # add event to task queue
2850 $WrapperCallback = array("ApplicationFramework", "PeriodicEventWrapper");
2851 $WrapperParameters = array(
2852 $EventName, $Callback, array("LastRunAt" => $LastRun));
2853 $this->QueueUniqueTask($WrapperCallback, $WrapperParameters);
2854 }
2855
2856 # add event to list of periodic events
2857 $this->KnownPeriodicEvents[$Signature] = array(
2858 "Period" => $EventName,
2859 "Callback" => $Callback,
2860 "Queued" => $ShouldExecute);
2861 }
2862
2870 private static function PeriodicEventWrapper($EventName, $Callback, $Parameters)
2871 {
2872 static $DB;
2873 if (!isset($DB)) { $DB = new Database(); }
2874
2875 # run event
2876 $ReturnVal = call_user_func_array($Callback, $Parameters);
2877
2878 # if event is already in database
2879 $Signature = self::GetCallbackSignature($Callback);
2880 if ($DB->Query("SELECT COUNT(*) AS EventCount FROM PeriodicEvents"
2881 ." WHERE Signature = '".addslashes($Signature)."'", "EventCount"))
2882 {
2883 # update last run time for event
2884 $DB->Query("UPDATE PeriodicEvents SET LastRunAt = "
2885 .(($EventName == "EVENT_PERIODIC")
2886 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
2887 : "NOW()")
2888 ." WHERE Signature = '".addslashes($Signature)."'");
2889 }
2890 else
2891 {
2892 # add last run time for event to database
2893 $DB->Query("INSERT INTO PeriodicEvents (Signature, LastRunAt) VALUES "
2894 ."('".addslashes($Signature)."', "
2895 .(($EventName == "EVENT_PERIODIC")
2896 ? "'".date("Y-m-d H:i:s", time() + ($ReturnVal * 60))."'"
2897 : "NOW()").")");
2898 }
2899 }
2900
2906 private static function GetCallbackSignature($Callback)
2907 {
2908 return !is_array($Callback) ? $Callback
2909 : (is_object($Callback[0]) ? md5(serialize($Callback[0])) : $Callback[0])
2910 ."::".$Callback[1];
2911 }
2912
2917 private function PrepForTSR()
2918 {
2919 # if HTML has been output and it's time to launch another task
2920 # (only TSR if HTML has been output because otherwise browsers
2921 # may misbehave after connection is closed)
2922 if (($this->JumpToPage || !$this->SuppressHTML)
2923 && (time() > (strtotime($this->Settings["LastTaskRunAt"])
2924 + (ini_get("max_execution_time")
2925 / $this->Settings["MaxTasksRunning"]) + 5))
2926 && $this->GetTaskQueueSize()
2927 && $this->Settings["TaskExecutionEnabled"])
2928 {
2929 # begin buffering output for TSR
2930 ob_start();
2931
2932 # let caller know it is time to launch another task
2933 return TRUE;
2934 }
2935 else
2936 {
2937 # let caller know it is not time to launch another task
2938 return FALSE;
2939 }
2940 }
2941
2946 private function LaunchTSR()
2947 {
2948 # set headers to close out connection to browser
2949 if (!$this->NoTSR)
2950 {
2951 ignore_user_abort(TRUE);
2952 header("Connection: close");
2953 header("Content-Length: ".ob_get_length());
2954 }
2955
2956 # output buffered content
2957 while (ob_get_level()) { ob_end_flush(); }
2958 flush();
2959
2960 # write out any outstanding data and end HTTP session
2961 session_write_close();
2962
2963 # set flag indicating that we are now running in background
2964 $this->RunningInBackground = TRUE;
2965
2966 # if there is still a task in the queue
2967 if ($this->GetTaskQueueSize())
2968 {
2969 # turn on output buffering to (hopefully) record any crash output
2970 ob_start();
2971
2972 # lock tables and grab last task run time to double check
2973 $this->DB->Query("LOCK TABLES ApplicationFrameworkSettings WRITE");
2974 $this->LoadSettings();
2975
2976 # if still time to launch another task
2977 if (time() > (strtotime($this->Settings["LastTaskRunAt"])
2978 + (ini_get("max_execution_time")
2979 / $this->Settings["MaxTasksRunning"]) + 5))
2980 {
2981 # update the "last run" time and release tables
2982 $this->DB->Query("UPDATE ApplicationFrameworkSettings"
2983 ." SET LastTaskRunAt = '".date("Y-m-d H:i:s")."'");
2984 $this->DB->Query("UNLOCK TABLES");
2985
2986 # run tasks while there is a task in the queue and enough time left
2987 do
2988 {
2989 # run the next task
2990 $this->RunNextTask();
2991 }
2992 while ($this->GetTaskQueueSize()
2993 && ($this->GetSecondsBeforeTimeout() > 65));
2994 }
2995 else
2996 {
2997 # release tables
2998 $this->DB->Query("UNLOCK TABLES");
2999 }
3000 }
3001 }
3002
3010 private function GetTaskList($DBQuery, $Count, $Offset)
3011 {
3012 $this->DB->Query($DBQuery." LIMIT ".intval($Offset).",".intval($Count));
3013 $Tasks = array();
3014 while ($Row = $this->DB->FetchRow())
3015 {
3016 $Tasks[$Row["TaskId"]] = $Row;
3017 if ($Row["Callback"] ==
3018 serialize(array("ApplicationFramework", "PeriodicEventWrapper")))
3019 {
3020 $WrappedCallback = unserialize($Row["Parameters"]);
3021 $Tasks[$Row["TaskId"]]["Callback"] = $WrappedCallback[1];
3022 $Tasks[$Row["TaskId"]]["Parameters"] = NULL;
3023 }
3024 else
3025 {
3026 $Tasks[$Row["TaskId"]]["Callback"] = unserialize($Row["Callback"]);
3027 $Tasks[$Row["TaskId"]]["Parameters"] = unserialize($Row["Parameters"]);
3028 }
3029 }
3030 return $Tasks;
3031 }
3032
3036 private function RunNextTask()
3037 {
3038 # lock tables to prevent same task from being run by multiple sessions
3039 $this->DB->Query("LOCK TABLES TaskQueue WRITE, RunningTasks WRITE");
3040
3041 # look for task at head of queue
3042 $this->DB->Query("SELECT * FROM TaskQueue ORDER BY Priority, TaskId LIMIT 1");
3043 $Task = $this->DB->FetchRow();
3044
3045 # if there was a task available
3046 if ($Task)
3047 {
3048 # move task from queue to running tasks list
3049 $this->DB->Query("INSERT INTO RunningTasks "
3050 ."(TaskId,Callback,Parameters,Priority,Description) "
3051 ."SELECT * FROM TaskQueue WHERE TaskId = "
3052 .intval($Task["TaskId"]));
3053 $this->DB->Query("DELETE FROM TaskQueue WHERE TaskId = "
3054 .intval($Task["TaskId"]));
3055
3056 # release table locks to again allow other sessions to run tasks
3057 $this->DB->Query("UNLOCK TABLES");
3058
3059 # unpack stored task info
3060 $Callback = unserialize($Task["Callback"]);
3061 $Parameters = unserialize($Task["Parameters"]);
3062
3063 # attempt to load task callback if not already available
3064 $this->LoadFunction($Callback);
3065
3066 # run task
3067 $this->RunningTask = $Task;
3068 if ($Parameters)
3069 {
3070 call_user_func_array($Callback, $Parameters);
3071 }
3072 else
3073 {
3074 call_user_func($Callback);
3075 }
3076 unset($this->RunningTask);
3077
3078 # remove task from running tasks list
3079 $this->DB->Query("DELETE FROM RunningTasks"
3080 ." WHERE TaskId = ".intval($Task["TaskId"]));
3081
3082 # prune running tasks list if necessary
3083 $RunningTasksCount = $this->DB->Query(
3084 "SELECT COUNT(*) AS TaskCount FROM RunningTasks", "TaskCount");
3085 if ($RunningTasksCount > $this->MaxRunningTasksToTrack)
3086 {
3087 $this->DB->Query("DELETE FROM RunningTasks ORDER BY StartedAt"
3088 ." LIMIT ".($RunningTasksCount - $this->MaxRunningTasksToTrack));
3089 }
3090 }
3091 else
3092 {
3093 # release table locks to again allow other sessions to run tasks
3094 $this->DB->Query("UNLOCK TABLES");
3095 }
3096 }
3097
3103 function OnCrash()
3104 {
3105 if (isset($this->RunningTask))
3106 {
3107 if (function_exists("error_get_last"))
3108 {
3109 $CrashInfo["LastError"] = error_get_last();
3110 }
3111 if (ob_get_length() !== FALSE)
3112 {
3113 $CrashInfo["OutputBuffer"] = ob_get_contents();
3114 }
3115 if (isset($CrashInfo))
3116 {
3117 $DB = new Database();
3118 $DB->Query("UPDATE RunningTasks SET CrashInfo = '"
3119 .addslashes(serialize($CrashInfo))
3120 ."' WHERE TaskId = ".intval($this->RunningTask["TaskId"]));
3121 }
3122 }
3123
3124 print("\n");
3125 return;
3126 }
3127
3144 private function AddToDirList($DirList, $Dir, $SearchLast, $SkipSlashCheck)
3145 {
3146 # convert incoming directory to array of directories (if needed)
3147 $Dirs = is_array($Dir) ? $Dir : array($Dir);
3148
3149 # reverse array so directories are searched in specified order
3150 $Dirs = array_reverse($Dirs);
3151
3152 # for each directory
3153 foreach ($Dirs as $Location)
3154 {
3155 # make sure directory includes trailing slash
3156 if (!$SkipSlashCheck)
3157 {
3158 $Location = $Location
3159 .((substr($Location, -1) != "/") ? "/" : "");
3160 }
3161
3162 # remove directory from list if already present
3163 if (in_array($Location, $DirList))
3164 {
3165 $DirList = array_diff(
3166 $DirList, array($Location));
3167 }
3168
3169 # add directory to list of directories
3170 if ($SearchLast)
3171 {
3172 array_push($DirList, $Location);
3173 }
3174 else
3175 {
3176 array_unshift($DirList, $Location);
3177 }
3178 }
3179
3180 # return updated directory list to caller
3181 return $DirList;
3182 }
3183
3191 private function ArrayPermutations($Items, $Perms = array())
3192 {
3193 if (empty($Items))
3194 {
3195 $Result = array($Perms);
3196 }
3197 else
3198 {
3199 $Result = array();
3200 for ($Index = count($Items) - 1; $Index >= 0; --$Index)
3201 {
3202 $NewItems = $Items;
3203 $NewPerms = $Perms;
3204 list($Segment) = array_splice($NewItems, $Index, 1);
3205 array_unshift($NewPerms, $Segment);
3206 $Result = array_merge($Result,
3207 $this->ArrayPermutations($NewItems, $NewPerms));
3208 }
3209 }
3210 return $Result;
3211 }
3212
3219 private function OutputModificationCallbackShell($Matches)
3220 {
3221 # call previously-stored external function
3222 return call_user_func($this->OutputModificationCallbackInfo["Callback"],
3223 $Matches,
3224 $this->OutputModificationCallbackInfo["Pattern"],
3225 $this->OutputModificationCallbackInfo["Page"],
3226 $this->OutputModificationCallbackInfo["SearchPattern"]);
3227 }
3228
3230 private $InterfaceDirList = array(
3231 "local/interface/%ACTIVEUI%/",
3232 "interface/%ACTIVEUI%/",
3233 "local/interface/default/",
3234 "interface/default/",
3235 );
3240 private $IncludeDirList = array(
3241 "local/interface/%ACTIVEUI%/include/",
3242 "interface/%ACTIVEUI%/include/",
3243 "local/interface/default/include/",
3244 "interface/default/include/",
3245 );
3247 private $ImageDirList = array(
3248 "local/interface/%ACTIVEUI%/images/",
3249 "interface/%ACTIVEUI%/images/",
3250 "local/interface/default/images/",
3251 "interface/default/images/",
3252 );
3254 private $FunctionDirList = array(
3255 "local/interface/%ACTIVEUI%/include/",
3256 "interface/%ACTIVEUI%/include/",
3257 "local/interface/default/include/",
3258 "interface/default/include/",
3259 "local/include/",
3260 "include/",
3261 );
3262
3263 const NOVALUE = ".-+-.NO VALUE PASSED IN FOR ARGUMENT.-+-.";
3264 };
ApplicationFramework\LOGLVL_ERROR
const LOGLVL_ERROR
ERROR error logging level.
Definition: ApplicationFramework.php:1627
ApplicationFramework\LoggingLevel
LoggingLevel($NewValue=NULL)
Get/set logging level.
Definition: ApplicationFramework.php:1571
ApplicationFramework\GetOrphanedTaskList
GetOrphanedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:2164
ApplicationFramework\SuppressHTMLOutput
SuppressHTMLOutput($NewSetting=TRUE)
Suppress loading of HTML files.
Definition: ApplicationFramework.php:1071
ApplicationFramework\AddInterfaceDirectories
AddInterfaceDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for user interface (HTML/TPL) files.
Definition: ApplicationFramework.php:222
ApplicationFramework\AddIncludeDirectories
AddIncludeDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for user interface include (CSS, JavaScript, common PHP, common HTML, etc) files.
Definition: ApplicationFramework.php:196
ApplicationFramework\GetScriptUrl
static GetScriptUrl()
Retrieve SCRIPT_URL server value, pulling it from elsewhere if that variable isn&#39;t set...
Definition: ApplicationFramework.php:1396
ApplicationFramework\LOGLVL_INFO
const LOGLVL_INFO
INFO error logging level.
Definition: ApplicationFramework.php:1616
ApplicationFramework\AddUnbufferedCallback
AddUnbufferedCallback($Callback, $Parameters=array())
Add a callback that will not be executed after buffered content has been output and that won&#39;t have i...
Definition: ApplicationFramework.php:271
ApplicationFramework\QueueUniqueTask
QueueUniqueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue if not already in queue or currently running.
Definition: ApplicationFramework.php:2024
ApplicationFramework\LOGLVL_FATAL
const LOGLVL_FATAL
FATAL error logging level.
Definition: ApplicationFramework.php:1632
ApplicationFramework\UseMinimizedJavascript
UseMinimizedJavascript($NewSetting=NULL)
Get/set whether or not to check for and use minimized JavaScript files when getting a JavaScript UI f...
Definition: ApplicationFramework.php:1043
ApplicationFramework\AddPostProcessingCall
AddPostProcessingCall($FunctionName, &$Arg1=self::NOVALUE, &$Arg2=self::NOVALUE, &$Arg3=self::NOVALUE, &$Arg4=self::NOVALUE, &$Arg5=self::NOVALUE, &$Arg6=self::NOVALUE, &$Arg7=self::NOVALUE, &$Arg8=self::NOVALUE, &$Arg9=self::NOVALUE)
Add function to be called after HTML has been loaded.
Definition: ApplicationFramework.php:1162
ApplicationFramework\GetCleanUrlForPath
GetCleanUrlForPath($Path)
Get the clean URL mapped for a path.
Definition: ApplicationFramework.php:453
ApplicationFramework\PRIORITY_LOW
const PRIORITY_LOW
Lower priority.
Definition: ApplicationFramework.php:1979
Message
Abstraction for forum messages and resource comments.
Definition: Message.php:15
ApplicationFramework\GetQueuedTaskList
GetQueuedTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:2096
ApplicationFramework\LogFile
LogFile($NewValue=NULL)
Get/set log file name.
Definition: ApplicationFramework.php:1595
ApplicationFramework\GetCleanUrl
GetCleanUrl()
Get the clean URL for the current page if one is available.
Definition: ApplicationFramework.php:551
ApplicationFramework\MaxExecutionTime
MaxExecutionTime($NewValue=NULL)
Get/set maximum PHP execution time.
Definition: ApplicationFramework.php:2307
ApplicationFramework\RequireUIFile
RequireUIFile($FileName)
Add file to list of required UI files.
Definition: ApplicationFramework.php:1253
ApplicationFramework
Top-level framework for web applications.
Definition: ApplicationFramework.php:14
ApplicationFramework\BaseUrl
static BaseUrl()
Get current base URL (usually the part before index.php).
Definition: ApplicationFramework.php:1363
ApplicationFramework\GetOrphanedTaskCount
GetOrphanedTaskCount()
Retrieve current number of orphaned tasks.
Definition: ApplicationFramework.php:2176
Database
SQL database abstraction object with smart query caching.
Definition: Axis--Database.php:22
ApplicationFramework\GetTaskQueueSize
GetTaskQueueSize($Priority=NULL)
Retrieve current number of tasks in queue.
Definition: ApplicationFramework.php:2084
ApplicationFramework\GetQueuedTaskCount
GetQueuedTaskCount($Callback=NULL, $Parameters=NULL, $Priority=NULL, $Description=NULL)
Get number of queued tasks that match supplied values.
Definition: ApplicationFramework.php:2115
ApplicationFramework\DeleteTask
DeleteTask($TaskId)
Remove task from task queues.
Definition: ApplicationFramework.php:2211
ApplicationFramework\LOGLVL_DEBUG
const LOGLVL_DEBUG
DEBUG error logging leve.
Definition: ApplicationFramework.php:1610
ApplicationFramework\EVENTTYPE_NAMED
const EVENTTYPE_NAMED
Named result event type.
Definition: ApplicationFramework.php:1663
ApplicationFramework\EVENTTYPE_FIRST
const EVENTTYPE_FIRST
First response event type.
Definition: ApplicationFramework.php:1655
ApplicationFramework\WasUrlRewritten
static WasUrlRewritten($ScriptName="index.php")
Determine if the URL was rewritten, i.e., the script is being accessed through a URL that isn&#39;t direc...
Definition: ApplicationFramework.php:1425
ApplicationFramework\EVENTTYPE_DEFAULT
const EVENTTYPE_DEFAULT
Default event type.
Definition: ApplicationFramework.php:1643
ApplicationFramework\GetPageUrl
GetPageUrl()
Get the full URL to the page.
Definition: ApplicationFramework.php:980
ApplicationFramework\IsStaticOnlyEvent
IsStaticOnlyEvent($EventName)
Report whether specified event only allows static callbacks.
Definition: ApplicationFramework.php:1882
ApplicationFramework\IsRegisteredEvent
IsRegisteredEvent($EventName)
Check if event has been registered (is available to be signaled).
Definition: ApplicationFramework.php:1701
ApplicationFramework\AddObjectDirectory
static AddObjectDirectory($Dir, $Prefix="", $ClassPattern=NULL, $ClassReplacement=NULL)
Add directory to be searched for object files when autoloading.
Definition: ApplicationFramework.php:134
ApplicationFramework\SignalEvent
SignalEvent($EventName, $Parameters=NULL)
Signal that an event has occured.
Definition: ApplicationFramework.php:1800
ApplicationFramework\BasePath
static BasePath()
Get current base path (usually the part after the host name).
Definition: ApplicationFramework.php:1379
ApplicationFramework\LOGLVL_TRACE
const LOGLVL_TRACE
TRACE error logging level.
Definition: ApplicationFramework.php:1605
ApplicationFramework\LOGLVL_WARNING
const LOGLVL_WARNING
WARNING error logging level.
Definition: ApplicationFramework.php:1621
ApplicationFramework\PRIORITY_MEDIUM
const PRIORITY_MEDIUM
Medium (default) priority.
Definition: ApplicationFramework.php:1977
ApplicationFramework\LogError
LogError($Level, $Msg)
Write error message to log.
Definition: ApplicationFramework.php:1462
ApplicationFramework\OnCrash
OnCrash()
Called automatically at program termination to ensure output is written out.
Definition: ApplicationFramework.php:3103
ApplicationFramework\GetKnownPeriodicEvents
GetKnownPeriodicEvents()
Get list of known periodic events.
Definition: ApplicationFramework.php:1932
ApplicationFramework\EVENTTYPE_CHAIN
const EVENTTYPE_CHAIN
Result chaining event type.
Definition: ApplicationFramework.php:1649
ApplicationFramework\GetSecondsBeforeTimeout
GetSecondsBeforeTimeout()
Get remaining available (PHP) execution time.
Definition: ApplicationFramework.php:1324
ApplicationFramework\TaskIsInQueue
TaskIsInQueue($Callback, $Parameters=NULL)
Check if task is already in queue or currently running.
Definition: ApplicationFramework.php:2061
ApplicationFramework\AddFunctionDirectories
AddFunctionDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for function (&quot;F-&quot;) files.
Definition: ApplicationFramework.php:248
ApplicationFramework\ORDER_MIDDLE
const ORDER_MIDDLE
Run hooked function after ORDER_FIRST and before ORDER_LAST events.
Definition: ApplicationFramework.php:1668
PHP
PHP
Definition: OAIClient.php:39
ApplicationFramework\RegisterEvent
RegisterEvent($EventsOrEventName, $EventType=NULL)
Register one or more events that may be signaled.
Definition: ApplicationFramework.php:1680
ApplicationFramework\SetJumpToPage
SetJumpToPage($Page, $IsLiteral=FALSE)
Set URL of page to autoload after PHP page file is executed.
Definition: ApplicationFramework.php:993
ApplicationFramework\GetPageName
GetPageName()
Get name of page being loaded.
Definition: ApplicationFramework.php:951
ApplicationFramework\CleanUrlIsMapped
CleanUrlIsMapped($Path)
Report whether clean URL has already been mapped.
Definition: ApplicationFramework.php:435
ApplicationFramework\TaskExecutionEnabled
TaskExecutionEnabled($NewValue=NULL)
Get/set whether automatic task execution is enabled.
Definition: ApplicationFramework.php:2272
ApplicationFramework\PRIORITY_HIGH
const PRIORITY_HIGH
Highest priority.
Definition: ApplicationFramework.php:1975
ApplicationFramework\LoadFunction
LoadFunction($Callback)
Attempt to load code for function or method if not currently available.
Definition: ApplicationFramework.php:1266
ApplicationFramework\GetRunningTaskList
GetRunningTaskList($Count=100, $Offset=0)
Retrieve list of tasks currently in queue.
Definition: ApplicationFramework.php:2149
ApplicationFramework\FindCommonTemplate
FindCommonTemplate($BaseName)
Preserved for backward compatibility for use with code written prior to October 2012.
Definition: ApplicationFramework.php:2334
ApplicationFramework\EventWillNextRunAt
EventWillNextRunAt($EventName, $Callback)
Get date/time a periodic event will next run.
Definition: ApplicationFramework.php:1897
ApplicationFramework\SessionLifetime
static SessionLifetime($NewValue=NULL)
Get/set session timeout in seconds.
Definition: ApplicationFramework.php:302
ApplicationFramework\HookEvent
HookEvent($EventsOrEventName, $Callback=NULL, $Order=self::ORDER_MIDDLE)
Hook one or more functions to be called when the specified event is signaled.
Definition: ApplicationFramework.php:1738
ApplicationFramework\IsHookedEvent
IsHookedEvent($EventName)
Check if an event is registered and is hooked to.
Definition: ApplicationFramework.php:1713
ApplicationFramework\TemplateLocationCacheExpirationInterval
TemplateLocationCacheExpirationInterval($NewInterval=-1)
Get/set UI template location cache expiration period in minutes.
Definition: ApplicationFramework.php:285
ApplicationFramework\AddImageDirectories
AddImageDirectories($Dir, $SearchLast=FALSE, $SkipSlashCheck=FALSE)
Add additional directory(s) to be searched for image files.
Definition: ApplicationFramework.php:169
ApplicationFramework\HtmlCharset
HtmlCharset($NewSetting=NULL)
Get/set HTTP character encoding value.
Definition: ApplicationFramework.php:1031
ApplicationFramework\ORDER_FIRST
const ORDER_FIRST
Run hooked function first (i.e.
Definition: ApplicationFramework.php:1666
ApplicationFramework\HtaccessSupport
HtaccessSupport()
Determine if .htaccess files are enabled.
Definition: ApplicationFramework.php:1353
ApplicationFramework\GetUncleanUrlForPath
GetUncleanUrlForPath($Path)
Get the unclean URL for mapped for a path.
Definition: ApplicationFramework.php:501
ApplicationFramework\GetUncleanUrl
GetUncleanUrl()
Get the unclean URL for the current page.
Definition: ApplicationFramework.php:560
ApplicationFramework\JumpToPageIsSet
JumpToPageIsSet()
Report whether a page to autoload has been set.
Definition: ApplicationFramework.php:1017
ApplicationFramework\ORDER_LAST
const ORDER_LAST
Run hooked function last (i.e.
Definition: ApplicationFramework.php:1670
ApplicationFramework\UseBaseTag
UseBaseTag($NewValue=NULL)
Get/set whether or not to use the &quot;base&quot; tag to ensure relative URL paths are correct.
Definition: ApplicationFramework.php:1059
ApplicationFramework\GetFreeMemory
GetFreeMemory()
Get current amount of free memory.
Definition: ApplicationFramework.php:1334
ApplicationFramework\GetTask
GetTask($TaskId)
Retrieve task info from queue (either running or queued tasks).
Definition: ApplicationFramework.php:2224
ApplicationFramework\LoadPage
LoadPage($PageName)
Load page PHP and HTML/TPL files.
Definition: ApplicationFramework.php:570
ApplicationFramework\AddEnvInclude
AddEnvInclude($FileName)
Add file to be included to set up environment.
Definition: ApplicationFramework.php:1184
ApplicationFramework\NOVALUE
const NOVALUE
Definition: ApplicationFramework.php:3263
ApplicationFramework\ReQueueOrphanedTask
ReQueueOrphanedTask($TaskId, $NewPriority=NULL)
Move orphaned task back into queue.
Definition: ApplicationFramework.php:2189
ApplicationFramework\GUIFile
GUIFile($FileName)
Search UI directories for specified image or CSS file and return name of correct file.
Definition: ApplicationFramework.php:1195
ApplicationFramework\QueueTask
QueueTask($Callback, $Parameters=NULL, $Priority=self::PRIORITY_LOW, $Description="")
Add task to queue.
Definition: ApplicationFramework.php:1995
ApplicationFramework\MaxTasks
MaxTasks($NewValue=NULL)
Get/set maximum number of tasks to have running simultaneously.
Definition: ApplicationFramework.php:2289
ApplicationFramework\GetUserInterfaces
GetUserInterfaces()
Get the list of available user interfaces.
Definition: ApplicationFramework.php:1096
ApplicationFramework\PUIFile
PUIFile($FileName)
Search UI directories for specified image or CSS file and print name of correct file.
Definition: ApplicationFramework.php:1240
ApplicationFramework\ActiveUserInterface
ActiveUserInterface($UIName=NULL)
Get/set name of current active user interface.
Definition: ApplicationFramework.php:1082
ApplicationFramework\GetPageLocation
GetPageLocation()
Get the URL path to the page without the base path, if present.
Definition: ApplicationFramework.php:961
ApplicationFramework\GetElapsedExecutionTime
GetElapsedExecutionTime()
Get time elapsed since constructor was called.
Definition: ApplicationFramework.php:1315
ApplicationFramework\SetBrowserDetectionFunc
SetBrowserDetectionFunc($DetectionFunc)
Specify function to use to detect the web browser type.
Definition: ApplicationFramework.php:260
ApplicationFramework\AddCleanUrl
AddCleanUrl($Pattern, $Page, $GetVars=NULL, $Template=NULL)
Add clean URL mapping.
Definition: ApplicationFramework.php:337
ApplicationFramework\PRIORITY_BACKGROUND
const PRIORITY_BACKGROUND
Lowest priority.
Definition: ApplicationFramework.php:1981
ApplicationFramework\LogMessage
LogMessage($Level, $Msg)
Write status message to log.
Definition: ApplicationFramework.php:1503
$Items
$Items
Definition: RSSClient--Test.php:26