setImageFormat($image->getNumberImages() > 1 ? 'gif' : 'png'); $image = $image->coalesceImages(); $width = $image->getImageWidth(); $height = $image->getImageHeight(); if ($width > $height) { $resize_width = $width * $target_height / $height; $resize_height = $target_height; } else { $resize_width = $target_width; $resize_height = $height * $target_width / $width; } do { $image->resizeImage( $resize_width, $resize_height, Imagick::FILTER_LANCZOS, 0.9 ); $image->cropImage( $target_width, $target_height, ($resize_width - $target_width) / 2, ($resize_height - $target_height) / 2 ); $image->setImagePage( $target_width, $target_height, 0, 0 ); } while ($image->nextImage()); return $image->deconstructImages(); } function running_on_windows(): bool { return starts_with(mb_strtolower(PHP_OS), 'win'); } function pdo_prepare_array_update(array $keys, bool $useKeys = false, string $format = '%s'): string { return pdo_prepare_array($keys, $useKeys, sprintf($format, '`%1$s` = :%1$s')); } function pdo_prepare_array(array $keys, bool $useKeys = false, string $format = '`%s`'): string { $parts = []; if ($useKeys) { $keys = array_keys($keys); } foreach ($keys as $key) { $parts[] = sprintf($format, $key); } return implode(', ', $parts); } function is_local_url(string $url): bool { $length = mb_strlen($url); if ($length < 1) { return false; } if ($url[0] === '/' && ($length > 1 ? $url[1] !== '/' : true)) { return true; } $prefix = 'http' . (empty($_SERVER['HTTPS']) ? '' : 's') . '://' . $_SERVER['HTTP_HOST'] . '/'; return starts_with($url, $prefix); } function render_error(int $code, string $template = 'errors.%d'): string { return render_info(null, $code, $template); } function render_info(?string $message, int $httpCode, string $template = 'errors.%d'): string { http_response_code($httpCode); try { tpl_var('http_code', $httpCode); if (mb_strlen($message)) { tpl_var('message', $message); } $template = sprintf($template, $httpCode); if (!tpl_exists($template)) { $template = 'errors.master'; } return tpl_render(sprintf($template, $httpCode)); } catch (Exception $ex) { echo $ex->getMessage(); return $message ?? ''; } } function render_info_or_json(bool $json, string $message, int $httpCode = 200, string $template = 'errors.%d'): string { $error = $httpCode >= 400; http_response_code($httpCode); if ($json) { return json_encode([($error ? 'error' : 'message') => $message, 'success' => $error]); } return render_info($message, $httpCode, $template); } function html_link(string $url, ?string $content = null, $attributes = []): string { $content = $content ?? $url; $attributes = array_merge( is_string($attributes) ? ['class' => $attributes] : $attributes, ['href' => $url] ); if (mb_strpos($url, '://') !== false) { $attributes['target'] = '_blank'; $attributes['rel'] = 'noreferrer noopener'; } $html = ' $value) { $value = str_replace('"', '\"', $value); $html .= " {$name}=\"{$value}\""; } $html .= ">{$content}"; return $html; } function html_colour(?int $colour, $attribs = '--user-colour'): string { $colour = $colour ?? colour_none(); if (is_string($attribs)) { $attribs = [ $attribs => '%s', ]; } if (!$attribs) { $attribs = [ 'color' => '%s', '--user-colour' => '%s', ]; } $css = ''; $value = colour_get_css($colour); foreach ($attribs as $name => $format) { $css .= $name . ':' . sprintf($format, $value) . ';'; } return $css; } function is_user_int($value): bool { return ctype_digit(strval($value)); } // https://secure.php.net/manual/en/function.base64-encode.php#103849 function base64url_encode(string $data): string { return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } function base64url_decode(string $data): string { return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); } function proxy_media_url(?string $url): ?string { if (empty($url) || !config_get_default(false, 'Proxy', 'enabled') || is_local_url($url)) { return $url; } $secret = config_get_default('insecure', 'Proxy', 'secret_key'); $encodedUrl = base64url_encode($url); $hash = hash_hmac('sha256', $encodedUrl, $secret); return "/proxy.php/{$hash}/{$encodedUrl}"; }