dispatch.php 20 KB

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