PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/frontend/init.php

http://github.com/forkcms/forkcms
PHP | 396 lines | 190 code | 68 blank | 138 comment | 34 complexity | 4000de6f5d9a6b0ee54f03478a7dee13 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, MIT, AGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of Fork CMS.
  4. *
  5. * For the full copyright and license information, please view the license
  6. * file that was distributed with this source code.
  7. */
  8. /**
  9. * This class will initiate the frontend-application
  10. *
  11. * @author Tijs Verkoyen <tijs@sumocoders.be>
  12. * @author Davy Hellemans <davy.hellemans@netlash.com>
  13. * @author Matthias Mullie <matthias@mullie.eu>
  14. */
  15. class FrontendInit
  16. {
  17. /**
  18. * Current type
  19. *
  20. * @var string
  21. */
  22. private $type;
  23. /**
  24. * @param string $type The type of init to load, possible values are: frontend, frontend_ajax, frontend_js.
  25. */
  26. public function __construct($type)
  27. {
  28. $allowedTypes = array('frontend', 'frontend_ajax', 'frontend_js');
  29. $type = (string) $type;
  30. // check if this is a valid type
  31. if(!in_array($type, $allowedTypes)) exit('Invalid init-type');
  32. $this->type = $type;
  33. // register the autoloader
  34. spl_autoload_register(array('FrontendInit', 'autoLoader'));
  35. // set some ini-options
  36. ini_set('pcre.backtrack_limit', 999999999);
  37. ini_set('pcre.recursion_limit', 999999999);
  38. ini_set('memory_limit', '64M');
  39. // set a default timezone if no one was set by PHP.ini
  40. if(ini_get('date.timezone') == '') date_default_timezone_set('Europe/Brussels');
  41. /**
  42. * At first we enable the error reporting. Later on it will be disabled based on the
  43. * value of SPOON_DEBUG, but for now it's required to see possible errors while trying
  44. * to include the globals file(s).
  45. */
  46. error_reporting(E_ALL | E_STRICT);
  47. ini_set('display_errors', 'On');
  48. $this->requireGlobals();
  49. // get last modified time for globals
  50. $lastModifiedTime = @filemtime(PATH_LIBRARY . '/globals.php');
  51. // reset lastmodified time if needed (SPOON_DEBUG is enabled or we don't get a decent timestamp)
  52. if($lastModifiedTime === false || SPOON_DEBUG) $lastModifiedTime = time();
  53. // define as a constant
  54. define('LAST_MODIFIED_TIME', $lastModifiedTime);
  55. $this->definePaths();
  56. $this->defineURLs();
  57. $this->setIncludePath();
  58. $this->setDebugging();
  59. // require spoon
  60. require_once 'spoon/spoon.php';
  61. $this->requireFrontendClasses();
  62. SpoonFilter::disableMagicQuotes();
  63. }
  64. /**
  65. * Autoloader for the frontend
  66. *
  67. * @param string $className The name of the class to require.
  68. */
  69. public static function autoLoader($className)
  70. {
  71. // redefine
  72. $className = strtolower((string) $className);
  73. // init var
  74. $pathToLoad = '';
  75. // exceptions
  76. $exceptions = array();
  77. $exceptions['frontend'] = FRONTEND_CORE_PATH . '/engine/frontend.php';
  78. $exceptions['frontendbaseajaxaction'] = FRONTEND_CORE_PATH . '/engine/base.php';
  79. $exceptions['frontendbaseconfig'] = FRONTEND_CORE_PATH . '/engine/base.php';
  80. $exceptions['frontendbaseobject'] = FRONTEND_CORE_PATH . '/engine/base.php';
  81. $exceptions['frontendblockextra'] = FRONTEND_CORE_PATH . '/engine/block.php';
  82. $exceptions['frontendblockwidget'] = FRONTEND_CORE_PATH . '/engine/block.php';
  83. $exceptions['frontendtemplatecompiler'] = FRONTEND_CORE_PATH . '/engine/template_compiler.php';
  84. // is it an exception
  85. if(isset($exceptions[$className])) $pathToLoad = $exceptions[$className];
  86. // frontend
  87. elseif(substr($className, 0, 8) == 'frontend') $pathToLoad = FRONTEND_CORE_PATH . '/engine/' . str_replace('frontend', '', $className) . '.php';
  88. // file check in core
  89. if($pathToLoad != '' && SpoonFile::exists($pathToLoad)) require_once $pathToLoad;
  90. // check if module file exists
  91. else
  92. {
  93. // we'll need the original class name again, with the uppercases
  94. $className = func_get_arg(0);
  95. // split in parts, if nothing is found we stop processing
  96. if(!preg_match_all('/[A-Z][a-z0-9]*/', $className, $parts)) return;
  97. // the real matches
  98. $parts = $parts[0];
  99. // doublecheck that we are looking for a frontend class, of that isn't the case we should stop.
  100. $root = array_shift($parts);
  101. if(strtolower($root) != 'frontend') return;
  102. foreach($parts as $i => $part)
  103. {
  104. // skip the first
  105. if($i == 0) continue;
  106. // action
  107. $action = strtolower(implode('_', $parts));
  108. // module
  109. $module = '';
  110. for($j = 0; $j < $i; $j++) $module .= strtolower($parts[$j]) . '_';
  111. // fix action & module
  112. $action = substr($action, strlen($module));
  113. $module = substr($module, 0, -1);
  114. // check the actions, engine & widgets directories
  115. foreach(array('actions', 'engine', 'widgets') as $dir)
  116. {
  117. // file to be loaded
  118. $pathToLoad = FRONTEND_PATH . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR . $action . '.php';
  119. // if it exists, load it!
  120. if($pathToLoad != '' && SpoonFile::exists($pathToLoad))
  121. {
  122. require_once $pathToLoad;
  123. break;
  124. }
  125. }
  126. }
  127. }
  128. }
  129. /**
  130. * Define paths
  131. */
  132. private function definePaths()
  133. {
  134. // fix the Application setting
  135. if($this->type == 'frontend_js') define('APPLICATION', 'frontend');
  136. elseif($this->type == 'frontend_ajax') define('APPLICATION', 'frontend');
  137. // general paths
  138. define('FRONTEND_PATH', PATH_WWW . '/' . APPLICATION);
  139. define('FRONTEND_CACHE_PATH', FRONTEND_PATH . '/cache');
  140. define('FRONTEND_CORE_PATH', FRONTEND_PATH . '/core');
  141. define('FRONTEND_MODULES_PATH', FRONTEND_PATH . '/modules');
  142. define('FRONTEND_FILES_PATH', FRONTEND_PATH . '/files');
  143. }
  144. /**
  145. * Define URLs
  146. */
  147. private function defineURLs()
  148. {
  149. define('FRONTEND_CORE_URL', '/' . APPLICATION . '/core');
  150. define('FRONTEND_CACHE_URL', '/' . APPLICATION . '/cache');
  151. define('FRONTEND_FILES_URL', '/' . APPLICATION . '/files');
  152. }
  153. /**
  154. * A custom error-handler so we can handle warnings about undefined labels
  155. *
  156. * @param int $errorNumber The level of the error raised, as an integer.
  157. * @param string $errorString The error message, as a string.
  158. * @return bool
  159. */
  160. public static function errorHandler($errorNumber, $errorString)
  161. {
  162. // redefine
  163. $errorNumber = (int) $errorNumber;
  164. $errorString = (string) $errorString;
  165. // is this an undefined index?
  166. if(mb_substr_count($errorString, 'Undefined index:') > 0)
  167. {
  168. // cleanup
  169. $index = trim(str_replace('Undefined index:', '', $errorString));
  170. // get the type
  171. $type = mb_substr($index, 0, 3);
  172. // is the index locale?
  173. if(in_array($type, array('act', 'err', 'lbl', 'msg'))) echo '{$' . $index . '}';
  174. // return false, so the standard error handler isn't bypassed
  175. else return false;
  176. }
  177. // return false, so the standard error handler isn't bypassed
  178. else return false;
  179. }
  180. /**
  181. * This method will be called by the Spoon Exceptionhandler and is specific for exceptions thrown in AJAX-actions
  182. *
  183. * @param object $exception The exception that was thrown.
  184. * @param string $output The output that should be mailed.
  185. */
  186. public static function exceptionAJAXHandler($exception, $output)
  187. {
  188. // redefine
  189. $output = (string) $output;
  190. // set headers
  191. SpoonHTTP::setHeaders('content-type: application/json');
  192. // create response array
  193. $response = array('code' => ($exception->getCode() != 0) ? $exception->getCode() : 500, 'message' => $exception->getMessage());
  194. // output to the browser
  195. echo json_encode($response);
  196. // stop script execution
  197. exit;
  198. }
  199. /**
  200. * This method will be called by the Spoon Exceptionhandler
  201. *
  202. * @param object $exception The exception that was thrown.
  203. * @param string $output The output that should be mailed.
  204. */
  205. public static function exceptionHandler($exception, $output)
  206. {
  207. $output = (string) $output;
  208. // mail it?
  209. if(SPOON_DEBUG_EMAIL != '')
  210. {
  211. // e-mail headers
  212. $headers = "MIME-Version: 1.0\n";
  213. $headers .= "Content-type: text/html; charset=iso-8859-15\n";
  214. $headers .= "X-Priority: 3\n";
  215. $headers .= "X-MSMail-Priority: Normal\n";
  216. $headers .= "X-Mailer: SpoonLibrary Webmail\n";
  217. $headers .= "From: Spoon Library <no-reply@spoon-library.com>\n";
  218. // send email
  219. @mail(SPOON_DEBUG_EMAIL, 'Exception Occured (' . SITE_DOMAIN . ')', $output, $headers);
  220. }
  221. // build HTML for nice error
  222. $html = '<html><body>Something went wrong.</body></html>';
  223. // output
  224. echo $html;
  225. exit;
  226. }
  227. /**
  228. * This method will be called by the Spoon Exceptionhandler and is specific for exceptions thrown in JS-files parsed through PHP
  229. *
  230. * @param object $exception The exception that was thrown.
  231. * @param string $output The output that should be mailed.
  232. */
  233. public static function exceptionJSHandler($exception, $output)
  234. {
  235. // redefine
  236. $output = (string) $output;
  237. // set correct headers
  238. SpoonHTTP::setHeaders('content-type: application/javascript');
  239. // output
  240. echo '// ' . $exception->getMessage();
  241. exit;
  242. }
  243. /**
  244. * Require all needed classes
  245. */
  246. private function requireFrontendClasses()
  247. {
  248. switch($this->type)
  249. {
  250. case 'frontend':
  251. case 'frontend_ajax':
  252. require_once FRONTEND_CORE_PATH . '/engine/template_custom.php';
  253. require_once FRONTEND_PATH . '/modules/tags/engine/model.php';
  254. break;
  255. }
  256. }
  257. /**
  258. * Require globals-file
  259. */
  260. private function requireGlobals()
  261. {
  262. // fetch config
  263. $installed[] = @include_once dirname(__FILE__) . '/cache/config/config.php';
  264. // load the globals
  265. $installed[] = @include_once INIT_PATH_LIBRARY . '/globals.php';
  266. $installed[] = @include_once INIT_PATH_LIBRARY . '/globals_backend.php';
  267. $installed[] = @include_once INIT_PATH_LIBRARY . '/globals_frontend.php';
  268. // something could not be loaded
  269. if(in_array(false, $installed))
  270. {
  271. // installation folder
  272. $installer = dirname(__FILE__) . '/../install/cache';
  273. // Fork has not yet been installed
  274. if(file_exists($installer) && is_dir($installer) && !file_exists($installer . '/installed.txt'))
  275. {
  276. // redirect to installer
  277. header('Location: /install');
  278. }
  279. // we can nog load configuration file, however we can not run installer
  280. echo 'Required configuration files are missing. Try deleting current files, clearing your database, re-uploading <a href="http://www.fork-cms.be">Fork CMS</a> and <a href="/install">rerun the installer</a>.';
  281. exit;
  282. }
  283. }
  284. /**
  285. * Set debugging
  286. */
  287. private function setDebugging()
  288. {
  289. // debugging enabled
  290. if(SPOON_DEBUG)
  291. {
  292. // set error reporting as high as possible
  293. error_reporting(E_ALL | E_STRICT);
  294. // show errors on the screen
  295. ini_set('display_errors', 'On');
  296. // in debug mode notices are triggered when using non existing locale, so we use a custom errorhandler to cleanup the message
  297. set_error_handler(array('FrontendInit', 'errorHandler'));
  298. }
  299. // debugging disabled
  300. else
  301. {
  302. // set error reporting as low as possible
  303. error_reporting(0);
  304. // don't show error on the screen
  305. ini_set('display_errors', 'Off');
  306. // add callback for the spoon exceptionhandler
  307. switch($this->type)
  308. {
  309. case 'backend_ajax':
  310. define('SPOON_EXCEPTION_CALLBACK', __CLASS__ . '::exceptionAJAXHandler');
  311. break;
  312. case 'backend_js':
  313. define('SPOON_EXCEPTION_CALLBACK', __CLASS__ . '::exceptionJSHandler');
  314. break;
  315. default:
  316. define('SPOON_EXCEPTION_CALLBACK', __CLASS__ . '::exceptionHandler');
  317. }
  318. }
  319. }
  320. /**
  321. * Set include path
  322. */
  323. private function setIncludePath()
  324. {
  325. // prepend the libary and document_root to the existing include path
  326. set_include_path(PATH_LIBRARY . PATH_SEPARATOR . PATH_WWW . PATH_SEPARATOR . get_include_path());
  327. }
  328. }