GET /hu/rolunk
/srv/phlo/functions.php:114
Class "page_about" not found
phlo() shop.php:104
shop->section() app.php:113
shop() app.php:120
app->controller() functions.php:116
phlo() phlo.php:23
phlo_app() phlo.php:8
phlo_app_jsonfile() app.php:5
  1. <?php
  2. function view(string $body = null, string $title = null, array|string $css = [], array|string $js = [], array|string $defer = [], array|string $options = [], array $settings = [], string $ns = null, bool $cache = false, ...$cmds){
  3. !async && isset($cmds['uri']) && $cmds['uri'] !== true && $cmds['uri'] !== req && location("/$cmds[uri]");
  4. $app = phlo('app');
  5. $title = title($title);
  6. $css = array_merge((array)$css, (array)$app->css);
  7. $js = array_merge((array)$js, (array)$app->js);
  8. $defer = array_merge((array)$defer, (array)$app->defer);
  9. $options = implode(space, array_merge((array)$options, (array)$app->options, debug ? ['debug'] : []));
  10. $settings = array_merge($settings, (array)$app->settings);
  11. if (async){
  12. if (isset($cmds['uri']) && $cmds['uri'] === true) $cmds['uri'] = req;
  13. $cmds['trans'] ??= true;
  14. $cmds['title'] = $title;
  15. $css && $cmds['css'] = $css;
  16. $js && $cmds['js'] = $js;
  17. $defer && $cmds['defer'] = $defer;
  18. $cmds['options'] = $options;
  19. $cmds['settings'] = $settings;
  20. !is_null($body) && $cmds['inner']['body'] = $body;
  21. $cache && $cmds['cache'] = $cache;
  22. apply(...$cmds);
  23. }
  24. $body ??= $cmds['main'] ?? void;
  25. !$cache && debug && $body .= lf.debug_render();
  26. $ns ??= $app->ns ?? 'app';
  27. $link = [];
  28. $head = tag('title', inner: $title).lf;
  29. $head .= '<meta name="viewport" content="'.($cmds['viewport'] ?? $app->viewport ?? 'width=device-width').'">'.lf;
  30. $app->description && $head .= "<meta name=\"description\" content=\"$app->description\">\n";
  31. $app->themeColor && $head .= "<meta name=\"theme-color\" content=\"$app->themeColor\">\n";
  32. $app->image && $head .= "<meta property=\"og:image\" content=\"$app->image\">\n";
  33. file_exists(www.$filename = 'favicon.ico') && $head .= "<link rel=\"favicon\" href=\"/$filename?".version."\">\n";
  34. file_exists(www.$filename = 'manifest.json') && $head .= "<link rel=\"manifest\" href=\"/$filename?".version."\">\n";
  35. file_exists(www.$filename = 'icons.png') && $link[] = "</$filename?".version.">; rel=preload; as=image";
  36. file_exists(www.$filename = "$ns.css") && [$link[] = "</$filename?".version.">; rel=preload; as=style", $head .= '<link rel="stylesheet" href="'.esc(slash.$filename.qm.version).'">'.lf];
  37. foreach ($css AS $item) $head .= '<link rel="stylesheet" href="'.esc($item).'">'.lf;
  38. file_exists(www.$filename = "$ns.js") && [$link[] = "</$ns.js?".version.">; rel=preload; as=script", $head .= '<script src="'.esc(slash.$filename.qm.version).'" defer></script>'.lf];
  39. foreach ($js AS $item) $head .= '<script src="'.esc($item).'"></script>'.lf;
  40. foreach ($defer AS $item) $head .= '<script src="'.esc($item).'" defer></script>'.lf;
  41. $app->head && $head .= $app->head;
  42. !build && $link && header('Link: '.implode(comma, $link), false);
  43. if ($lang = $cmds['lang'] ?? $app->lang ?? 'en') unset($cmds['lang']);
  44. $bodyAttrs = void;
  45. $options && $bodyAttrs .= " class=\"$options\"";
  46. $settings && $bodyAttrs .= loop($settings, fn($value, $key) => ' data-'.$key.'="'.esc($value).'"', void);
  47. $DOM = DOM($body, $head, $lang, $bodyAttrs);
  48. if ($cache){
  49. apcu_store($key = host.slash.req, $DOM, 3600);
  50. debug("W: $key:string:".strlen($DOM));
  51. $DOM = strtr($DOM, ['</body>' => debug_render().lf.'</body>']);
  52. }
  53. die($DOM);
  54. }
  55. //Output instructions or start an output stream
  56. function apply(...$cmds){
  57. cli || phlo('app')->streaming || [header('Content-Type: application/json'), header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0'), header('Pragma: no-cache')];
  58. if (isset($cmds['cache'])){
  59. unset($cmds['cache']);
  60. apcu_store($key = host.'/async/'.req, $cmds, 3600);
  61. debug("W: $key (".count($cmds).")");
  62. }
  63. debug && $cmds = debug_apply($cmds);
  64. die(json_encode($cmds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK));
  65. }
  66. function chunk(...$cmds){
  67. static $header;
  68. $header ??= first(true, cli || [header('Content-Type: text/event-stream'), phlo('app')->streaming = true]);
  69. echo json_encode($cmds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK).lf;
  70. cli || [ob_flush(), flush()];
  71. }
  72. function output($content = void, $filename = null, $attachment = false){
  73. header('Content-Type: '.mime($filename ?? basename(req)));
  74. header('Content-Length: '.strlen($content));
  75. if ($filename || $attachment) header('Content-Disposition: '.($attachment ? 'attachment' : 'inline').';filename='.rawurlencode($filename ?: basename(req)));
  76. echo $content;
  77. exit;
  78. }
  79. // HTML tag functions
  80. function DOM($body = void, $head = void, $lang = 'en', $bodyAttrs = void){ return "<!DOCTYPE html>\n<html lang=\"$lang\">\n<head>\n$head</head>\n<body$bodyAttrs>\n$body\n</body>\n</html>"; }
  81. function tag($tagName, ...$args){
  82. if (isset($args['inner'])){
  83. $end = "$args[inner]</$tagName>";
  84. unset($args['inner']);
  85. }
  86. else $end = void;
  87. return "<$tagName".loop(array_filter($args, fn($value) => !is_null($value)), fn($value, $key) => space.strtr($key, [us => dash]).($value === true ? void : '="'.esc($value).'"'), void).">$end";
  88. }
  89. function button(...$args){ return tag('button', ...$args); }
  90. function input(...$args){ return tag('input', ...$args); }
  91. function select(...$args){ return tag('select', ...$args); }
  92. function textarea(...$args){ return tag('textarea', ...$args); }
  93. function title(...$args){ return loop(array_filter($args), fn($title) => "$title - ", void).phlo('app')->title ?: 'Phlo '.phlo; }
  94. function error(string $msg){
  95. if (cli) die("$msg\n");
  96. if (async) apply(error: $msg);
  97. die(DOM(strtr(esc($msg), [lf => br])).lf);
  98. }
  99. //Handle Phlo object instances
  100. function phlo(string $phloName = null, ...$args){
  101. static $list = [];
  102. if (is_null($phloName)) return array_keys($list);
  103. $phloName = strtr($phloName, [slash => us]);
  104. $handle = method_exists($phloName, '__handle') ? $phloName::__handle(...$args) : ($args ? null : $phloName);
  105. if ($handle === true){
  106. if (isset($list[$phloName])) return $list[$phloName]->objImport(...$args);
  107. $handle = $phloName;
  108. }
  109. elseif ($handle && isset($list[$handle])) return $list[$handle];
  110. $phlo = new $phloName(...$args);
  111. if ($handle) $list[$handle] = $phlo;
  112. if ($phlo->hasMethod('controller') && (!cli || $phloName !== 'app')) $phlo->controller();
  113. return $phlo;
  114. }
  115. //Phlo execution functions
  116. function phlo_exec($path, $obj, $call, $sync = true, ...$args){ return last(exec('/usr/bin/php '.rtrim($path, slash).'/app.php '.$obj.space.$call.loop($args, fn($arg) => str_contains($arg, space) || str_contains($arg, dq) || str_contains($arg, sq) ? ' "'.strtr($arg, [dq => bs.dq]).'"' : space.$arg, void).($sync ? void : ' > /dev/null 2>&1 &'), $res), $sync ? implode(lf, $res) : true); }
  117. function phlo_sync($obj, $call, ...$args){ return phlo_exec(www, $obj, $call, true, ...$args); }
  118. function phlo_async($obj, $call, ...$args){ return phlo_exec(www, $obj, $call, false, ...$args); }
  119. function phlo_exists($obj){ return file_exists(php.strtr($obj, [us => dot]).'.php'); }
  120. // Obj/array generator functions
  121. function arr(...$array){ return $array; }
  122. function obj(...$data){ return new obj(...$data); }
  123. function HTTP(string $url, array $headers = [], bool $JSON = false, array $POST = null, array $PUT = null, bool $DELETE = false){
  124. $curl = curl_init($url);
  125. if ($POST || $PUT){
  126. if ($POST && $method = 'POST') $content = $POST;
  127. elseif ($PUT && $method = 'PUT') $content = $PUT;
  128. curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
  129. if ($JSON) array_push($headers, 'Content-Type: application/json', 'Content-Length: '.strlen($content = json_encode($content)));
  130. curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
  131. }
  132. elseif ($DELETE) curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
  133. curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  134. curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
  135. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  136. return curl_exec($curl);
  137. }
  138. //APCu cache function
  139. function apcu($key, $cb, $duration = 3600, bool $log = true){ return first($value = apcu_entry($key, $cb, $duration), $log && debug('C: '.(strlen($key) > 58 ? substr($key, 0, 55).'...' : $key).(is_array($value) ? ' ('.count($value).')' : (is_numeric($value) ? ":$value" : (is_string($value) ? ':string:'.strlen($value) : colon.gettype($value)))))); }
  140. //JSON functions
  141. function json_read($file, $assoc = null){ return json_decode(file_get_contents($file), $assoc) ?? error('Error reading '.esc($file)); }
  142. function json_write($file, $data, $flags = null){ return file_put_contents($file, json_encode($data, $flags ?? jsonFlags)); }
  143. // Argument handling functions
  144. function first(...$args){ return current($args); }
  145. function last(...$args){ return end($args); }
  146. // Time functions
  147. function age(int $time){ return time() - $time; }
  148. function age_human(int $age){
  149. foreach (arr(seconds: 60, minutes: 60, hours: 24, days: 7, weeks: 4, months: 13, years: 1) AS $range => $multiplier){
  150. if ($age / $multiplier < 1.66) break;
  151. $age /= $multiplier;
  152. }
  153. return ($rounded = (int)round($age)).space.substr($range, 0, strlen($range) + -($rounded === 1));
  154. }
  155. function duration(int $decimals = 4){ return ltrim(round($duration = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], $decimals), 0).'s'.($duration < .5 ? ' ('.round(1 / $duration).'/s)' : void); }
  156. function time_human(int $time){ return age_human(time() - $time); }
  157. // Generic functions
  158. function active(bool $cond, string $classList = void){ return $cond || $classList ? ' class="'.$classList.($cond ? ($classList ? space : void).'active' : void).'"' : void; }
  159. function camel($text){ return lcfirst(str_replace(space, void, ucwords(strtolower($text)))); }
  160. function create($items, Closure $keyCb, Closure $valueCb = null){ return array_combine(loop($items, $keyCb), $valueCb ? loop($items, $valueCb) : $items); }
  161. function debug(string $msg = null){
  162. if (!debug) return;
  163. static $debug = [];
  164. if (!$msg) return debug ? $debug : null;
  165. $debug[] = substr($msg, 0, 160);
  166. }
  167. function esc($string){ return htmlspecialchars((string)$string); }
  168. function files(string|array $paths, string $ext = '*.*'){ return array_merge(...loop((array)$paths, fn($path) => glob("$path$ext"))); }
  169. function iif($condition, $true, $false = null){ return $condition ? ($true instanceof Closure ? $true() : $true) : ($false instanceof Closure ? $false() : $false); }
  170. function indent(string $string, int $depth = 1){ return ($tab = str_repeat(tab, $depth)).rtrim(strtr($string, [lf => lf.$tab]), tab); }
  171. function indentView(string $string, int $depth = 1){ return last($tab = str_repeat(tab, $depth), rtrim(preg_replace('/\n(\t*)</', "\n$1$tab<", $string), tab)); }
  172. function left($string, $length){ return substr($string, 0, $length); }
  173. function location(string $location = null){ async ? apply(location: $location ?? true) : [header('Location: '.($location ?? ($_SERVER['HTTP_REFERER'] ?? slash))), exit]; }
  174. function loop(iterable $data, closure|array $cb, string $implode = null){
  175. $return = [];
  176. $isArray = is_array($cb);
  177. foreach ($data AS $key => $value) $return[$key] = $isArray ? $cb[0]->{$cb[1]}($value, $key) : $cb($value, $key);
  178. return is_null($implode) ? $return : implode($implode, $return);
  179. }
  180. function mime($filename){ return ['html' => 'text/html', 'css' => 'text/css', 'gif' => 'image/gif', 'ico' => 'image/x-icon', 'ini' => 'text/plain', 'js' => 'application/javascript', 'json' => 'application/json', 'jpg' => 'image/jpeg', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'ogg' => 'audio/ogg', 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', 'pdf' => 'application/pdf', 'phlo' => 'application/phlo', 'php' => 'application/x-httpd-php', 'png' => 'image/png', 'svg' => 'image/svg+xml', 'txt' => 'text/plain'][pathinfo($filename, PATHINFO_EXTENSION)] ?? 'application/octet-stream'; }
  181. function regex(string $pattern, string $subject, int $flags = 0, int $offset = 0):array { return last(str_starts_with($pattern, slash) || $pattern = "/$pattern/", preg_match($pattern, $subject, $match, $flags, $offset) ? $match : []); }
  182. function regex_all(string $pattern, string $subject, int $flags = 0, int $offset = 0):array { return last(str_starts_with($pattern, slash) || $pattern = "/$pattern/", preg_match_all($pattern, $subject, $matches, $flags, $offset) ? $matches : []); }
  183. function right($string, $length){ return substr($string, -$length); }
  184. function req(int $index, $length = null){
  185. static $parts;
  186. $parts ??= explode(slash, req);
  187. return is_null($length) ? ($parts[$index] ?? null) : (implode(slash, array_slice($parts, $index, $length < 0 ? null : $length)) ?: null);
  188. }
  189. function route(string $method = null, string $path = void, bool $async = null, string $data = null, string $cb = null){
  190. if ($method && $method !== method) return;
  191. if (!is_null($async) && $async !== async) return;
  192. if ($data && phlo('payload')->objKeys !== explode(comma, $data)) return;
  193. $req = array_filter(explode(slash, req));
  194. $cbArgs = [];
  195. $index = -1;
  196. foreach (array_filter(explode(space, $path)) AS $index => $item){
  197. $reqItem = req($index);
  198. if (strpos($item, '$') === 0){
  199. $item = substr($item, 1);
  200. if (str_ends_with($item, '=*')){
  201. $cbArgs[substr($item, 0, -2)] = implode(slash, array_slice($req, $index));
  202. $index = count($req) - 1;
  203. break;
  204. }
  205. elseif (str_ends_with($item, qm)){
  206. $item = substr($item, 0, -1);
  207. if ($reqItem && $item !== $reqItem) return;
  208. $reqItem = $item === $reqItem;
  209. }
  210. elseif (strpos($item, '=')){
  211. list ($item, $default) = explode('=', $item, 2);
  212. $default = $default ?: null;
  213. }
  214. elseif (is_null($reqItem)) return;
  215. if (strpos($item, dot) && (list ($item, $length) = explode(dot, $item, 2)) && strlen($reqItem) != $length) return false;
  216. if (strpos($item, ':')){
  217. (list ($item, $list) = explode(':', $item, 2)) && $list = explode(comma, $list);
  218. if (!$reqItem || in_array($reqItem, $list)) $cbArgs[$item] = $reqItem ?: $default;
  219. else return;
  220. }
  221. else $cbArgs[$item] = $reqItem ?? $default;
  222. }
  223. elseif ($item !== $reqItem) return;
  224. }
  225. if (isset($req[$index + 1])) return;
  226. if (!$cb) return obj(...$cbArgs);
  227. if ($cb(...$cbArgs) === false) return;
  228. exit;
  229. }
  230. function size_human(int $size, int $precision = 0){
  231. foreach (['b', 'Kb', 'Mb', 'Gb', 'Tb'] AS $range){
  232. if ($size / 1024 < 1) break;
  233. $size /= 1024;
  234. }
  235. return round($size, $precision).$range;
  236. }
  237. function slug(string $text){ return strtolower(strtr(iconv('UTF-8', 'ASCII//TRANSLIT', $text), [space => dash])); }
  238. function token(int $length){
  239. $token = void;
  240. while (strlen($token) < $length) $token .= chr(rand(97, 122));
  241. return $token;
  242. }
  243. function whitelist(...$IPs){ return cli || in_array($_SERVER['REMOTE_ADDR'], $IPs); }