diff --git a/config/phpstan/phpstan.neon b/config/phpstan/phpstan.neon index 5a46ff53..816ab4bf 100644 --- a/config/phpstan/phpstan.neon +++ b/config/phpstan/phpstan.neon @@ -7,6 +7,9 @@ parameters: ignoreErrors: # Ignore errors caused by Template static class reflection - '#Call to an undefined static method Template::[a-zA-Z0-9\\_]+\(\)\.#' + + # Ignore errors caused by no type hints on class properties, as that's not available till PHP 7.4 + - '#Property .+? has no typehint specified.#' level: 7 paths: diff --git a/lib/Core.php b/lib/Core.php index 6ba2777c..117753e7 100644 --- a/lib/Core.php +++ b/lib/Core.php @@ -11,7 +11,7 @@ mb_http_output('UTF-8'); date_default_timezone_set('UTC'); // Custom error handler to output more details about the specific Apache request that caused an exception. -set_exception_handler(function($ex){ +set_exception_handler(function(Throwable $ex): void{ $errorString = "----------------------------------------\n"; $errorString .= trim(vds(array_intersect_key($_SERVER, array('REQUEST_URI' => '', 'QUERY_STRING' => '', 'REQUEST_METHOD' => '', 'REDIRECT_QUERY_STRING' => '', 'REDIRECT_URL' => '', 'SCRIPT_FILENAME' => '', 'REMOTE_ADDR' => '', 'HTTP_COOKIE' => '', 'HTTP_USER_AGENT' => '', 'SCRIPT_URI' => '')))); diff --git a/lib/CoreFunctions.php b/lib/CoreFunctions.php index b1695e8a..c065ad43 100644 --- a/lib/CoreFunctions.php +++ b/lib/CoreFunctions.php @@ -5,21 +5,24 @@ use function Safe\ob_end_clean; // Convenience alias of var_dump. -function vd($var){ +function vd($var): void{ var_dump($var); } // var_dump($var) then die(). -function vdd($var){ +function vdd($var): void{ var_dump($var); die(); } // var_dump into a string. -function vds($var){ +function vds($var): string{ ob_start(); var_dump($var); $str = ob_get_contents(); + if($str === false){ + $str = ''; + } ob_end_clean(); return $str; } diff --git a/lib/Ebook.php b/lib/Ebook.php index 8947341c..0663d7d2 100644 --- a/lib/Ebook.php +++ b/lib/Ebook.php @@ -1,10 +1,11 @@ FullTitle = $this->NullIfEmpty($xml->xpath('/package/metadata/dc:title[@id="fulltitle"]')); - $this->Timestamp = new \DateTime((string)$xml->xpath('/package/metadata/dc:date')[0]); + $date = $xml->xpath('/package/metadata/dc:date'); + if($date !== false && sizeof($date) > 0){ + $this->Timestamp = new DateTime((string)$date[0]); + } // Get SE tags foreach($xml->xpath('/package/metadata/meta[@property="se:subject"]') ?: [] as $tag){ @@ -170,14 +174,22 @@ class Ebook{ $this->LocTags[] = (string)$tag; } - // Figure out authors and contributors. + // Figure out authors and contributors foreach($xml->xpath('/package/metadata/dc:creator') ?: [] as $author){ $id = ''; + if($author->attributes() !== null){ $id = $author->attributes()->id; } + + $refines = null; + $refinesElement = $xml->xpath('/package/metadata/meta[@property="file-as"][@refines="#' . $id . '"]'); + if($refinesElement !== false && sizeof($refinesElement) > 0){ + $refines = (string)$refinesElement[0]; + } + $this->Authors[] = new Contributor( (string)$author, - (string)$xml->xpath('/package/metadata/meta[@property="file-as"][@refines="#' . $id . '"]')[0], + $refines, $this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="se:name.person.full-name"][@refines="#' . $id . '"]')), $this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="se:url.encyclopedia.wikipedia"][@refines="#' . $id . '"]')) ); @@ -225,8 +237,20 @@ class Ebook{ $this->Description = $this->NullIfEmpty($xml->xpath('/package/metadata/dc:description')); $this->Language = $this->NullIfEmpty($xml->xpath('/package/metadata/dc:language')); $this->LongDescription = $this->NullIfEmpty($xml->xpath('/package/metadata/meta[@property="se:long-description"]')); - $this->WordCount = (int)$xml->xpath('/package/metadata/meta[@property="se:word-count"]')[0] ?? 0; - $this->ReadingEase = (float)$xml->xpath('/package/metadata/meta[@property="se:reading-ease.flesch"]')[0] ?? 0; + + $wordCount = 0; + $wordCountElement = $xml->xpath('/package/metadata/meta[@property="se:word-count"]'); + if($wordCountElement !== false && sizeof($wordCountElement) > 0){ + $wordCount = (int)$wordCountElement[0]; + } + $this->WordCount = $wordCount; + + $readingEase = 0; + $readingEaseElement = $xml->xpath('/package/metadata/meta[@property="se:reading-ease.flesch"]'); + if($readingEaseElement !== false && sizeof($readingEaseElement) > 0){ + $readingEase = (float)$readingEaseElement[0]; + } + $this->ReadingEase = $readingEase; if($this->ReadingEase !== null){ if($this->ReadingEase >= 90){ @@ -479,9 +503,10 @@ class Ebook{ return $object; } + /** + * @param array $contributors + */ private function GenerateContributorList(array $contributors): string{ - // Inputs: An array of Contributor objects. - $string = ''; $i = 0; foreach($contributors as $contributor){ diff --git a/lib/GitCommit.php b/lib/GitCommit.php index a0dc9451..921abc92 100644 --- a/lib/GitCommit.php +++ b/lib/GitCommit.php @@ -1,10 +1,12 @@ Timestamp = new \DateTimeImmutable('@' . $unixTimestamp); + $this->Timestamp = new DateTimeImmutable('@' . $unixTimestamp); $this->Message = $message; } } diff --git a/lib/HttpInput.php b/lib/HttpInput.php index f1c45a4a..68cb3b9d 100644 --- a/lib/HttpInput.php +++ b/lib/HttpInput.php @@ -1,6 +1,6 @@ + */ public static function GetEbooks(string $sort = null): array{ $ebooks = []; @@ -69,6 +72,9 @@ class Library{ return $ebooks; } + /** + * @return array + */ public static function GetEbooksByAuthor(string $wwwFilesystemPath): array{ // Do we have the author's ebooks cached? $ebooks = []; @@ -82,6 +88,9 @@ class Library{ return $ebooks; } + /** + * @return array + */ public static function GetEbooksByTag(string $tag): array{ // Do we have the tag's ebooks cached? $ebooks = []; @@ -95,6 +104,9 @@ class Library{ return $ebooks; } + /** + * @return array + */ public static function GetEbooksByCollection(string $collection): array{ // Do we have the tag's ebooks cached? $ebooks = []; @@ -108,6 +120,9 @@ class Library{ return $ebooks; } + /** + * @return array + */ public static function Search(string $query): array{ $ebooks = Library::GetEbooks(); $matches = []; diff --git a/lib/Logger.php b/lib/Logger.php index 15c55730..40f3269d 100644 --- a/lib/Logger.php +++ b/lib/Logger.php @@ -5,7 +5,7 @@ use function Safe\fclose; use function Safe\error_log; class Logger{ - public static function WriteGithubWebhookLogEntry(string $requestId, string $text){ + public static function WriteGithubWebhookLogEntry(string $requestId, string $text): void{ try{ $fp = fopen(GITHUB_WEBHOOK_LOG_FILE_PATH, 'a+'); } @@ -18,7 +18,7 @@ class Logger{ fclose($fp); } - public static function WriteErrorLogEntry(string $text){ + public static function WriteErrorLogEntry(string $text): void{ error_log($text); } } diff --git a/lib/SeeOtherEbookException.php b/lib/SeeOtherEbookException.php index def2120c..780431c4 100644 --- a/lib/SeeOtherEbookException.php +++ b/lib/SeeOtherEbookException.php @@ -2,7 +2,7 @@ class SeeOtherEbookException extends \Exception{ public $Url; - public function __construct($url = ''){ + public function __construct(string $url = ''){ $this->Url = $url; parent::__construct('This ebook is at a different URL: ' . $url); } diff --git a/lib/WebhookException.php b/lib/WebhookException.php index e76d62fd..48189862 100644 --- a/lib/WebhookException.php +++ b/lib/WebhookException.php @@ -2,7 +2,7 @@ class WebhookException extends \Exception{ public $PostData; - public function __construct($message = '', $data = null){ + public function __construct(string $message = '', string $data = null){ $this->PostData = $data; parent::__construct($message); } diff --git a/www/webhooks/github.php b/www/webhooks/github.php index de80bfa2..b66ddab8 100644 --- a/www/webhooks/github.php +++ b/www/webhooks/github.php @@ -41,7 +41,6 @@ try{ // Silence on success. Logger::WriteGithubWebhookLogEntry($requestId, 'Event type: ping.'); throw new NoopException(); - break; case 'push': Logger::WriteGithubWebhookLogEntry($requestId, 'Event type: push.'); @@ -114,7 +113,6 @@ try{ break; default: throw new WebhookException('Unrecognized GitHub webhook event.', $post); - break; } // "Success, no content"