diff --git a/core/basepage.php b/core/basepage.php index 6b3aaa69..d0ba5e1d 100644 --- a/core/basepage.php +++ b/core/basepage.php @@ -308,7 +308,7 @@ class BasePage assert($this->file, "file should not be null with PageMode::FILE"); // https://gist.github.com/codler/3906826 - $size = filesize($this->file); // File size + $size = false_throws(filesize($this->file)); // File size $length = $size; // Content length $start = 0; // Start byte $end = $size - 1; // End byte @@ -420,7 +420,7 @@ class BasePage if (!file_exists($css_cache_file)) { $mcss = new \MicroBundler\MicroBundler(); foreach($css_files as $css) { - $mcss->addSource($css, file_get_contents($css)); + $mcss->addSource($css); } $mcss->save($css_cache_file); } @@ -443,7 +443,7 @@ class BasePage if (!file_exists($js_cache_file)) { $mcss = new \MicroBundler\MicroBundler(); foreach($js_files as $js) { - $mcss->addSource($js, file_get_contents($js)); + $mcss->addSource($js); } $mcss->save($js_cache_file); } @@ -471,7 +471,7 @@ class BasePage if (!file_exists($js_cache_file)) { $mcss = new \MicroBundler\MicroBundler(); foreach($js_files as $js) { - $mcss->addSource($js, file_get_contents($js)); + $mcss->addSource($js); } $mcss->save($js_cache_file); } diff --git a/core/cacheengine.php b/core/cacheengine.php index b6e2b0b3..0ae69a8e 100644 --- a/core/cacheengine.php +++ b/core/cacheengine.php @@ -70,7 +70,7 @@ class EventTracingCache implements CacheInterface /** * @param string[] $keys * @param mixed $default - * @return mixed[] + * @return iterable */ public function getMultiple($keys, $default = null) { @@ -126,10 +126,10 @@ function loadCache(?string $dsn): CacheInterface } elseif ($url['scheme'] == "redis") { $redis = new \Predis\Client([ 'scheme' => 'tcp', - 'host' => $url['host'], - 'port' => $url['port'], - 'username' => $url['user'], - 'password' => $url['pass'], + 'host' => $url['host'] ?? "127.0.0.1", + 'port' => $url['port'] ?? 6379, + 'username' => $url['user'] ?? null, + 'password' => $url['pass'] ?? null, ], ['prefix' => 'shm:']); $c = new \Naroga\RedisCache\Redis($redis); } diff --git a/core/database.php b/core/database.php index d9b1e60b..ab6e173c 100644 --- a/core/database.php +++ b/core/database.php @@ -129,6 +129,11 @@ class Database } } + /** + * @template T + * @param callable():T $callback + * @return T + */ public function with_savepoint(callable $callback, string $name = "sp"): mixed { global $_tracer; diff --git a/core/dbengine.php b/core/dbengine.php index abd9909a..9855b733 100644 --- a/core/dbengine.php +++ b/core/dbengine.php @@ -72,7 +72,7 @@ class MySQL extends DBEngine public function get_version(PDO $db): string { - return $db->query('select version()')->fetch()[0]; + return false_throws($db->query('select version()'))->fetch()[0]; } } @@ -124,14 +124,14 @@ class PostgreSQL extends DBEngine public function get_version(PDO $db): string { - return $db->query('select version()')->fetch()[0]; + return false_throws($db->query('select version()'))->fetch()[0]; } } // shimmie functions for export to sqlite function _unix_timestamp(string $date): int { - return strtotime($date); + return false_throws(strtotime($date)); } function _now(): string { @@ -231,6 +231,6 @@ class SQLite extends DBEngine public function get_version(PDO $db): string { - return $db->query('select sqlite_version()')->fetch()[0]; + return false_throws($db->query('select sqlite_version()'))->fetch()[0]; } } diff --git a/core/extension.php b/core/extension.php index b3431846..7a5640ee 100644 --- a/core/extension.php +++ b/core/extension.php @@ -43,9 +43,13 @@ abstract class Extension $normal = "Shimmie2\\{$base}Theme"; if (class_exists($custom)) { - return new $custom(); + $c = new $custom(); + assert(is_a($c, Themelet::class)); + return $c; } elseif (class_exists($normal)) { - return new $normal(); + $n = new $normal(); + assert(is_a($n, Themelet::class)); + return $n; } else { return new Themelet(); } @@ -266,6 +270,7 @@ abstract class ExtensionInfo { foreach (get_subclasses_of(ExtensionInfo::class) as $class) { $extension_info = new $class(); + assert(is_a($extension_info, ExtensionInfo::class)); if (array_key_exists($extension_info->key, self::$all_info_by_key)) { throw new SCoreException("Extension Info $class with key $extension_info->key has already been loaded"); } @@ -317,7 +322,7 @@ abstract class DataHandlerExtension extends Extension throw new UploadException("Invalid or corrupted file"); } - $existing = Image::by_hash(md5_file($event->tmpname)); + $existing = Image::by_hash(false_throws(md5_file($event->tmpname))); if (!is_null($existing)) { if ($config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER) == ImageConfig::COLLISION_MERGE) { // Right now tags are the only thing that get merged, so @@ -338,8 +343,8 @@ abstract class DataHandlerExtension extends Extension assert(is_readable($filename)); $image = new Image(); $image->tmp_file = $filename; - $image->filesize = filesize($filename); - $image->hash = md5_file($filename); + $image->filesize = false_throws(filesize($filename)); + $image->hash = false_throws(md5_file($filename)); $image->filename = (($pos = strpos($event->metadata['filename'], '?')) !== false) ? substr($event->metadata['filename'], 0, $pos) : $event->metadata['filename']; $image->set_mime(MimeType::get_for_file($filename, get_file_ext($event->metadata["filename"]) ?? null)); if (empty($image->get_mime())) { @@ -424,6 +429,7 @@ abstract class DataHandlerExtension extends Extension $arr = []; foreach (get_subclasses_of(DataHandlerExtension::class) as $handler) { $handler = (new $handler()); + assert(is_a($handler, DataHandlerExtension::class)); $arr = array_merge($arr, $handler->SUPPORTED_MIME); } diff --git a/core/polyfills.php b/core/polyfills.php index 992de6c3..791d66ca 100644 --- a/core/polyfills.php +++ b/core/polyfills.php @@ -79,9 +79,13 @@ function full_copy(string $source, string $target): void if (is_dir($source)) { @mkdir($target); - $d = dir($source); + $d = false_throws(dir($source)); - while (false !== ($entry = $d->read())) { + while (true) { + $entry = $d->read(); + if ($entry === false) { + break; + } if ($entry == '.' || $entry == '..') { continue; } @@ -155,12 +159,16 @@ function flush_output(): void function stream_file(string $file, int $start, int $end): void { $fp = fopen($file, 'r'); + if(!$fp) { + throw new \Exception("Failed to open $file"); + } try { fseek($fp, $start); $buffer = 1024 * 1024; while (!feof($fp) && ($p = ftell($fp)) <= $end) { if ($p + $buffer > $end) { $buffer = $end - $p + 1; + assert($buffer >= 0); } echo fread($fp, $buffer); flush_output(); @@ -180,13 +188,13 @@ function stream_file(string $file, int $start, int $end): void # http://www.php.net/manual/en/function.http-parse-headers.php#112917 if (!function_exists('http_parse_headers')) { /** - * @return string[] + * @return array */ function http_parse_headers(string $raw_headers): array { - $headers = []; // $headers = []; + $headers = []; - foreach (explode("\n", $raw_headers) as $i => $h) { + foreach (explode("\n", $raw_headers) as $h) { $h = explode(':', $h, 2); if (isset($h[1])) { @@ -441,7 +449,7 @@ function page_number(string $input, ?int $max = null): int } else { $pageNumber = $input - 1; } - return $pageNumber; + return (int)$pageNumber; } function is_numberish(string $s): bool @@ -449,6 +457,14 @@ function is_numberish(string $s): bool return is_numeric($s); } +/** + * Because apparently phpstan thinks that if $i is an int, type(-$i) == int|float + */ +function negative_int(int $i): int +{ + return -$i; +} + function clamp(int $val, ?int $min = null, ?int $max = null): int { if (!is_null($min) && $val < $min) { @@ -611,11 +627,24 @@ function parse_to_milliseconds(string $input): int */ function autodate(string $date, bool $html = true): string { - $cpu = date('c', strtotime($date)); - $hum = date('F j, Y; H:i', strtotime($date)); + $cpu = date('c', false_throws(strtotime($date))); + $hum = date('F j, Y; H:i', false_throws(strtotime($date))); return ($html ? "" : $hum); } +/** + * @template T + * @param T|false $x + * @return T + */ +function false_throws(mixed $x): mixed +{ + if($x === false) { + throw new \Exception("Unexpected false"); + } + return $x; +} + /** * Check if a given string is a valid date-time. ( Format: yyyy-mm-dd hh:mm:ss ) */ @@ -710,7 +739,7 @@ function validate_input(array $inputs): array } elseif (in_array('bool', $flags)) { $outputs[$key] = bool_escape($value); } elseif (in_array('date', $flags)) { - $outputs[$key] = date("Y-m-d H:i:s", strtotime(trim($value))); + $outputs[$key] = date("Y-m-d H:i:s", false_throws(strtotime(trim($value)))); } elseif (in_array('string', $flags)) { if (in_array('trim', $flags)) { $value = trim($value); diff --git a/core/urls.php b/core/urls.php index b715e1d5..b74580e6 100644 --- a/core/urls.php +++ b/core/urls.php @@ -84,6 +84,7 @@ function modify_current_url(array $changes): string */ function modify_url(string $url, array $changes): string { + /** @var array */ $parts = parse_url($url); $params = []; diff --git a/core/userclass.php b/core/userclass.php index 1afa8a37..f3588c99 100644 --- a/core/userclass.php +++ b/core/userclass.php @@ -89,6 +89,7 @@ class UserClass $_all_false = []; foreach ((new \ReflectionClass(Permissions::class))->getConstants() as $k => $v) { + assert(is_string($v)); $_all_false[$v] = false; } new UserClass("base", null, $_all_false); diff --git a/core/util.php b/core/util.php index 961355fa..e948ff29 100644 --- a/core/util.php +++ b/core/util.php @@ -194,7 +194,7 @@ function get_session_ip(Config $config): string { $mask = $config->get_string("session_hash_mask", "255.255.0.0"); $addr = get_real_ip(); - $addr = inet_ntop(inet_pton($addr) & inet_pton($mask)); + $addr = false_throws(inet_ntop(false_throws(inet_pton($addr)) & false_throws(inet_pton($mask)))); return $addr; } @@ -285,17 +285,21 @@ function load_balance_url(string $tmpl, string $hash, int $n = 0): string return $tmpl; } +class FetchException extends \Exception +{ +} + /** - * @return null|array + * @return array */ -function fetch_url(string $url, string $mfile): ?array +function fetch_url(string $url, string $mfile): array { global $config; if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "curl" && function_exists("curl_init")) { $ch = curl_init($url); assert($ch !== false); - $fp = fopen($mfile, "w"); + $fp = false_throws(fopen($mfile, "w")); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_VERBOSE, 1); @@ -306,37 +310,37 @@ function fetch_url(string $url, string $mfile): ?array $response = curl_exec($ch); if ($response === false) { - return null; + throw new FetchException("cURL failed: ".curl_error($ch)); + } + if ($response === true) { // we use CURLOPT_RETURNTRANSFER, so this should never happen + throw new FetchException("cURL failed successfully??"); } $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $headers = http_parse_headers(implode("\n", preg_split('/\R/', rtrim(substr($response, 0, $header_size))))); + $header_text = trim(substr($response, 0, $header_size)); + $headers = http_parse_headers(implode("\n", false_throws(preg_split('/\R/', $header_text)))); $body = substr($response, $header_size); curl_close($ch); fwrite($fp, $body); fclose($fp); - - return $headers; - } - - if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "wget") { + } elseif ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "wget") { $s_url = escapeshellarg($url); $s_mfile = escapeshellarg($mfile); system("wget --no-check-certificate $s_url --output-document=$s_mfile"); - - return file_exists($mfile) ? ["ok" => "true"] : null; - } - - if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "fopen") { + if(!file_exists($mfile)) { + throw new FetchException("wget failed"); + } + $headers = []; + } elseif ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "fopen") { $fp_in = @fopen($url, "r"); $fp_out = fopen($mfile, "w"); if (!$fp_in || !$fp_out) { - return null; + throw new FetchException("fopen failed"); } $length = 0; while (!feof($fp_in) && $length <= $config->get_int(UploadConfig::SIZE)) { - $data = fread($fp_in, 8192); + $data = false_throws(fread($fp_in, 8192)); $length += strlen($data); fwrite($fp_out, $data); } @@ -344,11 +348,16 @@ function fetch_url(string $url, string $mfile): ?array fclose($fp_out); $headers = http_parse_headers(implode("\n", $http_response_header)); - - return $headers; + } else { + throw new FetchException("No transload engine configured"); } - return null; + if (filesize($mfile) == 0) { + @unlink($mfile); + throw new FetchException("No data found in $url -- perhaps the site has hotlink protection?"); + } + + return $headers; } /** @@ -412,29 +421,17 @@ function get_dir_contents(string $dir): array return []; } return array_diff( - scandir( - $dir - ), + false_throws(scandir($dir)), ['..', '.'] ); } function remove_empty_dirs(string $dir): bool { - assert(!empty($dir)); - $result = true; - if (!is_dir($dir)) { - return false; - } - - $items = array_diff( - scandir( - $dir - ), - ['..', '.'] - ); + $items = get_dir_contents($dir); + ; foreach ($items as $item) { $path = join_path($dir, $item); if (is_dir($path)) { @@ -454,22 +451,10 @@ function remove_empty_dirs(string $dir): bool */ function get_files_recursively(string $dir): array { - assert(!empty($dir)); - - if (!is_dir($dir)) { - return []; - } - - $things = array_diff( - scandir( - $dir - ), - ['..', '.'] - ); + $things = get_dir_contents($dir); $output = []; - foreach ($things as $thing) { $path = join_path($dir, $thing); if (is_file($path)) { @@ -659,8 +644,10 @@ function _fatal_error(\Exception $e): void foreach ($t as $n => $f) { $c = $f['class'] ?? ''; $t = $f['type'] ?? ''; + $i = $f['file'] ?? 'unknown file'; + $l = $f['line'] ?? -1; $a = implode(", ", array_map("Shimmie2\stringer", $f['args'] ?? [])); - print("$n: {$f['file']}({$f['line']}): {$c}{$t}{$f['function']}({$a})\n"); + print("$n: {$i}({$l}): {$c}{$t}{$f['function']}({$a})\n"); } print("Message: $message\n"); diff --git a/ext/alias_editor/main.php b/ext/alias_editor/main.php index 97e2b58e..9bd29d89 100644 --- a/ext/alias_editor/main.php +++ b/ext/alias_editor/main.php @@ -105,7 +105,7 @@ class AliasEditor extends Extension if ($user->can(Permissions::MANAGE_ALIAS_LIST)) { if (count($_FILES) > 0) { $tmp = $_FILES['alias_file']['tmp_name']; - $contents = file_get_contents($tmp); + $contents = false_throws(file_get_contents($tmp)); $this->add_alias_csv($contents); log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many? $page->set_mode(PageMode::REDIRECT); diff --git a/ext/auto_tagger/main.php b/ext/auto_tagger/main.php index 39d88d5c..1f3c3793 100644 --- a/ext/auto_tagger/main.php +++ b/ext/auto_tagger/main.php @@ -111,7 +111,7 @@ class AutoTagger extends Extension if ($user->can(Permissions::MANAGE_AUTO_TAG)) { if (count($_FILES) > 0) { $tmp = $_FILES['auto_tag_file']['tmp_name']; - $contents = file_get_contents($tmp); + $contents = false_throws(file_get_contents($tmp)); $count = $this->add_auto_tag_csv($contents); log_info(AutoTaggerInfo::KEY, "Imported $count auto-tag definitions from file from file", "Imported $count auto-tag definitions"); $page->set_mode(PageMode::REDIRECT); diff --git a/ext/browser_search/main.php b/ext/browser_search/main.php index 87af19ba..fa5b8e9f 100644 --- a/ext/browser_search/main.php +++ b/ext/browser_search/main.php @@ -28,7 +28,7 @@ class BrowserSearch extends Extension $search_title = $config->get_string(SetupConfig::TITLE); $search_form_url = search_link(['{searchTerms}']); $suggenton_url = make_link('browser_search/')."{searchTerms}"; - $icon_b64 = base64_encode(file_get_contents("ext/static_files/static/favicon.ico")); + $icon_b64 = base64_encode(false_throws(file_get_contents("ext/static_files/static/favicon.ico"))); // Now for the XML $xml = " diff --git a/ext/bulk_download/main.php b/ext/bulk_download/main.php index f7659d10..d6e1bdf7 100644 --- a/ext/bulk_download/main.php +++ b/ext/bulk_download/main.php @@ -48,7 +48,7 @@ class BulkDownload extends Extension if ($user->can(Permissions::BULK_DOWNLOAD) && ($event->action == BulkDownload::DOWNLOAD_ACTION_NAME)) { $download_filename = $user->name . '-' . date('YmdHis') . '.zip'; - $zip_filename = tempnam(sys_get_temp_dir(), "shimmie_bulk_download"); + $zip_filename = false_throws(tempnam(sys_get_temp_dir(), "shimmie_bulk_download")); $zip = new \ZipArchive(); $size_total = 0; $max_size = $config->get_int(BulkDownloadConfig::SIZE_LIMIT); @@ -61,7 +61,6 @@ class BulkDownload extends Extension throw new BulkDownloadException("Bulk download limited to ".human_filesize($max_size)); } - $filename = urldecode($image->get_nice_image_name()); $filename = str_replace(":", ";", $filename); $zip->addFile($img_loc, $filename); diff --git a/ext/danbooru_api/main.php b/ext/danbooru_api/main.php index fb82d6f7..980ff2ee 100644 --- a/ext/danbooru_api/main.php +++ b/ext/danbooru_api/main.php @@ -313,10 +313,11 @@ class DanbooruApi extends Extension $source = isset($_REQUEST['source']) ? $_REQUEST['source'] : $_REQUEST['post']['source']; $file = tempnam(sys_get_temp_dir(), "shimmie_transload"); assert($file !== false); - $ok = fetch_url($source, $file); - if (!$ok) { + try { + fetch_url($source, $file); + } catch(FetchException $e) { $page->set_code(409); - $page->add_http_header("X-Danbooru-Errors: fopen read error"); + $page->add_http_header("X-Danbooru-Errors: $e"); return; } $filename = basename($source); diff --git a/ext/home/main.php b/ext/home/main.php index 8df72915..d05c7b6d 100644 --- a/ext/home/main.php +++ b/ext/home/main.php @@ -28,7 +28,7 @@ class Home extends Extension $counters = []; $counters["None"] = "none"; $counters["Text-only"] = "text-only"; - foreach (glob("ext/home/counters/*") as $counter_dirname) { + foreach (false_throws(glob("ext/home/counters/*")) as $counter_dirname) { $name = str_replace("ext/home/counters/", "", $counter_dirname); $counters[ucfirst($name)] = $name; } diff --git a/ext/ouroboros_api/main.php b/ext/ouroboros_api/main.php index 3123e978..422ef592 100644 --- a/ext/ouroboros_api/main.php +++ b/ext/ouroboros_api/main.php @@ -352,8 +352,10 @@ class OuroborosAPI extends Extension // Transload from source $meta['file'] = tempnam(sys_get_temp_dir(), 'shimmie_transload_' . $config->get_string(UploadConfig::TRANSLOAD_ENGINE)); $meta['filename'] = basename($post->file_url); - if (!fetch_url($post->file_url, $meta['file'])) { - $this->sendResponse(500, 'Transloading failed'); + try { + fetch_url($post->file_url, $meta['file']); + } catch (FetchException $e) { + $this->sendResponse(500, "Transloading failed: $e"); return; } $meta['hash'] = md5_file($meta['file']); diff --git a/ext/rss_images/main.php b/ext/rss_images/main.php index aae332d3..ad3d9403 100644 --- a/ext/rss_images/main.php +++ b/ext/rss_images/main.php @@ -109,7 +109,7 @@ class RSSImages extends Extension $tags = html_escape($image->get_tag_list()); $thumb_url = $image->get_thumb_link(); $image_url = $image->get_image_link(); - $posted = date(DATE_RSS, strtotime($image->posted)); + $posted = date(DATE_RSS, false_throws(strtotime($image->posted))); $content = html_escape( "
" . "

" . $this->theme->build_thumb_html($image) . "

" . diff --git a/ext/setup/main.php b/ext/setup/main.php index 54ae1560..c1f8fe5c 100644 --- a/ext/setup/main.php +++ b/ext/setup/main.php @@ -348,7 +348,7 @@ class Setup extends Extension public function onSetupBuilding(SetupBuildingEvent $event): void { $themes = []; - foreach (glob("themes/*") as $theme_dirname) { + foreach (false_throws(glob("themes/*")) as $theme_dirname) { $name = str_replace("themes/", "", $theme_dirname); $human = str_replace("_", " ", $name); $human = ucwords($human); diff --git a/ext/transcode_video/main.php b/ext/transcode_video/main.php index 713c9822..68a0b711 100644 --- a/ext/transcode_video/main.php +++ b/ext/transcode_video/main.php @@ -211,7 +211,7 @@ class TranscodeVideo extends Extension } $original_file = warehouse_path(Image::IMAGE_DIR, $image->hash); - $tmp_filename = tempnam(sys_get_temp_dir(), "shimmie_transcode_video"); + $tmp_filename = false_throws(tempnam(sys_get_temp_dir(), "shimmie_transcode_video")); $tmp_filename = $this->transcode_video($original_file, $image->video_codec, $target_mime, $tmp_filename); send_event(new ImageReplaceEvent($image, $tmp_filename)); return true; diff --git a/ext/update/main.php b/ext/update/main.php index 09c0a3f3..307bc104 100644 --- a/ext/update/main.php +++ b/ext/update/main.php @@ -69,18 +69,14 @@ class Update extends Extension $filename = "./data/update_{$commitSHA}.zip"; log_info("update", "Attempting to download Shimmie commit: ".$commitSHA); - if ($headers = fetch_url($url, $filename)) { - if (($headers['Content-Type'] !== MimeType::ZIP) || ((int) $headers['Content-Length'] !== filesize($filename))) { - unlink("./data/update_{$commitSHA}.zip"); - log_warning("update", "Download failed: not zip / not same size as remote file."); - return false; - } - - return true; + $headers = fetch_url($url, $filename); + if (($headers['Content-Type'] !== MimeType::ZIP) || ((int) $headers['Content-Length'] !== filesize($filename))) { + unlink("./data/update_{$commitSHA}.zip"); + log_warning("update", "Download failed: not zip / not same size as remote file."); + return false; } - log_warning("update", "Download failed to download."); - return false; + return true; } private function update_shimmie(): bool diff --git a/ext/upload/main.php b/ext/upload/main.php index 1741d426..2ac35958 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -385,13 +385,10 @@ class Upload extends Extension try { // Fetch file - $headers = fetch_url($url, $tmp_filename); - if (is_null($headers)) { - log_warning("core-util", "Failed to fetch $url"); - throw new UploadException("Error reading from $url"); - } - if (filesize($tmp_filename) == 0) { - throw new UploadException("No data found in $url -- perhaps the site has hotlink protection?"); + try { + $headers = fetch_url($url, $tmp_filename); + } catch (FetchException $e) { + throw new UploadException("Error reading from $url: $e"); } // Parse metadata diff --git a/ext/user/events.php b/ext/user/events.php index a57b047d..8a558141 100644 --- a/ext/user/events.php +++ b/ext/user/events.php @@ -8,7 +8,7 @@ use MicroHTML\HTMLElement; class UserBlockBuildingEvent extends Event { - /** @var array */ + /** @var array */ public array $parts = []; public function add_link(string|HTMLElement $name, string $link, int $position = 50): void diff --git a/ext/user/theme.php b/ext/user/theme.php index d492b59e..97f31418 100644 --- a/ext/user/theme.php +++ b/ext/user/theme.php @@ -45,7 +45,7 @@ class UserPageTheme extends Themelet } /** - * @param array $parts + * @param array $parts */ public function display_user_links(Page $page, User $user, array $parts): void { @@ -53,7 +53,7 @@ class UserPageTheme extends Themelet } /** - * @param array $parts + * @param array $parts */ public function display_user_block(Page $page, User $user, array $parts): void { diff --git a/tests/defines.php b/tests/defines.php index 5744f427..9a820285 100644 --- a/tests/defines.php +++ b/tests/defines.php @@ -5,7 +5,9 @@ declare(strict_types=1); namespace Shimmie2; define("UNITTEST", true); -define("EXTRA_EXTS", str_replace("ext/", "", implode(',', glob('ext/*')))); +$_all_exts = glob('ext/*'); +assert($_all_exts !== false); +define("EXTRA_EXTS", str_replace("ext/", "", implode(',', $_all_exts))); define("DATABASE_DSN", null); define("DATABASE_TIMEOUT", 10000); diff --git a/tests/phpstan.neon b/tests/phpstan.neon index ad3d6fa0..6bbec296 100644 --- a/tests/phpstan.neon +++ b/tests/phpstan.neon @@ -1,6 +1,6 @@ parameters: errorFormat: raw - level: 5 + level: 6 paths: - ../core - ../ext diff --git a/themes/danbooru/comment.theme.php b/themes/danbooru/comment.theme.php index 5dea15f3..1465bf38 100644 --- a/themes/danbooru/comment.theme.php +++ b/themes/danbooru/comment.theme.php @@ -59,7 +59,8 @@ class CustomCommentListTheme extends CommentListTheme if ($comment_limit > 0 && $comment_count > $comment_limit) { //$hidden = $comment_count - $comment_limit; $comment_html .= "

showing $comment_limit of $comment_count comments

"; - $comments = array_slice($comments, -$comment_limit); + + $comments = array_slice($comments, negative_int($comment_limit)); } foreach ($comments as $comment) { $comment_html .= $this->comment_to_html($comment); diff --git a/themes/danbooru2/comment.theme.php b/themes/danbooru2/comment.theme.php index e1b30d5a..a6525e0c 100644 --- a/themes/danbooru2/comment.theme.php +++ b/themes/danbooru2/comment.theme.php @@ -59,7 +59,7 @@ class CustomCommentListTheme extends CommentListTheme if ($comment_limit > 0 && $comment_count > $comment_limit) { //$hidden = $comment_count - $comment_limit; $comment_html .= "

showing $comment_limit of $comment_count comments

"; - $comments = array_slice($comments, -$comment_limit); + $comments = array_slice($comments, negative_int($comment_limit)); } foreach ($comments as $comment) { $comment_html .= $this->comment_to_html($comment); diff --git a/themes/rule34v2/page.class.php b/themes/rule34v2/page.class.php index 4e56bc82..b96b423b 100644 --- a/themes/rule34v2/page.class.php +++ b/themes/rule34v2/page.class.php @@ -88,6 +88,7 @@ EOD; $footer_html = $this->footer_html(); $header_inc = file_get_contents("themes/rule34v2/header.inc"); + assert($header_inc !== false); $header_inc = str_replace('$QUERY', $query, $header_inc); return <<