Просмотр файла htmly-2.9.8/system/includes/dispatch.php

Размер файла: 15.95Kb
  1. <?php
  2. if (!defined('PHP_VERSION_ID') || PHP_VERSION_ID < 50300) {
  3. error(500, 'dispatch requires at least PHP 5.3 to run.');
  4. }
  5.  
  6. function _log($message)
  7. {
  8. if (config('debug.enable') == true && php_sapi_name() !== 'cli') {
  9. $file = config('debug.log');
  10. $type = $file ? 3 : 0;
  11. error_log("{$message}\n", $type, $file);
  12. }
  13. }
  14.  
  15. function site_url()
  16. {
  17. if (config('multi.site') == "true" || config('site.url') == null){
  18. return rtrim(generateSiteUrl(), '/') . '/';
  19. } else {
  20. // Forcing the forward slash
  21. return rtrim(config('site.url'), '/') . '/';
  22. }
  23. }
  24.  
  25. function generateSiteUrl()
  26. {
  27. $dir = trim(dirname(substr($_SERVER["SCRIPT_FILENAME"], strlen($_SERVER["DOCUMENT_ROOT"]))), '/');
  28. if ($dir == '.' || $dir == '..') {
  29. $dir = '';
  30. }
  31. $port = '';
  32. if ($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443") {
  33. $port = ':' . $_SERVER["SERVER_PORT"];
  34. }
  35. $scheme = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https' : 'http';
  36. if ($dir === '') {
  37. return $siteUrl = $scheme . '://' . trim($_SERVER['SERVER_NAME'], "/") . $port . "/";
  38. }
  39. return $siteUrl = $scheme . '://' . trim($_SERVER['SERVER_NAME'], "/") . $port . "/" . $dir . '/';
  40. }
  41.  
  42. function site_path()
  43. {
  44. static $_path;
  45.  
  46. if (!$_path)
  47. $_path = rtrim(parse_url(site_url(), PHP_URL_PATH), '/');
  48.  
  49. return $_path;
  50. }
  51.  
  52. function theme_path()
  53. {
  54. if (config('views.root') == null)
  55. error(500, '[views.root] is not set');
  56.  
  57. return site_url() . rtrim(config('views.root'), '/') . '/';
  58. }
  59.  
  60. function error($code, $message)
  61. {
  62. @header("HTTP/1.0 {$code} {$message}", true, $code);
  63. die($message);
  64. }
  65.  
  66. // Set the language
  67. function get_language()
  68. {
  69. $langID = config('language');
  70. $langFile = 'lang/'. $langID . '.ini';
  71.  
  72. // Settings for the language
  73. if (file_exists($langFile)) {
  74. i18n('source', $langFile);
  75. setlocale(LC_ALL, $langID . '.utf8');
  76. } else {
  77. i18n('source', 'lang/en_US.ini'); // Load the English language file
  78. setlocale(LC_ALL, 'en_US.utf8'); // Change locale to English
  79. }
  80. }
  81.  
  82. // i18n provides strings in the current language
  83. function i18n($key, $value = null)
  84. {
  85. static $_i18n = array();
  86. $key = strtolower($key);
  87.  
  88. if ($key === 'source') {
  89. if (file_exists($value))
  90. $_i18n = parse_ini_file($value, true);
  91. else
  92. $_i18n = parse_ini_file('lang/en_US.ini', true);
  93. } elseif ($value == null)
  94. return (isset($_i18n[$key]) ? $_i18n[$key] : $key);
  95. else
  96. $_i18n[$key] = $value;
  97. }
  98.  
  99. function config($key, $value = null)
  100. {
  101. static $_config = array();
  102.  
  103. if ($key === 'source' && file_exists($value))
  104. $_config = parse_ini_file($value, true);
  105. elseif ($value == null)
  106. return (isset($_config[$key]) ? $_config[$key] : null);
  107. else
  108. $_config[$key] = $value;
  109. }
  110.  
  111. function save_config($data = array(), $new = array())
  112. {
  113. global $config_file;
  114.  
  115. $string = file_get_contents($config_file) . "\n";
  116.  
  117. foreach ($data as $word => $value) {
  118. $value = str_replace('"', '\"', $value);
  119. $string = preg_replace("/^" . $word . " = .+$/m", $word . ' = "' . $value . '"', $string);
  120. }
  121. $string = rtrim($string);
  122. foreach ($new as $word => $value) {
  123. $value = str_replace('"', '\"', $value);
  124. $string .= "\n" . $word . ' = "' . $value . '"' . "\n";
  125. }
  126. $string = rtrim($string);
  127. return file_put_contents($config_file, $string, LOCK_EX);
  128. }
  129.  
  130. function to_b64($str)
  131. {
  132. $str = base64_encode($str);
  133. $str = preg_replace('/\//', '_', $str);
  134. $str = preg_replace('/\+/', '.', $str);
  135. $str = preg_replace('/\=/', '-', $str);
  136. return trim($str, '-');
  137. }
  138.  
  139. function from_b64($str)
  140. {
  141. $str = preg_replace('/\_/', '/', $str);
  142. $str = preg_replace('/\./', '+', $str);
  143. $str = preg_replace('/\-/', '=', $str);
  144. $str = base64_decode($str);
  145. return $str;
  146. }
  147.  
  148. if (extension_loaded('mcrypt')) {
  149.  
  150. function encrypt($decoded, $algo = MCRYPT_RIJNDAEL_256, $mode = MCRYPT_MODE_CBC)
  151. {
  152. if (($secret = config('cookies.secret')) == null)
  153. error(500, '[cookies.secret] is not set');
  154.  
  155. $secret = mb_substr($secret, 0, mcrypt_get_key_size($algo, $mode));
  156. $iv_size = mcrypt_get_iv_size($algo, $mode);
  157. $iv_code = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
  158. $encrypted = to_b64(mcrypt_encrypt($algo, $secret, $decoded, $mode, $iv_code));
  159.  
  160. return sprintf('%s|%s', $encrypted, to_b64($iv_code));
  161. }
  162.  
  163. function decrypt($encoded, $algo = MCRYPT_RIJNDAEL_256, $mode = MCRYPT_MODE_CBC)
  164. {
  165. if (($secret = config('cookies.secret')) == null)
  166. error(500, '[cookies.secret] is not set');
  167.  
  168. $secret = mb_substr($secret, 0, mcrypt_get_key_size($algo, $mode));
  169. list($enc_str, $iv_code) = explode('|', $encoded);
  170. $enc_str = from_b64($enc_str);
  171. $iv_code = from_b64($iv_code);
  172. $enc_str = mcrypt_decrypt($algo, $secret, $enc_str, $mode, $iv_code);
  173.  
  174. return rtrim($enc_str, "\0");
  175. }
  176.  
  177. }
  178.  
  179. function set_cookie($name, $value, $expire = 31536000, $path = '/')
  180. {
  181. $value = (function_exists('encrypt') ? encrypt($value) : $value);
  182. setcookie($name, $value, time() + $expire, $path);
  183. }
  184.  
  185. function get_cookie($name)
  186. {
  187. $value = from($_COOKIE, $name);
  188.  
  189. if ($value)
  190. $value = (function_exists('decrypt') ? decrypt($value) : $value);
  191.  
  192. return $value;
  193. }
  194.  
  195. function delete_cookie()
  196. {
  197. $cookies = func_get_args();
  198. foreach ($cookies as $ck)
  199. setcookie($ck, '', -10, '/');
  200. }
  201.  
  202. // if we have APCu loaded, enable cache functions
  203. if (extension_loaded('apcu')) {
  204.  
  205. function cache($key, $func, $ttl = 0)
  206. {
  207. if (($data = apcu_fetch($key)) === false) {
  208. $data = call_user_func($func);
  209. if ($data !== null) {
  210. apcu_store($key, $data, $ttl);
  211. }
  212. }
  213. return $data;
  214. }
  215.  
  216. function cache_invalidate()
  217. {
  218. foreach (func_get_args() as $key) {
  219. apcu_delete($key);
  220. }
  221. }
  222.  
  223. }
  224.  
  225. function warn($name = null, $message = null)
  226. {
  227. static $warnings = array();
  228.  
  229. if ($name == '*')
  230. return $warnings;
  231.  
  232. if (!$name)
  233. return count(array_keys($warnings));
  234.  
  235. if (!$message)
  236. return isset($warnings[$name]) ? $warnings[$name] : null;
  237.  
  238. $warnings[$name] = $message;
  239. }
  240.  
  241. function _u($str)
  242. {
  243. return urlencode($str);
  244. }
  245.  
  246. function _h($str, $enc = 'UTF-8', $flags = ENT_QUOTES)
  247. {
  248. return htmlentities($str, $flags, $enc);
  249. }
  250.  
  251. function from($source, $name)
  252. {
  253. $map = array("\r\n" => "\n", "\r" => "\n");
  254. if (is_array($name)) {
  255. $data = array();
  256. foreach ($name as $k)
  257. $data[$k] = isset($source[$k]) ? trim(strtr($source[$k], $map)) : null;
  258. return $data;
  259. }
  260. return isset($source[$name]) ? trim(strtr($source[$name], $map)) : null;
  261. }
  262.  
  263. function stash($name, $value = null)
  264. {
  265. static $_stash = array();
  266.  
  267. if ($value === null)
  268. return isset($_stash[$name]) ? $_stash[$name] : null;
  269.  
  270. $_stash[$name] = $value;
  271.  
  272. return $value;
  273. }
  274.  
  275. function method($verb = null)
  276. {
  277. if ($verb == null || (strtoupper($verb) == strtoupper($_SERVER['REQUEST_METHOD'])))
  278. return strtoupper($_SERVER['REQUEST_METHOD']);
  279.  
  280. error(400, 'bad request');
  281. }
  282.  
  283. function client_ip()
  284. {
  285. if (isset($_SERVER['HTTP_CLIENT_IP']))
  286. return $_SERVER['HTTP_CLIENT_IP'];
  287. elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
  288. return $_SERVER['HTTP_X_FORWARDED_FOR'];
  289.  
  290. return $_SERVER['REMOTE_ADDR'];
  291. }
  292.  
  293. function redirect(/* $code_or_path, $path_or_cond, $cond */)
  294. {
  295. $argv = func_get_args();
  296. $argc = count($argv);
  297.  
  298. $path = null;
  299. $code = 302;
  300. $cond = true;
  301.  
  302. switch ($argc) {
  303. case 3:
  304. list($code, $path, $cond) = $argv;
  305. break;
  306. case 2:
  307. if (is_string($argv[0]) ? $argv[0] : $argv[1]) {
  308. $code = 302;
  309. $path = $argv[0];
  310. $cond = $argv[1];
  311. } else {
  312. $code = $argv[0];
  313. $path = $argv[1];
  314. }
  315. break;
  316. case 1:
  317. if (!is_string($argv[0]))
  318. error(500, 'bad call to redirect()');
  319. $path = $argv[0];
  320. break;
  321. default:
  322. error(500, 'bad call to redirect()');
  323. }
  324.  
  325. $cond = (is_callable($cond) ? !!call_user_func($cond) : !!$cond);
  326.  
  327. if (!$cond)
  328. return;
  329.  
  330. header('Location: ' . $path, true, $code);
  331. exit;
  332. }
  333.  
  334. function partial($view, $locals = null)
  335. {
  336. if (is_array($locals) && count($locals)) {
  337. extract($locals, EXTR_SKIP);
  338. }
  339.  
  340. if (($view_root = config('views.root')) == null)
  341. error(500, "[views.root] is not set");
  342.  
  343. $path = basename($view);
  344. $view = preg_replace('/' . $path . '$/', "_{$path}", $view);
  345. $view = "{$view_root}/{$view}.html.php";
  346.  
  347. if (file_exists($view)) {
  348. ob_start();
  349. require $view;
  350. return ob_get_clean();
  351. } else {
  352. error(500, "partial [{$view}] not found");
  353. }
  354.  
  355. return '';
  356. }
  357.  
  358. function content($value = null)
  359. {
  360. return stash('$content$', $value);
  361. }
  362.  
  363. function render($view, $locals = null, $layout = null)
  364. {
  365. if (!login()) {
  366. $c = str_replace('/', '#', str_replace('?', '~', rawurldecode($_SERVER['REQUEST_URI'])));
  367. $dir = 'cache/page';
  368. $cachefile = $dir . '/' . $c . '.cache';
  369. if (!is_dir($dir)) {
  370. mkdir($dir, 0775, true);
  371. }
  372. }
  373.  
  374. if (is_array($locals) && count($locals)) {
  375. extract($locals, EXTR_SKIP);
  376. }
  377.  
  378. if (($view_root = config('views.root')) == null)
  379. error(500, "[views.root] is not set");
  380.  
  381. $fnc = "{$view_root}/functions.php";
  382.  
  383. ob_start();
  384. if (file_exists($fnc)) {
  385. include $fnc;
  386. }
  387. include "{$view_root}/{$view}.html.php";
  388. content(trim(ob_get_clean()));
  389.  
  390. if ($layout !== false) {
  391. if ($layout == null) {
  392. $layout = config('views.layout');
  393. $layout = ($layout == null) ? 'layout' : $layout;
  394. }
  395. $layout = "{$view_root}/{$layout}.html.php";
  396. header('Content-type: text/html; charset=utf-8');
  397. if (config('generation.time') == 'true') {
  398. ob_start();
  399. require $layout;
  400. $time = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
  401. $total_time = round($time, 4);
  402. echo "\n" . '<!-- Dynamic page generated in '.$total_time.' seconds. -->';
  403. } else {
  404. ob_start();
  405. require $layout;
  406. }
  407. if (!login() && $view != '404' && $view != '404-search' && config('cache.off') == "false") {
  408. if (config('cache.timestamp') == 'true') {
  409. echo "\n" . '<!-- Cached page generated on '.date('Y-m-d H:i:s').' -->';
  410. }
  411. if (isset($cachefile))
  412. file_put_contents($cachefile, ob_get_contents(), LOCK_EX);
  413. }
  414. echo trim(ob_get_clean());
  415. } else {
  416. echo content();
  417. }
  418. }
  419.  
  420. function json($obj, $code = 200)
  421. {
  422. header('Content-type: application/json', true, $code);
  423. echo json_encode($obj);
  424. exit;
  425. }
  426.  
  427. function save_json_pretty($filename, $arr)
  428. {
  429. if (defined("JSON_PRETTY_PRINT")) {
  430. file_put_contents($filename, json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX);
  431. } else {
  432. file_put_contents($filename, json_encode($arr, JSON_UNESCAPED_UNICODE), LOCK_EX);
  433. }
  434. }
  435.  
  436. function file_get_data($filename)
  437. {
  438. $thisFile = fopen($filename, 'r');
  439. if (flock($thisFile, LOCK_SH)) {
  440. $fileData = file_get_contents($filename);
  441. flock($thisFile, LOCK_UN);
  442. } else {
  443. $fileData = json_encode(array('flock_fail' => 'reading'));
  444. }
  445. fclose($thisFile);
  446. return $fileData;
  447. }
  448.  
  449. function condition()
  450. {
  451. static $cb_map = array();
  452.  
  453. $argv = func_get_args();
  454. $argc = count($argv);
  455.  
  456. if (!$argc)
  457. error(500, 'bad call to condition()');
  458.  
  459. $name = array_shift($argv);
  460. $argc = $argc - 1;
  461.  
  462. if (!$argc && is_callable($cb_map[$name]))
  463. return call_user_func($cb_map[$name]);
  464.  
  465. if (is_callable($argv[0]))
  466. return ($cb_map[$name] = $argv[0]);
  467.  
  468. if (is_callable($cb_map[$name]))
  469. return call_user_func_array($cb_map[$name], $argv);
  470.  
  471. error(500, 'condition [' . $name . '] is undefined');
  472. }
  473.  
  474. function middleware($cb_or_path = null)
  475. {
  476. static $cb_map = array();
  477.  
  478. if ($cb_or_path == null || is_string($cb_or_path)) {
  479. foreach ($cb_map as $cb) {
  480. call_user_func($cb, $cb_or_path);
  481. }
  482. } else {
  483. array_push($cb_map, $cb_or_path);
  484. }
  485. }
  486.  
  487. function filter($sym, $cb_or_val = null)
  488. {
  489. static $cb_map = array();
  490.  
  491. if (is_callable($cb_or_val)) {
  492. $cb_map[$sym] = $cb_or_val;
  493. return;
  494. }
  495.  
  496. if (is_array($sym) && count($sym) > 0) {
  497. foreach ($sym as $s) {
  498. $s = substr($s, 1);
  499. if (isset($cb_map[$s]) && isset($cb_or_val[$s]))
  500. call_user_func($cb_map[$s], $cb_or_val[$s]);
  501. }
  502. return;
  503. }
  504.  
  505. error(500, 'bad call to filter()');
  506. }
  507.  
  508. function route_to_regex($route)
  509. {
  510. $route = preg_replace_callback('@:[\w]+@i', function ($matches) {
  511. $token = str_replace(':', '', $matches[0]);
  512. return '(?P<' . $token . '>[a-z0-9_\0-\.]+)';
  513. }, $route);
  514. return '@^' . rtrim($route, '/') . '$@i';
  515. }
  516.  
  517. function route($method, $pattern, $callback = null)
  518. {
  519. // callback map by request type
  520. static $route_map = array(
  521. 'GET' => array(),
  522. 'POST' => array()
  523. );
  524.  
  525. $method = strtoupper($method);
  526.  
  527. if (!in_array($method, array('GET', 'POST')))
  528. error(500, 'Only GET and POST are supported');
  529.  
  530. // a callback was passed, so we create a route defiition
  531. if ($callback !== null) {
  532.  
  533. // create a route entry for this pattern
  534. $route_map[$method][$pattern] = array(
  535. 'xp' => route_to_regex($pattern),
  536. 'cb' => $callback
  537. );
  538.  
  539. } else {
  540.  
  541.  
  542. // callback is null, so this is a route invokation. look up the callback.
  543. foreach ($route_map[$method] as $pat => $obj) {
  544.  
  545. // if the requested uri ($pat) has a matching route, let's invoke the cb
  546. if (!preg_match($obj['xp'], $pattern, $vals))
  547. continue;
  548.  
  549. // call middleware
  550. middleware($pattern);
  551.  
  552. // construct the params for the callback
  553. array_shift($vals);
  554. preg_match_all('@:([\w]+)@', $pat, $keys, PREG_PATTERN_ORDER);
  555. $keys = array_shift($keys);
  556. $argv = array();
  557.  
  558. foreach ($keys as $index => $id) {
  559. $id = substr($id, 1);
  560. if (isset($vals[$id])) {
  561. array_push($argv, trim(urldecode($vals[$id])));
  562. }
  563. }
  564.  
  565. // call filters if we have symbols
  566. if (count($keys)) {
  567. filter(array_values($keys), $vals);
  568. }
  569.  
  570. // if cb found, invoke it
  571. if (is_callable($obj['cb'])) {
  572. call_user_func_array($obj['cb'], $argv);
  573. }
  574.  
  575. // leave after first match
  576. break;
  577.  
  578. }
  579. }
  580.  
  581. }
  582.  
  583. function get($path, $cb)
  584. {
  585. route('GET', $path, $cb);
  586. }
  587.  
  588. function post($path, $cb)
  589. {
  590. route('POST', $path, $cb);
  591. }
  592.  
  593. function flash($key, $msg = null, $now = false)
  594. {
  595. static $x = array(),
  596. $f = null;
  597.  
  598. $f = (config('cookies.flash') ? config('cookies.flash') : '_F');
  599.  
  600. if ($c = get_cookie($f))
  601. $c = json_decode($c, true);
  602. else
  603. $c = array();
  604.  
  605. if ($msg == null) {
  606.  
  607. if (isset($c[$key])) {
  608. $x[$key] = $c[$key];
  609. unset($c[$key]);
  610. set_cookie($f, json_encode($c));
  611. }
  612.  
  613. return (isset($x[$key]) ? $x[$key] : null);
  614. }
  615.  
  616. if (!$now) {
  617. $c[$key] = $msg;
  618. set_cookie($f, json_encode($c));
  619. }
  620.  
  621. $x[$key] = $msg;
  622. }
  623.  
  624. function dispatch()
  625. {
  626. $path = $_SERVER['REQUEST_URI'];
  627.  
  628. if (config('site.url') !== null)
  629. $path = preg_replace('@^' . preg_quote(site_path()) . '@', '', $path);
  630.  
  631. $parts = preg_split('/\?/', $path, -1, PREG_SPLIT_NO_EMPTY);
  632.  
  633. $uri = trim($parts[0], '/');
  634. $uri = strlen($uri) ? $uri : 'index';
  635.  
  636. route(method(), "/{$uri}");
  637. }