diff options
Diffstat (limited to 'functions.php')
-rw-r--r-- | functions.php | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/functions.php b/functions.php new file mode 100644 index 0000000..9f62f32 --- /dev/null +++ b/functions.php @@ -0,0 +1,298 @@ +<?php + +function htmlescape(string|array $s): string|array { + if (is_array($s)) { + foreach ($s as $k => $v) { + $s[$k] = htmlescape($v); + } + return $s; + } + return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); +} + +function strtrim(string $str, int $len, bool &$trimmed): string { + if (mb_strlen($str) > $len) { + $str = mb_substr($str, 0, $len); + $trimmed = true; + } else { + $trimmed = false; + } + return $str; +} + +function sizeString(int $size): string { + $ks = array('B', 'KiB', 'MiB', 'GiB'); + foreach ($ks as $i => $k) { + if ($size < pow(1024, $i + 1)) { + if ($i == 0) + return $size . ' ' . $k; + return round($size / pow(1024, $i), 2).' '.$k; + } + } + return $size; +} + +function extension(string $name): string { + $expl = explode('.', $name); + return end($expl); +} + +/** + * @param string $filename + * @return resource|bool + */ +function imageopen(string $filename) { + $size = getimagesize($filename); + $types = [ + 1 => 'gif', + 2 => 'jpeg', + 3 => 'png' + ]; + if (!$size || !isset($types[$size[2]])) + return null; + return call_user_func('imagecreatefrom'.$types[$size[2]], $filename); +} + +function detect_image_type(string $filename) { + $size = getimagesize($filename); + $types = [ + 1 => 'gif', + 2 => 'jpg', + 3 => 'png' + ]; + if (!$size || !isset($types[$size[2]])) + return false; + return $types[$size[2]]; +} + +function transliterate(string $string): string { + $roman = array( + 'Sch', 'sch', 'Yo', 'Zh', 'Kh', 'Ts', 'Ch', 'Sh', 'Yu', 'ya', 'yo', + 'zh', 'kh', 'ts', 'ch', 'sh', 'yu', 'ya', 'A', 'B', 'V', 'G', 'D', 'E', + 'Z', 'I', 'Y', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', + '', 'Y', '', 'E', 'a', 'b', 'v', 'g', 'd', 'e', 'z', 'i', 'y', 'k', + 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f', '', 'y', '', 'e' + ); + $cyrillic = array( + 'Щ', 'щ', 'Ё', 'Ж', 'Х', 'Ц', 'Ч', 'Ш', 'Ю', 'я', 'ё', 'ж', 'х', 'ц', + 'ч', 'ш', 'ю', 'я', 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'З', 'И', 'Й', 'К', + 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Ь', 'Ы', 'Ъ', 'Э', + 'а', 'б', 'в', 'г', 'д', 'е', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', + 'п', 'р', 'с', 'т', 'у', 'ф', 'ь', 'ы', 'ъ', 'э' + ); + return str_replace($cyrillic, $roman, $string); +} + +/** + * @param resource $img + * @param ?int $w + * @param ?int $h + * @param ?int[] $transparent_color + */ +function imageresize(&$img, ?int $w = null, ?int $h = null, ?array $transparent_color = null) { + assert(is_int($w) || is_int($h)); + + $curw = imagesx($img); + $curh = imagesy($img); + + if (!is_int($w) && is_int($h)) { + $w = round($curw / ($curw / $w)); + } else if (is_int($w) && !is_int($h)) { + $h = round($curh / ($curh / $h)); + } + + $img2 = imagecreatetruecolor($w, $h); + if (is_array($transparent_color)) { + list($r, $g, $b) = $transparent_color; + $col = imagecolorallocate($img2, $r, $g, $b); + imagefilledrectangle($img2, 0, 0, $w, $h, $col); + } else { + imagealphablending($img2, false); + imagesavealpha($img2, true); + imagefilledrectangle($img2, 0, 0, $w, $h, imagecolorallocatealpha($img2, 255, 255, 255, 127)); + } + + imagecopyresampled($img2, $img, 0, 0, 0, 0, $w, $h, $curw, $curh); + imagedestroy($img); + + $img = $img2; +} + +function rrmdir(string $dir, bool $dont_delete_dir = false): bool { + if (!is_dir($dir)) { + logError('rrmdir: '.$dir.' is not a directory'); + return false; + } + + $objects = scandir($dir); + foreach ($objects as $object) { + if ($object != '.' && $object != '..') { + if (is_dir($dir.'/'.$object)) { + rrmdir($dir.'/'.$object); + } else { + unlink($dir.'/'.$object); + } + } + } + + if (!$dont_delete_dir) + rmdir($dir); + + return true; +} + +function ip2ulong(string $ip): int { + return sprintf("%u", ip2long($ip)); +} + +function ulong2ip(int $ip): string { + $long = 4294967295 - ($ip - 1); + return long2ip(-$long); +} + +function from_camel_case(string $s): string { + $buf = ''; + $len = strlen($s); + for ($i = 0; $i < $len; $i++) { + if (!ctype_upper($s[$i])) { + $buf .= $s[$i]; + } else { + $buf .= '_'.strtolower($s[$i]); + } + } + return $buf; +} + +function to_camel_case(string $input, string $separator = '_'): string { + return lcfirst(str_replace($separator, '', ucwords($input, $separator))); +} + +function str_replace_once(string $needle, string $replace, string $haystack) { + $pos = strpos($haystack, $needle); + if ($pos !== false) + $haystack = substr_replace($haystack, $replace, $pos, strlen($needle)); + return $haystack; +} + +function strgen(int $len): string { + $buf = ''; + for ($i = 0; $i < $len; $i++) { + $j = mt_rand(0, 61); + if ($j >= 36) { + $j += 13; + } else if ($j >= 10) { + $j += 7; + } + $buf .= chr(48 + $j); + } + return $buf; +} + +function sanitize_filename(string $name): string { + $name = mb_strtolower($name); + $name = transliterate($name); + $name = preg_replace('/[^\w\d\-_\s.]/', '', $name); + $name = preg_replace('/\s+/', '_', $name); + return $name; +} + +function glob_escape(string $pattern): string { + if (strpos($pattern, '[') !== false || strpos($pattern, ']') !== false) { + $placeholder = uniqid(); + $replaces = array( $placeholder.'[', $placeholder.']', ); + $pattern = str_replace( array('[', ']', ), $replaces, $pattern); + $pattern = str_replace( $replaces, array('[[]', '[]]', ), $pattern); + } + return $pattern; +} + +/** + * Does not support flag GLOB_BRACE + * + * @param string $pattern + * @param int $flags + * @return array + */ +function glob_recursive(string $pattern, int $flags = 0): array { + $files = glob(glob_escape($pattern), $flags); + foreach (glob(glob_escape(dirname($pattern)).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) { + $files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags)); + } + return $files; +} + +function setperm(string $file): void { + global $config; + + // chgrp + $gid = filegroup($file); + if ($gid != $config['group']) { + if (!chgrp($file, $config['group'])) { + logError(__FUNCTION__.": chgrp() failed on $file"); + } + } + + // chmod + $perms = fileperms($file); + $need_perms = is_dir($file) ? $config['dirs_mode'] : $config['files_mode']; + if (($perms & $need_perms) !== $need_perms) { + if (!chmod($file, $need_perms)) { + logError(__FUNCTION__.": chmod() failed on $file"); + } + } +} + +function salt_password(string $pwd): string { + global $config; + return hash('sha256', "{$pwd}|{$config['password_salt']}"); +} + +function exectime(?string $format = null) { + $time = round(microtime(true) - START_TIME, 4); + if (!is_null($format)) + $time = sprintf($format, $time); + return $time; +} + +function fullURL(string $url): string { + global $config; + return 'https://'.$config['domain'].$url; +} + +function getDb(): SQLiteConnection|MySQLConnection|null { + global $config; + static $link = null; + if (!is_null($link)) + return $link; + + switch ($config['db']['type']) { + case 'mysql': + $link = new MySQLConnection( + $config['db']['host'], + $config['db']['user'], + $config['db']['password'], + $config['db']['database']); + if (!$link->connect()) { + if (PHP_SAPI != 'cli') { + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + header('Retry-After: 300'); + die('database connection failed'); + } else { + fwrite(STDERR, 'database connection failed'); + exit(1); + } + } + break; + + case 'sqlite': + $link = new SQLiteConnection($config['db']['path']); + break; + + default: + logError('invalid database type'); + break; + } + + return $link; +} |