299 lines
8.2 KiB
PHP
299 lines
8.2 KiB
PHP
<?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;
|
||
}
|