From 073389c964d6afd5cfeb854c3c0479c210bb3c24 Mon Sep 17 00:00:00 2001 From: flashwave Date: Sat, 24 Mar 2018 05:31:42 +0100 Subject: [PATCH] Add avatar uploading. --- assets/less/mio/classes/input/upload.less | 7 + assets/less/mio/classes/settings/avatar.less | 20 +++ assets/less/mio/classes/settings/content.less | 4 + assets/less/mio/main.less | 2 + composer.json | 2 + composer.lock | 62 ++++----- misuzu.php | 11 +- public/images/no-avatar.png | Bin 0 -> 72465 bytes public/profile.php | 56 ++++++-- public/settings.php | 122 +++++++++++++++++- src/Application.php | 43 ++++++ src/IO/Directory.php | 50 ++++++- src/IO/File.php | 23 ++++ src/IO/FileStream.php | 16 +-- src/IO/NetworkStream.php | 16 +-- src/IO/Stream.php | 16 +-- utility.php | 47 +++++++ views/mio/master.twig | 2 +- views/mio/settings/avatar.twig | 21 ++- views/mio/user/view.twig | 2 +- views/nova/user/view.twig | 2 +- 21 files changed, 450 insertions(+), 74 deletions(-) create mode 100644 assets/less/mio/classes/input/upload.less create mode 100644 assets/less/mio/classes/settings/avatar.less create mode 100644 public/images/no-avatar.png diff --git a/assets/less/mio/classes/input/upload.less b/assets/less/mio/classes/input/upload.less new file mode 100644 index 00000000..a8d8bb71 --- /dev/null +++ b/assets/less/mio/classes/input/upload.less @@ -0,0 +1,7 @@ +.mio__input__upload { + display: none; + + &__label { + .mio__input__button(); + } +} diff --git a/assets/less/mio/classes/settings/avatar.less b/assets/less/mio/classes/settings/avatar.less new file mode 100644 index 00000000..a0705aee --- /dev/null +++ b/assets/less/mio/classes/settings/avatar.less @@ -0,0 +1,20 @@ +.mio__settings__avatar { + display: flex; + min-height: 200px; + justify-content: space-between; + + &__form { + display: block; + margin-bottom: 2px; + } + + &__forms { + text-align: center; + flex-grow: 1; + } + + &__preview { + flex-grow: 1; + flex-shrink: 0; + } +} diff --git a/assets/less/mio/classes/settings/content.less b/assets/less/mio/classes/settings/content.less index 27acb44f..70ca7989 100644 --- a/assets/less/mio/classes/settings/content.less +++ b/assets/less/mio/classes/settings/content.less @@ -2,4 +2,8 @@ &--account { margin: 1px; } + + &--avatar { + margin: 2px; + } } diff --git a/assets/less/mio/main.less b/assets/less/mio/main.less index d3550205..0c4e79ad 100644 --- a/assets/less/mio/main.less +++ b/assets/less/mio/main.less @@ -36,6 +36,7 @@ body { @import "classes/input/button"; @import "classes/input/text"; @import "classes/input/textarea"; +@import "classes/input/upload"; // Base styles @import "classes/avatar"; @@ -52,6 +53,7 @@ body { @import "classes/settings/content"; @import "classes/settings/errors"; @import "classes/settings/account"; +@import "classes/settings/avatar"; // Forums @import "classes/forum/listing"; diff --git a/composer.json b/composer.json index b6cac299..09dffd1c 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,9 @@ "require": { "php": ">=7.2", "ext-bcmath": "*", + "ext-imagick": "*", "ext-mbstring": "*", + "ext-redis": "*", "twig/twig": "~2.4", "nesbot/carbon": "~1.22", "illuminate/database": "~5.5", diff --git a/composer.lock b/composer.lock index 43ec0abb..9a5474fe 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "bfc5b8cbdbf22514c4b51ae1af8c333b", + "content-hash": "2a199e9d03d4a7caedecbe72d7ea6b35", "packages": [ { "name": "composer/ca-bundle", @@ -696,7 +696,7 @@ }, { "name": "illuminate/container", - "version": "v5.6.11", + "version": "v5.6.12", "source": { "type": "git", "url": "https://github.com/illuminate/container.git", @@ -740,7 +740,7 @@ }, { "name": "illuminate/contracts", - "version": "v5.6.11", + "version": "v5.6.12", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -784,16 +784,16 @@ }, { "name": "illuminate/database", - "version": "v5.6.11", + "version": "v5.6.12", "source": { "type": "git", "url": "https://github.com/illuminate/database.git", - "reference": "4d2fc3c816ed402fcac290e6ca7bc855d5313000" + "reference": "104cd99c17d46e6f96eafd4f1469ea921a289279" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/database/zipball/4d2fc3c816ed402fcac290e6ca7bc855d5313000", - "reference": "4d2fc3c816ed402fcac290e6ca7bc855d5313000", + "url": "https://api.github.com/repos/illuminate/database/zipball/104cd99c17d46e6f96eafd4f1469ea921a289279", + "reference": "104cd99c17d46e6f96eafd4f1469ea921a289279", "shasum": "" }, "require": { @@ -839,11 +839,11 @@ "orm", "sql" ], - "time": "2018-03-09T13:55:05+00:00" + "time": "2018-03-14T12:21:13+00:00" }, { "name": "illuminate/filesystem", - "version": "v5.6.11", + "version": "v5.6.12", "source": { "type": "git", "url": "https://github.com/illuminate/filesystem.git", @@ -894,7 +894,7 @@ }, { "name": "illuminate/pagination", - "version": "v5.6.11", + "version": "v5.6.12", "source": { "type": "git", "url": "https://github.com/illuminate/pagination.git", @@ -938,30 +938,30 @@ }, { "name": "illuminate/support", - "version": "v5.6.11", + "version": "v5.6.12", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "259f6f17a11b0379340ec5311fcba27bc2a04070" + "reference": "f0776f5bbfeeb9d4c4cac8f64d96f8f0cbe4f3f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/259f6f17a11b0379340ec5311fcba27bc2a04070", - "reference": "259f6f17a11b0379340ec5311fcba27bc2a04070", + "url": "https://api.github.com/repos/illuminate/support/zipball/f0776f5bbfeeb9d4c4cac8f64d96f8f0cbe4f3f7", + "reference": "f0776f5bbfeeb9d4c4cac8f64d96f8f0cbe4f3f7", "shasum": "" }, "require": { "doctrine/inflector": "~1.1", "ext-mbstring": "*", "illuminate/contracts": "5.6.*", - "nesbot/carbon": "^1.20", + "nesbot/carbon": "^1.24.1", "php": "^7.1.3" }, "conflict": { "tightenco/collect": "<5.5.33" }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (5.2.*).", + "illuminate/filesystem": "Required to use the composer class (5.6.*).", "symfony/process": "Required to use the composer class (~4.0).", "symfony/var-dumper": "Required to use the dd function (~4.0)." }, @@ -991,7 +991,7 @@ ], "description": "The Illuminate Support package.", "homepage": "https://laravel.com", - "time": "2018-03-09T16:52:54+00:00" + "time": "2018-03-14T12:56:14+00:00" }, { "name": "maxmind-db/reader", @@ -1097,16 +1097,16 @@ }, { "name": "nesbot/carbon", - "version": "1.24.2", + "version": "1.25.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "bba6c6e410c6b4317e37a9474aeaa753808c3875" + "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/bba6c6e410c6b4317e37a9474aeaa753808c3875", - "reference": "bba6c6e410c6b4317e37a9474aeaa753808c3875", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4", + "reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4", "shasum": "" }, "require": { @@ -1146,7 +1146,7 @@ "datetime", "time" ], - "time": "2018-03-10T10:10:14+00:00" + "time": "2018-03-19T15:50:49+00:00" }, { "name": "psr/container", @@ -1478,16 +1478,16 @@ }, { "name": "twig/twig", - "version": "v2.4.6", + "version": "v2.4.7", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "d2117ec118c1ff3d28ccddca8212d82787a4809f" + "reference": "69aacd44dbbaa3199d5afb68605c996d577896fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/d2117ec118c1ff3d28ccddca8212d82787a4809f", - "reference": "d2117ec118c1ff3d28ccddca8212d82787a4809f", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/69aacd44dbbaa3199d5afb68605c996d577896fc", + "reference": "69aacd44dbbaa3199d5afb68605c996d577896fc", "shasum": "" }, "require": { @@ -1496,8 +1496,8 @@ }, "require-dev": { "psr/container": "^1.0", - "symfony/debug": "~2.7", - "symfony/phpunit-bridge": "~3.3@dev" + "symfony/debug": "^2.7", + "symfony/phpunit-bridge": "^3.3" }, "type": "library", "extra": { @@ -1540,7 +1540,7 @@ "keywords": [ "templating" ], - "time": "2018-03-03T16:23:01+00:00" + "time": "2018-03-20T04:31:17+00:00" } ], "packages-dev": [ @@ -3010,7 +3010,9 @@ "platform": { "php": ">=7.2", "ext-bcmath": "*", - "ext-mbstring": "*" + "ext-imagick": "*", + "ext-mbstring": "*", + "ext-redis": "*" }, "platform-dev": [] } diff --git a/misuzu.php b/misuzu.php index 61db05fa..af98739a 100644 --- a/misuzu.php +++ b/misuzu.php @@ -10,11 +10,20 @@ $app = Application::start( $app->startDatabase(); if (PHP_SAPI !== 'cli') { + $storage_dir = $app->getStoragePath(); + if (!$storage_dir->isReadable() + || !$storage_dir->isWritable()) { + echo 'Cannot access storage directory.'; + exit; + } + if (isset($_COOKIE['msz_uid'], $_COOKIE['msz_sid'])) { $app->startSession((int)$_COOKIE['msz_uid'], $_COOKIE['msz_sid']); } - //ob_start('ob_gzhandler'); + if (!$app->inDebugMode()) { + ob_start('ob_gzhandler'); + } $app->startTemplating(); } diff --git a/public/images/no-avatar.png b/public/images/no-avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..f08da9e1ed40457e2a9b62f2d18df5dbba5abcbd GIT binary patch literal 72465 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≻bn}hYv$X2)Sks0DNEFNrM@P?EUU{zl%!c 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

W%*C!iKTZoSvM8bI^udnf`~|2)GE5x84ZqDVw}c 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['profile' => User::findOrFail($user_id)]); -} catch (Exception $ex) { - http_response_code(404); - echo $app->templating->render('user.notfound'); - return; +switch ($mode) { + case 'avatar': + $avatar_filename = $app->getPath( + $app->config->get('Avatar', 'default_path', 'string', 'public/images/no-avatar.png') + ); + + if ($profile_user !== null) { + $user_avatar = "{$profile_user->user_id}.msz"; + $cropped_avatar = $app->getStore('avatars/200x200')->filename($user_avatar); + + if (File::exists($cropped_avatar)) { + $avatar_filename = $cropped_avatar; + } else { + $original_avatar = $app->getStore('avatars/original')->filename($user_avatar); + + if (File::exists($original_avatar)) { + try { + File::writeAll( + $cropped_avatar, + crop_image_centred_path($original_avatar, 200, 200)->getImagesBlob() + ); + + $avatar_filename = $cropped_avatar; + } catch (Exception $ex) { + } + } + } + } + + header('Content-Type: ' . mime_content_type($avatar_filename)); + echo File::readToEnd($avatar_filename); + break; + + case 'view': + default: + if ($profile_user === null) { + http_response_code(404); + echo $app->templating->render('user.notfound'); + break; + } + + $app->templating->var('profile', $profile_user); + echo $app->templating->render('user.view'); + break; } - -echo $app->templating->render('user.view'); diff --git a/public/settings.php b/public/settings.php index b0c26b64..0a3d7f6d 100644 --- a/public/settings.php +++ b/public/settings.php @@ -1,5 +1,6 @@ [ 'name' => 'Twitter', @@ -91,11 +94,17 @@ if (!array_key_exists($settings_mode, $settings_modes)) { $settings_errors = []; +$avatar_filename = "{$settings_user->user_id}.msz"; +$avatar_max_width = $app->config->get('Avatar', 'max_width', 'int', 4000); +$avatar_max_height = $app->config->get('Avatar', 'max_height', 'int', 4000); +$avatar_max_filesize = $app->config->get('Avatar', 'max_filesize', 'int', 1000000); +$avatar_max_filesize_human = byte_symbol($avatar_max_filesize, true); + if ($_SERVER['REQUEST_METHOD'] === 'POST') { switch ($settings_mode) { case 'account': if (!tmp_csrf_verify($_POST['csrf'] ?? '')) { - $settings_errors[] = "Couldn't verify you, please refresh the page and retry."; + $settings_errors[] = $csrf_error_str; break; } @@ -193,6 +202,110 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $settings_user->save(); } break; + + case 'avatar': + if (isset($_POST['import']) + && !File::exists($app->getStore('avatars/original')->filename($avatar_filename))) { + if (!tmp_csrf_verify($_POST['import'])) { + $settings_errors[] = $csrf_error_str; + break; + } + + $old_avatar_url = trim(file_get_contents( + "https://secret.flashii.net/avatar-serve.php?id={$settings_user->user_id}&r" + )); + + if (empty($old_avatar_url)) { + $settings_errors[] = 'No old avatar was found for you.'; + break; + } + + File::writeAll( + $app->getStore('avatars/original')->filename($avatar_filename), + file_get_contents($old_avatar_url) + ); + break; + } + + if (isset($_POST['delete'])) { + if (!tmp_csrf_verify($_POST['delete'])) { + $settings_errors[] = $csrf_error_str; + break; + } + + File::delete($app->getStore('avatars/original')->filename($avatar_filename)); + File::delete($app->getStore('avatars/200x200')->filename($avatar_filename)); + break; + } + + if (isset($_POST['upload'])) { + if (!tmp_csrf_verify($_POST['upload'])) { + $settings_errors[] = $csrf_error_str; + break; + } + + switch ($_FILES['avatar']['error']) { + case UPLOAD_ERR_OK: + break; + + case UPLOAD_ERR_PARTIAL: + $settings_errors[] = 'The upload was interrupted, please try again!'; + break; + + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: + $settings_errors[] = "Your avatar is not allowed to be larger in filesize than {$avatar_max_filesize_human}!"; + break; + + case UPLOAD_ERR_NO_TMP_DIR: + case UPLOAD_ERR_CANT_WRITE: + $settings_errors[] = 'Unable to save your avatar, contact an administator!'; + break; + + case UPLOAD_ERR_EXTENSION: + default: + $settings_errors[] = 'Something happened?'; + break; + } + + if (count($settings_errors) > 0) { + break; + } + + $upload_path = $_FILES['avatar']['tmp_name']; + $upload_meta = getimagesize($upload_path); + + if (!$upload_meta + || !in_array($upload_meta[2], [IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG], true) + || $upload_meta[0] < 1 + || $upload_meta[1] < 1) { + $settings_errors[] = 'Please provide a valid image.'; + break; + } + + if ($upload_meta[0] > $avatar_max_width || $upload_meta[1] > $avatar_max_height) { + $settings_errors[] = "Your avatar can't be larger than {$avatar_max_width}x{$avatar_max_height}, yours was {$upload_meta[0]}x{$upload_meta[1]}"; + break; + } + + if (filesize($upload_path) > $avatar_max_filesize) { + $settings_errors[] = "Your avatar is not allowed to be larger in filesize than {$avatar_max_filesize_human}!"; + break; + } + + $avatar_path = $app->getStore('avatars/original')->filename($avatar_filename); + move_uploaded_file($upload_path, $avatar_path); + + $crop_path = $app->getStore('avatars/200x200')->filename($avatar_filename); + + if (File::exists($crop_path)) { + File::delete($crop_path); + } + break; + } + + $settings_errors[] = "You shouldn't have done that."; + break; } } @@ -204,6 +317,13 @@ switch ($settings_mode) { $app->templating->vars(compact('settings_profile_fields')); break; + case 'avatar': + $app->templating->var( + 'can_import_old_avatar', + !File::exists($app->getStore('avatars/original')->filename($avatar_filename)) + ); + break; + case 'sessions': $app->templating->var('user_sessions', $settings_user->sessions->reverse()); break; diff --git a/src/Application.php b/src/Application.php index 19402425..59bd32e7 100644 --- a/src/Application.php +++ b/src/Application.php @@ -2,6 +2,7 @@ namespace Misuzu; use Misuzu\Config\ConfigManager; +use Misuzu\IO\Directory; use Misuzu\Users\Session; use UnexpectedValueException; use InvalidArgumentException; @@ -48,6 +49,48 @@ class Application extends ApplicationBase ExceptionHandler::unregister(); } + public function inDebugMode(): bool + { + return $this->debugMode; + } + + public function getPath(string $path): string + { + if (!starts_with($path, '/')) { + $path = __DIR__ . '/../' . $path; + } + + return Directory::fixSlashes(rtrim($path, '/')); + } + + public function getStoragePath(string $append = ''): Directory + { + $path = ''; + + if (starts_with($append, '/')) { + $path = $append; + } else { + $path = $this->config->get('Storage', 'path', 'string', __DIR__ . '/../store'); + + if (!empty($append)) { + $path .= '/' . $append; + } + } + + return Directory::createOrOpen($this->getPath($path)); + } + + public function getStore(string $purpose): Directory + { + $override_key = "override_{$purpose}"; + + if ($this->config->contains('Storage', $override_key)) { + return new Directory($this->config->get('Storage', $override_key)); + } + + return $this->getStoragePath($purpose); + } + public function startSession(int $user_id, string $session_key): void { $session = Session::where('session_key', $session_key) diff --git a/src/IO/Directory.php b/src/IO/Directory.php index 940f5283..26f3e7fb 100644 --- a/src/IO/Directory.php +++ b/src/IO/Directory.php @@ -12,7 +12,22 @@ class Directory * Path to this directory. * @var string */ - public $path; + private $path; + + public function getPath(): string + { + return $this->path; + } + + public function isReadable(): bool + { + return is_readable($this->getPath()); + } + + public function isWritable(): bool + { + return is_writable($this->getPath()); + } /** * Fixes the path, sets proper slashes and checks if the directory exists. @@ -21,11 +36,13 @@ class Directory */ public function __construct(string $path) { - $this->path = static::fixSlashes(rtrim($path, '/\\')); + $path = static::fixSlashes(rtrim($path, '/\\')); - if (!static::exists($this->path)) { + if (!static::exists($path)) { throw new DirectoryDoesNotExistException; } + + $this->path = realpath($path); } /** @@ -44,6 +61,11 @@ class Directory }, glob($this->path . '/' . $pattern)); } + public function filename(string $filename): string + { + return $this->getPath() . '/' . $filename; + } + /** * Creates a directory if it doesn't already exist. * @param string $path @@ -52,17 +74,33 @@ class Directory */ public static function create(string $path): Directory { - $path = static::fixSlashes($path); - if (static::exists($path)) { throw new DirectoryExistsException; } - mkdir($path); + $split_path = explode('/', $path); + $existing_path = '/'; + + foreach ($split_path as $path_part) { + $existing_path .= $path_part . '/'; + + if (!Directory::exists($existing_path)) { + mkdir($existing_path); + } + } return new static($path); } + public static function createOrOpen(string $path): Directory + { + if (static::exists($path)) { + return new Directory($path); + } else { + return Directory::create($path); + } + } + /** * Deletes a directory, recursively if requested. Use $purge with care! * @param string $path diff --git a/src/IO/File.php b/src/IO/File.php index 10b3304b..e2dbc057 100644 --- a/src/IO/File.php +++ b/src/IO/File.php @@ -1,6 +1,8 @@ read($file->getLength()); + $file->close(); + } catch (Exception $ex) { + } + + return $output; + } + + public static function writeAll(string $filename, string $data): void + { + $file = new FileStream($filename, FileStream::MODE_TRUNCATE, true); + $file->write($data); + $file->close(); + } + /** * Creates an instance of a temporary file. * @param string $prefix diff --git a/src/IO/FileStream.php b/src/IO/FileStream.php index 0ee15b14..5777d67e 100644 --- a/src/IO/FileStream.php +++ b/src/IO/FileStream.php @@ -124,44 +124,44 @@ class FileStream extends Stream } } - protected function getCanRead(): bool + public function getCanRead(): bool { return ($this->fileMode & static::MODE_READ) > 0 && is_readable($this->filePath); } - protected function getCanSeek(): bool + public function getCanSeek(): bool { return ($this->fileMode & static::MODE_APPEND_RAW) == 0 && $this->getCanRead(); } - protected function getCanTimeout(): bool + public function getCanTimeout(): bool { return false; } - protected function getCanWrite(): bool + public function getCanWrite(): bool { return ($this->fileMode & static::MODE_WRITE) > 0 && is_writable($this->filePath); } - protected function getLength(): int + public function getLength(): int { $this->ensureHandleActive(); return fstat($this->fileHandle)['size']; } - protected function getPosition(): int + public function getPosition(): int { $this->ensureHandleActive(); return ftell($this->fileHandle); } - protected function getReadTimeout(): int + public function getReadTimeout(): int { return -1; } - protected function getWriteTimeout(): int + public function getWriteTimeout(): int { return -1; } diff --git a/src/IO/NetworkStream.php b/src/IO/NetworkStream.php index 59e85221..f1d3a8b6 100644 --- a/src/IO/NetworkStream.php +++ b/src/IO/NetworkStream.php @@ -49,42 +49,42 @@ class NetworkStream extends Stream } } - protected function getCanRead(): bool + public function getCanRead(): bool { return true; } - protected function getCanSeek(): bool + public function getCanSeek(): bool { return false; } - protected function getCanTimeout(): bool + public function getCanTimeout(): bool { return true; } - protected function getCanWrite(): bool + public function getCanWrite(): bool { return true; } - protected function getLength(): int + public function getLength(): int { return -1; } - protected function getPosition(): int + public function getPosition(): int { return -1; } - protected function getReadTimeout(): int + public function getReadTimeout(): int { return -1; } - protected function getWriteTimeout(): int + public function getWriteTimeout(): int { return -1; } diff --git a/src/IO/Stream.php b/src/IO/Stream.php index b0b2aaa0..96aed6eb 100644 --- a/src/IO/Stream.php +++ b/src/IO/Stream.php @@ -20,14 +20,14 @@ abstract class Stream throw new InvalidArgumentException; } - abstract protected function getCanRead(): bool; - abstract protected function getCanSeek(): bool; - abstract protected function getCanTimeout(): bool; - abstract protected function getCanWrite(): bool; - abstract protected function getLength(): int; - abstract protected function getPosition(): int; - abstract protected function getReadTimeout(): int; - abstract protected function getWriteTimeout(): int; + abstract public function getCanRead(): bool; + abstract public function getCanSeek(): bool; + abstract public function getCanTimeout(): bool; + abstract public function getCanWrite(): bool; + abstract public function getLength(): int; + abstract public function getPosition(): int; + abstract public function getReadTimeout(): int; + abstract public function getWriteTimeout(): int; abstract public function flush(): void; abstract public function close(): void; diff --git a/utility.php b/utility.php index a545e8f8..37111786 100644 --- a/utility.php +++ b/utility.php @@ -150,6 +150,53 @@ function tmp_csrf_token(?\Misuzu\Users\Session $session = null): string return md5($session->session_key); } +function crop_image_centred_path(string $filename, int $target_width, int $target_height): \Imagick +{ + return crop_image_centred(new \Imagick($filename), $target_width, $target_height); +} + +function crop_image_centred(Imagick $image, int $target_width, int $target_height): Imagick +{ + $image->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 is_int_ex($value, int $boundary_low, int $boundary_high): bool { return is_int($value) && $value >= $boundary_low && $value <= $boundary_high; diff --git a/views/mio/master.twig b/views/mio/master.twig index c171544a..c151379e 100644 --- a/views/mio/master.twig +++ b/views/mio/master.twig @@ -28,7 +28,7 @@

Hey, {{ app.session.user.username }}!
-
+
{% endspaceless %}
-
+
diff --git a/views/nova/user/view.twig b/views/nova/user/view.twig index d15f0826..cb99ec5b 100644 --- a/views/nova/user/view.twig +++ b/views/nova/user/view.twig @@ -55,7 +55,7 @@
{% spaceless %}
-
+
{% for id, data in hierarchies %} {% if data.display %}