diff --git a/composer.lock b/composer.lock index 4b904866..3801d496 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "brick/math", - "version": "0.12.1", + "version": "0.12.2", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "f510c0a40911935b77b86859eb5223d58d660df1" + "reference": "901eddb1e45a8e0f689302e40af871c181ecbe40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1", - "reference": "f510c0a40911935b77b86859eb5223d58d660df1", + "url": "https://api.github.com/repos/brick/math/zipball/901eddb1e45a8e0f689302e40af871c181ecbe40", + "reference": "901eddb1e45a8e0f689302e40af871c181ecbe40", "shasum": "" }, "require": { @@ -26,7 +26,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^10.1", - "vimeo/psalm": "5.16.0" + "vimeo/psalm": "6.8.8" }, "type": "library", "autoload": { @@ -56,7 +56,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.12.1" + "source": "https://github.com/brick/math/tree/0.12.2" }, "funding": [ { @@ -64,7 +64,7 @@ "type": "github" } ], - "time": "2023-11-29T23:19:16+00:00" + "time": "2025-02-26T10:21:45+00:00" }, { "name": "erusev/parsedown", @@ -694,16 +694,16 @@ }, { "name": "symfony/process", - "version": "v6.4.15", + "version": "v6.4.19", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3cb242f059c14ae08591c5c4087d1fe443564392" + "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3cb242f059c14ae08591c5c4087d1fe443564392", - "reference": "3cb242f059c14ae08591c5c4087d1fe443564392", + "url": "https://api.github.com/repos/symfony/process/zipball/7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3", + "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3", "shasum": "" }, "require": { @@ -735,7 +735,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.15" + "source": "https://github.com/symfony/process/tree/v6.4.19" }, "funding": [ { @@ -751,7 +751,7 @@ "type": "tidelift" } ], - "time": "2024-11-06T14:19:14+00:00" + "time": "2025-02-04T13:35:48+00:00" }, { "name": "thecodingmachine/safe", diff --git a/config/phpstan/phpstan.neon b/config/phpstan/phpstan.neon index a780a522..08a9547d 100644 --- a/config/phpstan/phpstan.neon +++ b/config/phpstan/phpstan.neon @@ -33,6 +33,8 @@ parameters: - Emit404 - RedirectToLogin exceptions: + # PHPStan only uses PHPDocs to compute exception bubbling; without this line, PHPStan assumes that any function without a `@throws` doc throws any number of exceptions, instead of no exceptions. + implicitThrows: false check: missingCheckedExceptionInThrows: true tooWideThrowType: true diff --git a/lib/Artwork.php b/lib/Artwork.php index 7ec2752f..93cbd93b 100644 --- a/lib/Artwork.php +++ b/lib/Artwork.php @@ -676,16 +676,16 @@ class Artwork{ * @throws Exceptions\InvalidImageUploadException */ private function WriteImageAndThumbnails(string $imagePath): void{ - exec('exiftool -quiet -overwrite_original -all= ' . escapeshellarg($imagePath)); - copy($imagePath, $this->ImageFsPath); - - // Generate the thumbnails try{ + exec('exiftool -quiet -overwrite_original -all= ' . escapeshellarg($imagePath)); + copy($imagePath, $this->ImageFsPath); + + // Generate the thumbnails $image = new Image($imagePath); $image->Resize($this->ThumbFsPath, ARTWORK_THUMBNAIL_WIDTH, ARTWORK_THUMBNAIL_HEIGHT); $image->Resize($this->Thumb2xFsPath, ARTWORK_THUMBNAIL_WIDTH * 2, ARTWORK_THUMBNAIL_HEIGHT * 2); } - catch(\Safe\Exceptions\FilesystemException | \Safe\Exceptions\ImageException){ + catch(\Safe\Exceptions\ExecException | \Safe\Exceptions\FilesystemException){ throw new Exceptions\InvalidImageUploadException('Failed to generate thumbnail.'); } } diff --git a/lib/Db.php b/lib/Db.php index 1c1a481d..7859e6d8 100644 --- a/lib/Db.php +++ b/lib/Db.php @@ -321,6 +321,7 @@ class Db{ */ protected static function PreparePdoHandle(string $sql, array $params): \PDOStatement{ try{ + /** @throws \PDOException */ $handle = static::$Link->prepare($sql); } catch(\PDOException $ex){ diff --git a/lib/Enums/ImageMimeType.php b/lib/Enums/ImageMimeType.php index 7ac68b94..53e99b8f 100644 --- a/lib/Enums/ImageMimeType.php +++ b/lib/Enums/ImageMimeType.php @@ -23,7 +23,12 @@ enum ImageMimeType: string{ return null; } - $mimeType = mime_content_type($path); + try{ + $mimeType = mime_content_type($path); + } + catch(\Safe\Exceptions\FileinfoException){ + return null; + } $mimeType = match($mimeType){ 'image/x-ms-bmp', 'image/x-bmp' => 'image/bmp', diff --git a/lib/HttpInput.php b/lib/HttpInput.php index 1e854ea0..68381d2c 100644 --- a/lib/HttpInput.php +++ b/lib/HttpInput.php @@ -317,12 +317,7 @@ class HttpInput{ case Enums\HttpVariableType::Integer: // Can't use `ctype_digit()` because we may want negative integers. if(is_numeric($var) && mb_strpos((string)$var, '.') === false){ - try{ - return intval($var); - } - catch(Exception){ - return null; - } + return intval($var); } break; case Enums\HttpVariableType::Boolean: @@ -334,12 +329,7 @@ class HttpInput{ } case Enums\HttpVariableType::Decimal: if(is_numeric($var)){ - try{ - return floatval($var); - } - catch(Exception){ - return null; - } + return floatval($var); } break; case Enums\HttpVariableType::DateTime: diff --git a/lib/Image.php b/lib/Image.php index 39e30054..c3bdb332 100644 --- a/lib/Image.php +++ b/lib/Image.php @@ -18,25 +18,30 @@ class Image{ /** * @return \GdImage - * @throws \Safe\Exceptions\ImageException + * * @throws Exceptions\InvalidImageUploadException */ private function GetImageHandle(){ - switch($this->MimeType){ - case Enums\ImageMimeType::JPG: - $handle = \Safe\imagecreatefromjpeg($this->Path); - break; - case Enums\ImageMimeType::BMP: - $handle = \Safe\imagecreatefrombmp($this->Path); - break; - case Enums\ImageMimeType::PNG: - $handle = \Safe\imagecreatefrompng($this->Path); - break; - case Enums\ImageMimeType::TIFF: - $handle = $this->GetImageHandleFromTiff(); - break; - default: - throw new \Exceptions\InvalidImageUploadException(); + try{ + switch($this->MimeType){ + case Enums\ImageMimeType::JPG: + $handle = \Safe\imagecreatefromjpeg($this->Path); + break; + case Enums\ImageMimeType::BMP: + $handle = \Safe\imagecreatefrombmp($this->Path); + break; + case Enums\ImageMimeType::PNG: + $handle = \Safe\imagecreatefrompng($this->Path); + break; + case Enums\ImageMimeType::TIFF: + $handle = $this->GetImageHandleFromTiff(); + break; + default: + throw new \Exceptions\InvalidImageUploadException(); + } + } + catch(\Safe\Exceptions\ImageException){ + throw new \Exceptions\InvalidImageUploadException(); } return $handle; @@ -93,38 +98,33 @@ class Image{ public function Resize(string $destImagePath, int $width, int $height): void{ try{ $imageDimensions = getimagesize($this->Path); + + $imageWidth = $imageDimensions[0] ?? 0; + $imageHeight = $imageDimensions[1] ?? 0; + + if($imageHeight > $imageWidth){ + $destinationHeight = $height; + $destinationWidth = intval($destinationHeight * ($imageWidth / $imageHeight)); + } + else{ + $destinationWidth = $width; + if($imageWidth == 0){ + $destinationHeight = 0; + } + else{ + $destinationHeight = intval($destinationWidth * ($imageHeight / $imageWidth)); + } + } + + $srcImageHandle = $this->GetImageHandle(); + $thumbImageHandle = imagecreatetruecolor($destinationWidth, $destinationHeight); + + imagecopyresampled($thumbImageHandle, $srcImageHandle, 0, 0, 0, 0, $destinationWidth, $destinationHeight, $imageWidth, $imageHeight); + + imagejpeg($thumbImageHandle, $destImagePath); } catch(\Safe\Exceptions\ImageException $ex){ throw new Exceptions\InvalidImageUploadException($ex->getMessage()); } - - $imageWidth = $imageDimensions[0] ?? 0; - $imageHeight = $imageDimensions[1] ?? 0; - - if($imageHeight > $imageWidth){ - $destinationHeight = $height; - try{ - $destinationWidth = intval($destinationHeight * ($imageWidth / $imageHeight)); - } - catch(\DivisionByZeroError){ - $destinationWidth = 0; - } - } - else{ - $destinationWidth = $width; - try{ - $destinationHeight = intval($destinationWidth * ($imageHeight / $imageWidth)); - } - catch(\DivisionByZeroError){ - $destinationHeight = 0; - } - } - - $srcImageHandle = $this->GetImageHandle(); - $thumbImageHandle = imagecreatetruecolor($destinationWidth, $destinationHeight); - - imagecopyresampled($thumbImageHandle, $srcImageHandle, 0, 0, 0, 0, $destinationWidth, $destinationHeight, $imageWidth, $imageHeight); - - imagejpeg($thumbImageHandle, $destImagePath); } } diff --git a/lib/PollVote.php b/lib/PollVote.php index b40a845e..39da3c0c 100644 --- a/lib/PollVote.php +++ b/lib/PollVote.php @@ -60,6 +60,10 @@ class PollVote{ } else{ try{ + /** + * @throws Exceptions\PollItemNotFoundException + * @throws Exceptions\PollNotFoundException + */ if(!$this->PollItem->Poll->IsActive()){ $error->Add(new Exceptions\PollClosedException()); } diff --git a/lib/Traits/Accessor.php b/lib/Traits/Accessor.php index a9cd2b22..99bbe8e6 100644 --- a/lib/Traits/Accessor.php +++ b/lib/Traits/Accessor.php @@ -126,6 +126,7 @@ trait Accessor{ if(property_exists($this, $privateVar)){ try{ + /** @throws \Throwable */ $this->__get($var); } catch(\Throwable){ diff --git a/lib/Traits/FromRow.php b/lib/Traits/FromRow.php index e5686ded..b3145a53 100644 --- a/lib/Traits/FromRow.php +++ b/lib/Traits/FromRow.php @@ -7,7 +7,7 @@ namespace Traits; trait FromRow{ /** * Fill an object with the given database row. - * This is useful when a subclass has to fill its object in a `FromRow()` method, but its parent class also has a `FromRow()` method defined. For example, `CompoundAction` and `Action`. + * This is useful when a subclass has to fill its object in a `FromRow()` method, but its parent class also has a `FromRow()` method defined. * * @template T of self * diff --git a/scripts/ingest-fa-payments b/scripts/ingest-fa-payments index 89503cf0..882841fa 100755 --- a/scripts/ingest-fa-payments +++ b/scripts/ingest-fa-payments @@ -224,5 +224,7 @@ catch(Exception $ex){ throw $ex; } finally{ + // `$driver` may be unintialized if we ctrl + c during Selenium initialization. + /** @phpstan-ignore nullsafe.neverNull */ $driver?->quit(); } diff --git a/scripts/process-pending-payments b/scripts/process-pending-payments index 9f407f8d..d52f822f 100755 --- a/scripts/process-pending-payments +++ b/scripts/process-pending-payments @@ -325,5 +325,7 @@ catch(Exception $ex){ throw $ex; } finally{ + // `$driver` may be unintialized if we ctrl + c during Selenium initialization. + /** @phpstan-ignore nullsafe.neverNull */ $driver?->quit(); } diff --git a/www/ebooks/index.php b/www/ebooks/index.php index a26d93a1..349b2284 100644 --- a/www/ebooks/index.php +++ b/www/ebooks/index.php @@ -134,12 +134,6 @@ catch(Exceptions\PageOutOfBoundsException){ header('Location: ' . $url); exit(); } -catch(Exceptions\AppException $ex){ - // Something very unexpected happened, log and emit 500. - http_response_code(Enums\HttpCode::InternalServerError->value); // Internal server error. - Log::WriteErrorLogEntry($ex); - exit(); -} ?> $pageTitle, 'highlight' => 'ebooks', 'description' => $pageDescription, 'canonicalUrl' => $canonicalUrl]) ?>

diff --git a/www/feeds/atom/search.php b/www/feeds/atom/search.php index ca82f6dd..716464de 100644 --- a/www/feeds/atom/search.php +++ b/www/feeds/atom/search.php @@ -1,20 +1,13 @@ value); - include(WEB_ROOT . '/404.php'); - exit(); -} print("\n\n"); ?> diff --git a/www/feeds/opds/search.php b/www/feeds/opds/search.php index 63a5bc5f..cf024a1f 100644 --- a/www/feeds/opds/search.php +++ b/www/feeds/opds/search.php @@ -1,19 +1,13 @@ value); - exit(); -} print("\n\n"); ?> diff --git a/www/feeds/rss/search.php b/www/feeds/rss/search.php index 5ddd169f..b044dac0 100644 --- a/www/feeds/rss/search.php +++ b/www/feeds/rss/search.php @@ -1,20 +1,13 @@ value); - include(WEB_ROOT . '/404.php'); - exit(); -} print("\n\n"); ?> diff --git a/www/projects/post.php b/www/projects/post.php index 0fffd6c3..93c22caf 100644 --- a/www/projects/post.php +++ b/www/projects/post.php @@ -118,7 +118,7 @@ catch(Exceptions\LoginRequiredException){ catch(Exceptions\InvalidPermissionsException){ Template::ExitWithCode(Enums\HttpCode::Forbidden); } -catch(Exceptions\InvalidProjectException | Exceptions\InvalidEbookException | Exceptions\ProjectExistsException | Exceptions\EbookExistsException | Exceptions\EbookIsNotAPlaceholderException $ex){ +catch(Exceptions\InvalidProjectException | Exceptions\InvalidEbookException | Exceptions\ProjectExistsException | Exceptions\EbookIsNotAPlaceholderException $ex){ $_SESSION['project'] = $project; $_SESSION['exception'] = $ex;