dispatch.php 21 KB

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