From 1b76366dd9fff566374fe9831d8ec6a3041fd432 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 09:34:37 -0500 Subject: [PATCH 001/133] Cleaned up some of the new image processing code, added documentation --- core/imageboard/misc.php | 148 ++++++++++++++++++++++---------------- ext/handle_pixel/main.php | 2 +- 2 files changed, 89 insertions(+), 61 deletions(-) diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index dbdf25f5..6336f8bb 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -7,6 +7,7 @@ * Move a file from PHP's temporary area into shimmie's image storage * hierarchy, or throw an exception trying. * + * @param DataUploadEvent $event * @throws UploadException */ function move_upload_to_archive(DataUploadEvent $event): void @@ -24,7 +25,8 @@ function move_upload_to_archive(DataUploadEvent $event): void /** * Add a directory full of images * - * #return string[] + * @param string $base + * @return array */ function add_dir(string $base): array { @@ -48,6 +50,14 @@ function add_dir(string $base): array return $results; } +/** + * Sends a DataUploadEvent for a file. + * + * @param string $tmpname + * @param string $filename + * @param string $tags + * @throws UploadException + */ function add_image(string $tmpname, string $filename, string $tags): void { assert(file_exists($tmpname)); @@ -65,10 +75,15 @@ function add_image(string $tmpname, string $filename, string $tags): void send_event($event); } - -function get_extension_from_mime(String $file_path): ?String +/** + * Gets an the extension defined in MIME_TYPE_MAP for a file. + * + * @param String $file_path + * @return String The extension that was found. + * @throws UploadException if the mimetype could not be determined, or if an extension for hte mimetype could not be found. + */ +function get_extension_from_mime(String $file_path): String { - global $config; $mime = mime_content_type($file_path); if (!empty($mime)) { $ext = get_extension($mime); @@ -83,11 +98,15 @@ function get_extension_from_mime(String $file_path): ?String /** * Given a full size pair of dimensions, return a pair scaled down to fit - * into the configured thumbnail square, with ratio intact + * into the configured thumbnail square, with ratio intact. + * Optionally uses the High-DPI scaling setting to adjust the final resolution. * - * #return int[] + * @param int $orig_width + * @param int $orig_height + * @param bool $use_dpi_scaling Enables the High-DPI scaling. + * @return array */ -function get_thumbnail_size(int $orig_width, int $orig_height): array +function get_thumbnail_size(int $orig_width, int $orig_height, bool $use_dpi_scaling = false): array { global $config; @@ -105,8 +124,15 @@ function get_thumbnail_size(int $orig_width, int $orig_height): array $orig_height = $orig_width * 5; } - $max_width = $config->get_int('thumb_width'); - $max_height = $config->get_int('thumb_height'); + + if($use_dpi_scaling) { + $max_size = get_thumbnail_max_size_scaled(); + $max_width = $max_size[0]; + $max_height = $max_size[1]; + } else { + $max_width = $config->get_int('thumb_width'); + $max_height = $config->get_int('thumb_height'); + } $xscale = ($max_height / $orig_height); $yscale = ($max_width / $orig_width); @@ -120,44 +146,10 @@ function get_thumbnail_size(int $orig_width, int $orig_height): array } /** - * Given a full size pair of dimensions, return a pair scaled down to fit - * into the configured thumbnail square, with ratio intact, using thumb_scaling + * Fetches the thumbnails height and width settings and applies the High-DPI scaling setting before returning the dimensions. * - * #return int[] + * @return array [width, height] */ -function get_thumbnail_size_scaled(int $orig_width, int $orig_height): array -{ - global $config; - - if ($orig_width === 0) { - $orig_width = 192; - } - if ($orig_height === 0) { - $orig_height = 192; - } - - if ($orig_width > $orig_height * 5) { - $orig_width = $orig_height * 5; - } - if ($orig_height > $orig_width * 5) { - $orig_height = $orig_width * 5; - } - - $max_size = get_thumbnail_max_size_scaled(); - $max_width = $max_size[0]; - $max_height = $max_size[1]; - - $xscale = ($max_height / $orig_height); - $yscale = ($max_width / $orig_width); - $scale = ($xscale < $yscale) ? $xscale : $yscale; - - if ($scale > 1 && $config->get_bool('thumb_upscale')) { - return [(int)$orig_width, (int)$orig_height]; - } else { - return [(int)($orig_width*$scale), (int)($orig_height*$scale)]; - } -} - function get_thumbnail_max_size_scaled(): array { global $config; @@ -168,7 +160,13 @@ function get_thumbnail_max_size_scaled(): array return [$max_width, $max_height]; } -function create_thumbnail_convert($hash): bool +/** + * Creates a thumbnail file using ImageMagick's convert command. + * + * @param $hash + * @return bool true is successful, false if not. + */ +function create_thumbnail_convert($hash): bool { global $config; @@ -187,9 +185,7 @@ function create_thumbnail_convert($hash): bool //$cmd = sprintf($format, $convert, $inname); //$size = shell_exec($cmd); //$size = explode(" ", trim($size)); - $tsize = get_thumbnail_max_size_scaled(); - $w = $tsize[0]; - $h = $tsize[1]; + list($w, $h) = get_thumbnail_max_size_scaled(); // running the call with cmd.exe requires quoting for our paths @@ -205,7 +201,6 @@ function create_thumbnail_convert($hash): bool $bg = "none"; } $format = '"%s" -flatten -strip -thumbnail %ux%u%s -quality %u -background %s "%s[0]" %s:"%s"'; - $cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg, $inname, $type, $outname); $cmd = str_replace("\"convert\"", "convert", $cmd); // quotes are only needed if the path to convert contains a space; some other times, quotes break things, see github bug #27 exec($cmd, $output, $ret); @@ -219,6 +214,12 @@ function create_thumbnail_convert($hash): bool return true; } +/** + * Creates a thumbnail using ffmpeg. + * + * @param $hash + * @return bool true if successful, false if not. + */ function create_thumbnail_ffmpeg($hash): bool { global $config; @@ -232,7 +233,7 @@ function create_thumbnail_ffmpeg($hash): bool $outname = warehouse_path("thumbs", $hash); $orig_size = video_size($inname); - $scaled_size = get_thumbnail_size_scaled($orig_size[0], $orig_size[1]); + $scaled_size = get_thumbnail_size($orig_size[0], $orig_size[1], true); $codec = "mjpeg"; $quality = $config->get_int("thumb_quality"); @@ -270,6 +271,12 @@ function create_thumbnail_ffmpeg($hash): bool } } +/** + * Determines the dimensions of a video file using ffmpeg. + * + * @param string $filename + * @return array [width, height] + */ function video_size(string $filename): array { global $config; @@ -307,6 +314,9 @@ function video_size(string $filename): array * * The factor of 2.5 is simply a rough guideline. * http://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize + * + * @param array $info The output of getimagesize() for the source file in question. + * @return int The number of bytes an image resize operation is estimated to use. */ function calc_memory_use(array $info): int { @@ -320,12 +330,25 @@ function calc_memory_use(array $info): int return (int)$memory_use; } +/** + * Performs a resize operation on an image file using GD. + * + * @param String $image_filename The source file to be resized. + * @param array $info The output of getimagesize() for the source file. + * @param int $new_width + * @param int $new_height + * @param string $output_filename + * @param string|null $output_type If set to null, the output file type will be automatically determined via the $info parameter. Otherwise an exception will be thrown. + * @param int $output_quality Defaults to 80. + * @throws ImageResizeException + * @throws InsufficientMemoryException if the estimated memory usage exceeds the memory limit. + */ function image_resize_gd( String $image_filename, array $info, int $new_width, int $new_height, - string $output_filename=null, + string $output_filename, string $output_type=null, int $output_quality = 80 ) { @@ -423,7 +446,7 @@ function image_resize_gd( throw new ImageResizeException("Unable to copy resized image data to new image"); } - $result = false; + switch ($output_type) { case "bmp": $result = imagebmp($image_resized, $output_filename, true); @@ -453,15 +476,20 @@ function image_resize_gd( } } -function is_animated_gif(String $image_filename) -{ - $isanigif = 0; +/** + * Determines if a file is an animated gif. + * + * @param String $image_filename The path of the file to check. + * @return bool true if the file is an animated gif, false if it is not. + */ +function is_animated_gif(String $image_filename) { + $is_anim_gif = 0; if (($fh = @fopen($image_filename, 'rb'))) { //check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) - while (!feof($fh) && $isanigif < 2) { + while (!feof($fh) && $is_anim_gif < 2) { $chunk = fread($fh, 1024 * 100); - $isanigif += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches); + $is_anim_gif += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches); } } - return ($isanigif == 0); -} + return ($is_anim_gif == 0); +} \ No newline at end of file diff --git a/ext/handle_pixel/main.php b/ext/handle_pixel/main.php index e10d8f75..daef5fe2 100644 --- a/ext/handle_pixel/main.php +++ b/ext/handle_pixel/main.php @@ -96,7 +96,7 @@ class PixelFileHandler extends DataHandlerExtension try { $info = getimagesize($inname); - $tsize = get_thumbnail_size_scaled($info[0], $info[1]); + $tsize = get_thumbnail_size($info[0], $info[1], true); $image = image_resize_gd( $inname, $info, From 85b6bba689f04a0a6d39f1272e1f9ef5d996cf1a Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 09:45:40 -0500 Subject: [PATCH 002/133] Changed path_to_tags to interpret ; as : and to allow inheriting categories from parent folders --- core/util.php | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/core/util.php b/core/util.php index 299463d8..57c7577e 100644 --- a/core/util.php +++ b/core/util.php @@ -281,21 +281,44 @@ function manual_include(string $fname): ?string function path_to_tags(string $path): string { $matches = []; - $tags = ""; - if (preg_match("/\d+ - (.*)\.([a-zA-Z0-9]+)/", basename($path), $matches)) { - $tags = $matches[1]; - } + $tags = []; + if(preg_match("/\d+ - (.*)\.([a-zA-Z0-9]+)/", basename($path), $matches)) { + $tags = explode($matches[1]," "); + } + + $path = dirname($path); + $path = str_replace(";", ":", $path); + $path = str_replace("__", " ", $path); - $dir_tags = dirname($path); - $dir_tags = str_replace("/", " ", $dir_tags); - $dir_tags = str_replace("__", " ", $dir_tags); - $dir_tags = trim($dir_tags); - if ($dir_tags != "") { - $tags = trim($tags)." ".trim($dir_tags); + + $category = ""; + foreach(explode("/", $path) as $dir) { + $category_to_inherit = ""; + foreach(explode(" ", $dir) as $tag) { + $tag = trim($tag); + if($tag=="") { + continue; + } + if(substr_compare($tag, ":", -1) === 0) { + // This indicates a tag that ends in a colon, + // which is for inheriting to tags on the subfolder + $category_to_inherit = $tag; + } else { + if($category!=""&&strpos($tag, ":") === false) { + // This indicates that category inheritance is active, + // and we've encountered a tag that does not specify a category. + // So we attach the inherited category to the tag. + $tag = $category.$tag; + } + array_push($tags, $tag); + } + } + // Category inheritance only works on the immediate subfolder, + // so we hold a category until the next iteration, and then set + // it back to an empty string after that iteration + $category = $category_to_inherit; } - $tags = trim($tags); - - return $tags; + return implode(" ",$tags); } From ed4b6bc4a0e6f5391f5204c1f48d6ec5e5564956 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 12:34:53 -0500 Subject: [PATCH 003/133] Updated handle_ico to use new common image thumbnailing and to inherit DataHandlerExtension --- core/extension.php | 6 +-- core/imageboard/misc.php | 10 +++-- ext/handle_flash/main.php | 2 +- ext/handle_ico/main.php | 83 +++++++++++---------------------------- ext/handle_mp3/main.php | 2 +- ext/handle_pixel/main.php | 7 ++-- ext/handle_svg/main.php | 2 +- ext/handle_video/main.php | 2 +- 8 files changed, 40 insertions(+), 74 deletions(-) diff --git a/core/extension.php b/core/extension.php index b7472583..af7bb6ad 100644 --- a/core/extension.php +++ b/core/extension.php @@ -222,13 +222,13 @@ abstract class DataHandlerExtension extends Extension $result = false; if ($this->supported_ext($event->type)) { if ($event->force) { - $result = $this->create_thumb($event->hash); + $result = $this->create_thumb($event->hash, $event->type); } else { $outname = warehouse_path("thumbs", $event->hash); if (file_exists($outname)) { return; } - $result = $this->create_thumb($event->hash); + $result = $this->create_thumb($event->hash, $event->type); } } if ($result) { @@ -256,5 +256,5 @@ abstract class DataHandlerExtension extends Extension abstract protected function supported_ext(string $ext): bool; abstract protected function check_contents(string $tmpname): bool; abstract protected function create_image_from_data(string $filename, array $metadata); - abstract protected function create_thumb(string $hash): bool; + abstract protected function create_thumb(string $hash, string $type): bool; } diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index 6336f8bb..e3e31576 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -164,9 +164,10 @@ function get_thumbnail_max_size_scaled(): array * Creates a thumbnail file using ImageMagick's convert command. * * @param $hash + * @param string $input_type Optional, allows specifying the input format. Usually not necessary. * @return bool true is successful, false if not. */ -function create_thumbnail_convert($hash): bool +function create_thumbnail_convert($hash, $input_type = ""): bool { global $config; @@ -200,8 +201,11 @@ function create_thumbnail_convert($hash): bool if ($type=="webp") { $bg = "none"; } - $format = '"%s" -flatten -strip -thumbnail %ux%u%s -quality %u -background %s "%s[0]" %s:"%s"'; - $cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg, $inname, $type, $outname); + if(!empty($input_type)) { + $input_type = $input_type.":"; + } + $format = '"%s" -flatten -strip -thumbnail %ux%u%s -quality %u -background %s %s"%s[0]" %s:"%s" 2>&1'; + $cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg,$input_type, $inname, $type, $outname); $cmd = str_replace("\"convert\"", "convert", $cmd); // quotes are only needed if the path to convert contains a space; some other times, quotes break things, see github bug #27 exec($cmd, $output, $ret); diff --git a/ext/handle_flash/main.php b/ext/handle_flash/main.php index 8da00583..9476499e 100644 --- a/ext/handle_flash/main.php +++ b/ext/handle_flash/main.php @@ -8,7 +8,7 @@ class FlashFileHandler extends DataHandlerExtension { - protected function create_thumb(string $hash): bool + protected function create_thumb(string $hash, string $type): bool { global $config; diff --git a/ext/handle_ico/main.php b/ext/handle_ico/main.php index 56e3f373..ab005c96 100644 --- a/ext/handle_ico/main.php +++ b/ext/handle_ico/main.php @@ -5,65 +5,45 @@ * Description: Handle windows icons */ -class IcoFileHandler extends Extension +class IcoFileHandler extends DataHandlerExtension { - public function onDataUpload(DataUploadEvent $event) + const SUPPORTED_EXTENSIONS = ["ico", "ani", "cur"]; + + + protected function supported_ext(string $ext): bool { - if ($this->supported_ext($event->type) && $this->check_contents($event->tmpname)) { - $hash = $event->hash; - $ha = substr($hash, 0, 2); - move_upload_to_archive($event); - send_event(new ThumbnailGenerationEvent($event->hash, $event->type)); - $image = $this->create_image_from_data("images/$ha/$hash", $event->metadata); - if (is_null($image)) { - throw new UploadException("Icon handler failed to create image object from data"); - } - $iae = new ImageAdditionEvent($image); - send_event($iae); - $event->image_id = $iae->image->id; - } + return in_array(strtolower($ext), self::SUPPORTED_EXTENSIONS); } - public function onDisplayingImage(DisplayingImageEvent $event) - { - global $page; - if ($this->supported_ext($event->image->ext)) { - $this->theme->display_image($page, $event->image); - } - } - - private function supported_ext(string $ext): bool - { - $exts = ["ico", "ani", "cur"]; - return in_array(strtolower($ext), $exts); - } - - private function create_image_from_data(string $filename, array $metadata) + protected function create_image_from_data(string $filename, array $metadata) { $image = new Image(); - $fp = fopen($filename, "r"); - $header = unpack("Snull/Stype/Scount", fread($fp, 6)); - $subheader = unpack("Cwidth/Cheight/Ccolours/Cnull/Splanes/Sbpp/Lsize/loffset", fread($fp, 16)); - fclose($fp); + $fp = fopen($filename, "r"); + try { + unpack("Snull/Stype/Scount", fread($fp, 6)); + $subheader = unpack("Cwidth/Cheight/Ccolours/Cnull/Splanes/Sbpp/Lsize/loffset", fread($fp, 16)); + } finally { + fclose($fp); + } $width = $subheader['width']; $height = $subheader['height']; $image->width = $width == 0 ? 256 : $width; $image->height = $height == 0 ? 256 : $height; - $image->filesize = $metadata['size']; - $image->hash = $metadata['hash']; - $image->filename = $metadata['filename']; - $image->ext = $metadata['extension']; + $image->filesize = $metadata['size']; + $image->hash = $metadata['hash']; + $image->filename = $metadata['filename']; + $image->ext = $metadata['extension']; $image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']); - $image->source = $metadata['source']; + $image->source = $metadata['source']; return $image; } - private function check_contents(string $file): bool + protected function check_contents(string $file): bool { if (!file_exists($file)) { return false; @@ -74,27 +54,8 @@ class IcoFileHandler extends Extension return ($header['null'] == 0 && ($header['type'] == 0 || $header['type'] == 1)); } - private function create_thumb(string $hash): bool + protected function create_thumb(string $hash, string $type): bool { - global $config; - - $inname = warehouse_path("images", $hash); - $outname = warehouse_path("thumbs", $hash); - - $tsize = get_thumbnail_size_scaled($width, $height); - $w = $tsize[0]; - $h = $tsise[1]; - - $q = $config->get_int("thumb_quality"); - $mem = $config->get_int("thumb_mem_limit") / 1024 / 1024; // IM takes memory in MB - - if ($config->get_bool("ico_convert")) { - // "-limit memory $mem" broken? - exec("convert {$inname}[0] -geometry {$w}x{$h} -quality {$q} jpg:$outname"); - } else { - copy($inname, $outname); - } - - return true; + return create_thumbnail_convert($hash, $type); } } diff --git a/ext/handle_mp3/main.php b/ext/handle_mp3/main.php index a3e3dc9c..13e2bab4 100644 --- a/ext/handle_mp3/main.php +++ b/ext/handle_mp3/main.php @@ -7,7 +7,7 @@ class MP3FileHandler extends DataHandlerExtension { - protected function create_thumb(string $hash): bool + protected function create_thumb(string $hash, string $type): bool { copy("ext/handle_mp3/thumb.jpg", warehouse_path("thumbs", $hash)); return true; diff --git a/ext/handle_pixel/main.php b/ext/handle_pixel/main.php index daef5fe2..a3bc3bd2 100644 --- a/ext/handle_pixel/main.php +++ b/ext/handle_pixel/main.php @@ -8,11 +8,12 @@ class PixelFileHandler extends DataHandlerExtension { + const SUPPORTED_EXTENSIONS = ["jpg", "jpeg", "gif", "png", "webp"]; + protected function supported_ext(string $ext): bool { - $exts = ["jpg", "jpeg", "gif", "png", "webp"]; $ext = (($pos = strpos($ext, '?')) !== false) ? substr($ext, 0, $pos) : $ext; - return in_array(strtolower($ext), $exts); + return in_array(strtolower($ext), self::SUPPORTED_EXTENSIONS); } protected function create_image_from_data(string $filename, array $metadata) @@ -53,7 +54,7 @@ class PixelFileHandler extends DataHandlerExtension return false; } - protected function create_thumb(string $hash): bool + protected function create_thumb(string $hash, string $type): bool { global $config; diff --git a/ext/handle_svg/main.php b/ext/handle_svg/main.php index 5676d24f..f2151c06 100644 --- a/ext/handle_svg/main.php +++ b/ext/handle_svg/main.php @@ -32,7 +32,7 @@ class SVGFileHandler extends DataHandlerExtension } } - protected function create_thumb(string $hash): bool + protected function create_thumb(string $hash, string $type): bool { if (!create_thumbnail_convert($hash)) { copy("ext/handle_svg/thumb.jpg", warehouse_path("thumbs", $hash)); diff --git a/ext/handle_video/main.php b/ext/handle_video/main.php index 316139c8..f4f50320 100644 --- a/ext/handle_video/main.php +++ b/ext/handle_video/main.php @@ -53,7 +53,7 @@ class VideoFileHandler extends DataHandlerExtension /** * Generate the Thumbnail image for particular file. */ - protected function create_thumb(string $hash): bool + protected function create_thumb(string $hash, string $type): bool { return create_thumbnail_ffmpeg($hash); } From 070429402bd279455618de35c7f1d698ea0e253a Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 12:45:15 -0500 Subject: [PATCH 004/133] readme corrections --- README.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index bd71aa06..23dec0ee 100644 --- a/README.markdown +++ b/README.markdown @@ -99,21 +99,21 @@ For example, one can override the default anonymous "allow nothing" permissions like so: ```php -new UserClass("anonymous", "base", array( +new UserClass("anonymous", "base", [ "create_comment" => True, "edit_image_tag" => True, "edit_image_source" => True, "create_image_report" => True, -)); +]); ``` For a moderator class, being a regular user who can delete images and comments: ```php -new UserClass("moderator", "user", array( +new UserClass("moderator", "user", [ "delete_image" => True, "delete_comment" => True, -)); +]); ``` For a list of permissions, see `core/userclass.php` From 58acb7128278c1523d9279ac8b81a8dfedb00a98 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 12:59:12 -0500 Subject: [PATCH 005/133] Change imagemagick commands to return the error output Added ico to transcode extension --- core/imageboard/misc.php | 7 +++++-- ext/transcode/main.php | 14 +++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index e3e31576..e9bd93c6 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -208,8 +208,11 @@ function create_thumbnail_convert($hash, $input_type = ""): bool $cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg,$input_type, $inname, $type, $outname); $cmd = str_replace("\"convert\"", "convert", $cmd); // quotes are only needed if the path to convert contains a space; some other times, quotes break things, see github bug #27 exec($cmd, $output, $ret); - - log_debug('handle_pixel', "Generating thumbnail with command `$cmd`, returns $ret"); + if ($ret!=0) { + log_warning('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret, outputting ".implode("\r\n",$output)); + } else { + log_debug('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret"); + } if ($config->get_bool("thumb_optim", false)) { exec("jpegoptim $outname", $output, $ret); diff --git a/ext/transcode/main.php b/ext/transcode/main.php index 85c554d8..aa471d0a 100644 --- a/ext/transcode/main.php +++ b/ext/transcode/main.php @@ -43,6 +43,7 @@ class TranscodeImage extends Extension "psd", "tiff", "webp", + "ico", ] ]; @@ -68,6 +69,7 @@ class TranscodeImage extends Extension const INPUT_FORMATS = [ "BMP" => "bmp", "GIF" => "gif", + "ICO" => "ico", "JPG" => "jpg", "PNG" => "png", "PSD" => "psd", @@ -440,15 +442,21 @@ class TranscodeImage extends Extension } $tmp_name = tempnam("/tmp", "shimmie_transcode"); - $format = '"%s" %s -quality %u -background %s "%s" %s:"%s"'; - $cmd = sprintf($format, $convert, $args, $q, $bg, $source_name, $ext, $tmp_name); + $source_type = ""; + switch ($source_format) { + case "ico": + $source_type = "ico:"; + } + + $format = '"%s" %s -quality %u -background %s %s"%s" %s:"%s" 2>&1'; + $cmd = sprintf($format, $convert, $args, $q, $bg, $source_type, $source_name, $ext, $tmp_name); $cmd = str_replace("\"convert\"", "convert", $cmd); // quotes are only needed if the path to convert contains a space; some other times, quotes break things, see github bug #27 exec($cmd, $output, $ret); log_debug('transcode', "Transcoding with command `$cmd`, returns $ret"); if ($ret!==0) { - throw new ImageTranscodeException("Transcoding failed with command ".$cmd); + throw new ImageTranscodeException("Transcoding failed with command ".$cmd.", returning ".implode("\r\n", $output)); } return $tmp_name; From 8950d27d642a41a1a9819fad5bd113d2ff540c7e Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 12:59:58 -0500 Subject: [PATCH 006/133] Changed upload to detect unrecognized files so that it doesn't just blankly refresh when the type isn't handled --- ext/upload/main.php | 55 ++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/ext/upload/main.php b/ext/upload/main.php index f42f1360..e0274346 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -27,7 +27,6 @@ class DataUploadEvent extends Event public $merged = false; - /** * Some data is being uploaded. * This should be caught by a file handler. @@ -49,10 +48,10 @@ class DataUploadEvent extends Event if ($config->get_bool("upload_use_mime")) { $this->set_type(get_extension_from_mime($tmpname)); } else { - if (array_key_exists('extension', $metadata)&&!empty($metadata['extension'])) { + if (array_key_exists('extension', $metadata) && !empty($metadata['extension'])) { $this->type = strtolower($metadata['extension']); } else { - throw new UploadException("Could not determine extension for file ".$metadata["filename"]); + throw new UploadException("Could not determine extension for file " . $metadata["filename"]); } } } @@ -130,9 +129,9 @@ class Upload extends Extension $sb->position = 10; // Output the limits from PHP so the user has an idea of what they can set. $sb->add_int_option("upload_count", "Max uploads: "); - $sb->add_label("PHP Limit = ".ini_get('max_file_uploads').""); + $sb->add_label("PHP Limit = " . ini_get('max_file_uploads') . ""); $sb->add_shorthand_int_option("upload_size", "
Max size per file: "); - $sb->add_label("PHP Limit = ".ini_get('upload_max_filesize').""); + $sb->add_label("PHP Limit = " . ini_get('upload_max_filesize') . ""); $sb->add_choice_option("transload_engine", $tes, "
Transload: "); $sb->add_bool_option("upload_tlsource", "
Use transloaded URL as source if none is provided: "); $sb->add_bool_option("upload_use_mime", "
Use mime type to determine file types: "); @@ -190,10 +189,10 @@ class Upload extends Extension if (count($_FILES) > 1) { throw new UploadException("Can not upload more than one image for replacing."); } - + $source = isset($_POST['source']) ? $_POST['source'] : null; $tags = []; // Tags aren't changed when replacing. Set to empty to stop PHP warnings. - + $ok = false; if (count($_FILES)) { foreach ($_FILES as $file) { @@ -249,7 +248,7 @@ class Upload extends Extension if (!empty($_GET['tags']) && $_GET['tags'] != "null") { $tags = Tag::explode($_GET['tags']); } - + $ok = $this->try_transload($url, $tags, $source); $this->theme->display_upload_status($page, $ok); } else { @@ -314,7 +313,7 @@ class Upload extends Extension * #param string[] $file * #param string[] $tags */ - private function try_upload(array $file, array $tags, ?string $source=null, int $replace=-1): bool + private function try_upload(array $file, array $tags, ?string $source = null, int $replace = -1): bool { global $page; @@ -331,7 +330,7 @@ class Upload extends Extension if ($file['error'] !== UPLOAD_ERR_OK) { throw new UploadException($this->upload_error_message($file['error'])); } - + $pathinfo = pathinfo($file['name']); $metadata = []; $metadata['filename'] = $pathinfo['basename']; @@ -340,19 +339,22 @@ class Upload extends Extension } $metadata['tags'] = $tags; $metadata['source'] = $source; - + /* check if we have been given an image ID to replace */ if ($replace >= 0) { $metadata['replace'] = $replace; } - + $event = new DataUploadEvent($file['tmp_name'], $metadata); send_event($event); - $page->add_http_header("X-Shimmie-Image-ID: ".int_escape($event->image_id)); + if ($event->image_id == -1) { + throw new UploadException("File type not supported: " . $metadata['extension']); + } + $page->add_http_header("X-Shimmie-Image-ID: " . int_escape($event->image_id)); } catch (UploadException $ex) { $this->theme->display_upload_error( $page, - "Error with ".html_escape($file['name']), + "Error with " . html_escape($file['name']), $ex->getMessage() ); $ok = false; @@ -362,7 +364,7 @@ class Upload extends Extension return $ok; } - private function try_transload(string $url, array $tags, string $source=null, int $replace=-1): bool + private function try_transload(string $url, array $tags, string $source = null, int $replace = -1): bool { global $page, $config, $user; @@ -372,7 +374,7 @@ class Upload extends Extension if ($user->can("edit_image_lock") && !empty($_GET['locked'])) { $locked = bool_escape($_GET['locked']); } - + // Checks if url contains rating, also checks if the rating extension is enabled. if ($config->get_string("transload_engine", "none") != "none" && ext_is_live("Ratings") && !empty($_GET['rating'])) { // Rating event will validate that this is s/q/e/u @@ -386,7 +388,7 @@ class Upload extends Extension // transload() returns Array or Bool, depending on the transload_engine. $headers = transload($url, $tmp_filename); - + $s_filename = is_array($headers) ? findHeader($headers, 'Content-Disposition') : null; $h_filename = ($s_filename ? preg_replace('/^.*filename="([^ ]+)"/i', '$1', $s_filename) : null); $filename = $h_filename ?: basename($url); @@ -394,8 +396,8 @@ class Upload extends Extension if (!$headers) { $this->theme->display_upload_error( $page, - "Error with ".html_escape($filename), - "Error reading from ".html_escape($url) + "Error with " . html_escape($filename), + "Error reading from " . html_escape($url) ); return false; } @@ -403,7 +405,7 @@ class Upload extends Extension if (filesize($tmp_filename) == 0) { $this->theme->display_upload_error( $page, - "Error with ".html_escape($filename), + "Error with " . html_escape($filename), "No data found -- perhaps the site has hotlink protection?" ); $ok = false; @@ -413,7 +415,7 @@ class Upload extends Extension $metadata['filename'] = $filename; $metadata['tags'] = $tags; $metadata['source'] = (($url == $source) && !$config->get_bool('upload_tlsource') ? "" : $source); - + $ext = false; if (is_array($headers)) { $ext = get_extension(findHeader($headers, 'Content-Type')); @@ -422,7 +424,7 @@ class Upload extends Extension $ext = $pathinfo['extension']; } $metadata['extension'] = $ext; - + /* check for locked > adds to metadata if it has */ if (!empty($locked)) { $metadata['locked'] = $locked ? "on" : ""; @@ -432,19 +434,22 @@ class Upload extends Extension if (!empty($rating)) { $metadata['rating'] = $rating; } - + /* check if we have been given an image ID to replace */ if ($replace >= 0) { $metadata['replace'] = $replace; } - + try { $event = new DataUploadEvent($tmp_filename, $metadata); send_event($event); + if ($event->image_id == -1) { + throw new UploadException("File type not supported: " . $metadata['extension']); + } } catch (UploadException $ex) { $this->theme->display_upload_error( $page, - "Error with ".html_escape($url), + "Error with " . html_escape($url), $ex->getMessage() ); $ok = false; From 444de26ce3ea32e91aae8cd5407b84fe546894bb Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 13:33:47 -0500 Subject: [PATCH 007/133] Added warning for webp thumbnails --- ext/image/main.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/image/main.php b/ext/image/main.php index b2fe5722..56405d65 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -141,7 +141,7 @@ class ImageIO extends Extension $thumb_types = []; $thumb_types['JPEG'] = "jpg"; - $thumb_types['WEBP'] = "webp"; + $thumb_types['WEBP (Not IE/Safari compatible)'] = "webp"; $sb = new SetupBlock("Thumbnailing"); From 6f501a6e74bb7e3cf52da8c315de2daed9d6362d Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Fri, 14 Jun 2019 13:17:03 -0500 Subject: [PATCH 008/133] Database driver constants --- core/_install.php | 14 +++++++------- core/database.php | 22 +++++++++++++--------- core/dbengine.php | 6 +++--- core/imageboard/image.php | 4 ++-- core/user.php | 2 +- ext/admin/main.php | 12 ++++++------ ext/admin/theme.php | 2 +- ext/comment/main.php | 4 ++-- ext/index/test.php | 2 +- ext/ipban/main.php | 2 +- ext/ipban/theme.php | 2 +- ext/log_db/main.php | 2 +- ext/rating/main.php | 6 +++--- ext/relatationships/main.php | 2 +- ext/rss_comments/main.php | 2 +- ext/rule34/main.php | 2 +- ext/rule34/theme.php | 2 +- ext/tips/main.php | 2 +- ext/upgrade/main.php | 12 ++++++------ 19 files changed, 53 insertions(+), 49 deletions(-) diff --git a/core/_install.php b/core/_install.php index dcc622be..99fa864d 100644 --- a/core/_install.php +++ b/core/_install.php @@ -110,7 +110,7 @@ function do_install() { // {{{ if (file_exists("data/config/auto_install.conf.php")) { require_once "data/config/auto_install.conf.php"; - } elseif (@$_POST["database_type"] == "sqlite") { + } elseif (@$_POST["database_type"] == Database::SQLITE_DRIVER) { $id = bin2hex(random_bytes(5)); define('DATABASE_DSN', "sqlite:data/shimmie.{$id}.sqlite"); } elseif (isset($_POST['database_type']) && isset($_POST['database_host']) && isset($_POST['database_user']) && isset($_POST['database_name'])) { @@ -153,9 +153,9 @@ function ask_questions() $drivers = PDO::getAvailableDrivers(); if ( - !in_array("mysql", $drivers) && - !in_array("pgsql", $drivers) && - !in_array("sqlite", $drivers) + !in_array(Database::MYSQL_DRIVER, $drivers) && + !in_array(Database::PGSQL_DRIVER, $drivers) && + !in_array(Database::SQLITE_DRIVER, $drivers) ) { $errors[] = " No database connection library could be found; shimmie needs @@ -163,9 +163,9 @@ function ask_questions() "; } - $db_m = in_array("mysql", $drivers) ? '' : ""; - $db_p = in_array("pgsql", $drivers) ? '' : ""; - $db_s = in_array("sqlite", $drivers) ? '' : ""; + $db_m = in_array(Database::MYSQL_DRIVER, $drivers) ? '' : ""; + $db_p = in_array(Database::PGSQL_DRIVER, $drivers) ? '' : ""; + $db_s = in_array(Database::SQLITE_DRIVER, $drivers) ? '' : ""; $warn_msg = $warnings ? "

Warnings

".implode("\n

", $warnings) : ""; $err_msg = $errors ? "

Errors

".implode("\n

", $errors) : ""; diff --git a/core/database.php b/core/database.php index c6135878..29381209 100644 --- a/core/database.php +++ b/core/database.php @@ -4,6 +4,10 @@ */ class Database { + const MYSQL_DRIVER = "mysql"; + const PGSQL_DRIVER = "pgsql"; + const SQLITE_DRIVER = "sqlite"; + /** * The PDO database connection object, for anyone who wants direct access. * @var null|PDO @@ -72,7 +76,7 @@ class Database // https://bugs.php.net/bug.php?id=70221 $ka = DATABASE_KA; - if (version_compare(PHP_VERSION, "6.9.9") == 1 && $this->get_driver_name() == "sqlite") { + if (version_compare(PHP_VERSION, "6.9.9") == 1 && $this->get_driver_name() == self::SQLITE_DRIVER) { $ka = false; } @@ -96,11 +100,11 @@ class Database throw new SCoreException("Can't figure out database engine"); } - if ($db_proto === "mysql") { + if ($db_proto === self::MYSQL_DRIVER) { $this->engine = new MySQL(); - } elseif ($db_proto === "pgsql") { + } elseif ($db_proto === self::PGSQL_DRIVER) { $this->engine = new PostgreSQL(); - } elseif ($db_proto === "sqlite") { + } elseif ($db_proto === self::SQLITE_DRIVER) { $this->engine = new SQLite(); } else { die('Unknown PDO driver: '.$db_proto); @@ -224,7 +228,7 @@ class Database } return $stmt; } catch (PDOException $pdoe) { - throw new SCoreException($pdoe->getMessage()."

Query: ".$query); + throw new SCoreException($pdoe->getMessage()."

Query: ".$query, $pdoe->getCode(), $pdoe); } } @@ -296,7 +300,7 @@ class Database */ public function get_last_insert_id(string $seq): int { - if ($this->engine->name == "pgsql") { + if ($this->engine->name == self::PGSQL_DRIVER) { return $this->db->lastInsertId($seq); } else { return $this->db->lastInsertId(); @@ -326,15 +330,15 @@ class Database $this->connect_db(); } - if ($this->engine->name === "mysql") { + if ($this->engine->name === self::MYSQL_DRIVER) { return count( $this->get_all("SHOW TABLES") ); - } elseif ($this->engine->name === "pgsql") { + } elseif ($this->engine->name === self::PGSQL_DRIVER) { return count( $this->get_all("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'") ); - } elseif ($this->engine->name === "sqlite") { + } elseif ($this->engine->name === self::SQLITE_DRIVER) { return count( $this->get_all("SELECT name FROM sqlite_master WHERE type = 'table'") ); diff --git a/core/dbengine.php b/core/dbengine.php index bb7c674b..d76a1a43 100644 --- a/core/dbengine.php +++ b/core/dbengine.php @@ -22,7 +22,7 @@ class DBEngine class MySQL extends DBEngine { /** @var string */ - public $name = "mysql"; + public $name = Database::MYSQL_DRIVER; public function init(PDO $db) { @@ -54,7 +54,7 @@ class MySQL extends DBEngine class PostgreSQL extends DBEngine { /** @var string */ - public $name = "pgsql"; + public $name = Database::PGSQL_DRIVER; public function init(PDO $db) { @@ -136,7 +136,7 @@ function _ln($n) class SQLite extends DBEngine { /** @var string */ - public $name = "sqlite"; + public $name = Database::SQLITE_DRIVER; public function init(PDO $db) { diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 928d4914..af6a15d8 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -590,7 +590,7 @@ class Image public function delete_tags_from_image(): void { global $database; - if ($database->get_driver_name() == "mysql") { + if ($database->get_driver_name() == Database::MYSQL_DRIVER) { //mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this $database->execute( " @@ -907,7 +907,7 @@ class Image // more than one positive tag, or more than zero negative tags else { - if ($database->get_driver_name() === "mysql") { + if ($database->get_driver_name() === Database::MYSQL_DRIVER) { $query = Image::build_ugly_search_querylet($tag_querylets); } else { $query = Image::build_accurate_search_querylet($tag_querylets); diff --git a/core/user.php b/core/user.php index 098c7723..a2a4d537 100644 --- a/core/user.php +++ b/core/user.php @@ -69,7 +69,7 @@ class User global $config, $database; $row = $database->cache->get("user-session:$name-$session"); if (!$row) { - if ($database->get_driver_name() === "mysql") { + if ($database->get_driver_name() === Database::MYSQL_DRIVER) { $query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess"; } else { $query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess"; diff --git a/ext/admin/main.php b/ext/admin/main.php index 212b07fb..2b484bc1 100644 --- a/ext/admin/main.php +++ b/ext/admin/main.php @@ -201,14 +201,14 @@ class AdminPage extends Extension $database = $matches['dbname']; switch ($software) { - case 'mysql': + case Database::MYSQL_DRIVER: $cmd = "mysqldump -h$hostname -u$username -p$password $database"; break; - case 'pgsql': + case Database::PGSQL_DRIVER: putenv("PGPASSWORD=$password"); $cmd = "pg_dump -h $hostname -U $username $database"; break; - case 'sqlite': + case Database::SQLITE_DRIVER: $cmd = "sqlite3 $database .dump"; break; default: @@ -257,7 +257,7 @@ class AdminPage extends Extension //TODO: Update score_log (Having an optional ID column for score_log would be nice..) preg_match("#^(?P\w+)\:(?:user=(?P\w+)(?:;|$)|password=(?P\w*)(?:;|$)|host=(?P[\w\.\-]+)(?:;|$)|dbname=(?P[\w_]+)(?:;|$))+#", DATABASE_DSN, $matches); - if ($matches['proto'] == "mysql") { + if ($matches['proto'] == Database::MYSQL_DRIVER) { $tables = $database->get_col("SELECT TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = :db @@ -280,9 +280,9 @@ class AdminPage extends Extension $i++; } $database->execute("ALTER TABLE images AUTO_INCREMENT=".(count($ids) + 1)); - } elseif ($matches['proto'] == "pgsql") { + } elseif ($matches['proto'] == Database::PGSQL_DRIVER) { //TODO: Make this work with PostgreSQL - } elseif ($matches['proto'] == "sqlite") { + } elseif ($matches['proto'] == Database::SQLITE_DRIVER) { //TODO: Make this work with SQLite } return true; diff --git a/ext/admin/theme.php b/ext/admin/theme.php index 3e60d224..5d3de30f 100644 --- a/ext/admin/theme.php +++ b/ext/admin/theme.php @@ -45,7 +45,7 @@ class AdminPageTheme extends Themelet $html .= $this->button("Download all images", "download_all_images", false); } $html .= $this->button("Download database contents", "database_dump", false); - if ($database->get_driver_name() == "mysql") { + if ($database->get_driver_name() == Database::MYSQL_DRIVER) { $html .= $this->button("Reset image IDs", "reset_image_ids", true); } $page->add_block(new Block("Misc Admin Tools", $html)); diff --git a/ext/comment/main.php b/ext/comment/main.php index 85a9672b..75b171d4 100644 --- a/ext/comment/main.php +++ b/ext/comment/main.php @@ -480,14 +480,14 @@ class CommentList extends Extension global $config, $database; // sqlite fails at intervals - if ($database->get_driver_name() === "sqlite") { + if ($database->get_driver_name() === Database::SQLITE_DRIVER) { return false; } $window = int_escape($config->get_int('comment_window')); $max = int_escape($config->get_int('comment_limit')); - if ($database->get_driver_name() == "mysql") { + if ($database->get_driver_name() == Database::MYSQL_DRIVER) { $window_sql = "interval $window minute"; } else { $window_sql = "interval '$window minute'"; diff --git a/ext/index/test.php b/ext/index/test.php index e9debe74..8f57bdb2 100644 --- a/ext/index/test.php +++ b/ext/index/test.php @@ -157,7 +157,7 @@ class IndexTest extends ShimmiePHPUnitTestCase global $database; $db = $database->get_driver_name(); - if ($db == "pgsql" || $db == "sqlite") { + if ($db == Database::PGSQL_DRIVER || $db == Database::SQLITE_DRIVER) { $this->markTestIncomplete(); } diff --git a/ext/ipban/main.php b/ext/ipban/main.php index 659246f9..541c853b 100644 --- a/ext/ipban/main.php +++ b/ext/ipban/main.php @@ -235,7 +235,7 @@ class IPBan extends Extension { global $config, $database; - $prefix = ($database->get_driver_name() == "sqlite" ? "bans." : ""); + $prefix = ($database->get_driver_name() == Database::SQLITE_DRIVER ? "bans." : ""); $bans = $this->get_active_bans(); diff --git a/ext/ipban/theme.php b/ext/ipban/theme.php index 6529c51f..67979128 100644 --- a/ext/ipban/theme.php +++ b/ext/ipban/theme.php @@ -16,7 +16,7 @@ class IPBanTheme extends Themelet { global $database, $user; $h_bans = ""; - $prefix = ($database->get_driver_name() == "sqlite" ? "bans." : ""); + $prefix = ($database->get_driver_name() == Database::SQLITE_DRIVER ? "bans." : ""); foreach ($bans as $ban) { $end_human = date('Y-m-d', $ban[$prefix.'end_timestamp']); $h_bans .= " diff --git a/ext/log_db/main.php b/ext/log_db/main.php index b185c783..5b400b12 100644 --- a/ext/log_db/main.php +++ b/ext/log_db/main.php @@ -68,7 +68,7 @@ class LogDatabase extends Extension $args["module"] = $_GET["module"]; } if (!empty($_GET["user"])) { - if ($database->get_driver_name() == "pgsql") { + if ($database->get_driver_name() == Database::PGSQL_DRIVER) { if (preg_match("#\d+\.\d+\.\d+\.\d+(/\d+)?#", $_GET["user"])) { $wheres[] = "(username = :user1 OR text(address) = :user2)"; $args["user1"] = $_GET["user"]; diff --git a/ext/rating/main.php b/ext/rating/main.php index 18b40823..9f32280d 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -37,7 +37,7 @@ class RatingSetEvent extends Event class Ratings extends Extension { - protected $db_support = ['mysql','pgsql']; // ? + protected $db_support = [Database::MYSQL_DRIVER,Database::PGSQL_DRIVER]; public function get_priority(): int { @@ -331,10 +331,10 @@ class Ratings extends Extension if ($config->get_int("ext_ratings2_version") < 3) { $database->Execute("UPDATE images SET rating = 'u' WHERE rating is null"); switch ($database->get_driver_name()) { - case "mysql": + case Database::MYSQL_DRIVER: $database->Execute("ALTER TABLE images CHANGE rating rating CHAR(1) NOT NULL DEFAULT 'u'"); break; - case "pgsql": + case Database::PGSQL_DRIVER: $database->Execute("ALTER TABLE images ALTER COLUMN rating SET DEFAULT 'u'"); $database->Execute("ALTER TABLE images ALTER COLUMN rating SET NOT NULL"); break; diff --git a/ext/relatationships/main.php b/ext/relatationships/main.php index 28e785d1..402f4fd0 100644 --- a/ext/relatationships/main.php +++ b/ext/relatationships/main.php @@ -8,7 +8,7 @@ class Relationships extends Extension { - protected $db_support = ['mysql', 'pgsql']; + protected $db_support = [Database::MYSQL_DRIVER, Database::PGSQL_DRIVER]; public function onInitExt(InitExtEvent $event) { diff --git a/ext/rss_comments/main.php b/ext/rss_comments/main.php index 4f3b5ed5..dfc37717 100644 --- a/ext/rss_comments/main.php +++ b/ext/rss_comments/main.php @@ -9,7 +9,7 @@ class RSS_Comments extends Extension { - protected $db_support = ['mysql', 'sqlite']; // pgsql has no UNIX_TIMESTAMP + protected $db_support = [Database::MYSQL_DRIVER, Database::SQLITE_DRIVER]; // pgsql has no UNIX_TIMESTAMP public function onPostListBuilding(PostListBuildingEvent $event) { diff --git a/ext/rule34/main.php b/ext/rule34/main.php index a39b6949..577ca5af 100644 --- a/ext/rule34/main.php +++ b/ext/rule34/main.php @@ -19,7 +19,7 @@ if ( // kill these glitched requests immediately class Rule34 extends Extension { - protected $db_support = ['pgsql']; # Only PG has the NOTIFY pubsub system + protected $db_support = [Database::PGSQL_DRIVER]; # Only PG has the NOTIFY pubsub system public function onImageDeletion(ImageDeletionEvent $event) { diff --git a/ext/rule34/theme.php b/ext/rule34/theme.php index 09712b3d..d4dd29e1 100644 --- a/ext/rule34/theme.php +++ b/ext/rule34/theme.php @@ -19,7 +19,7 @@ class Rule34Theme extends Themelet { global $database, $user; $h_bans = ""; - $prefix = ($database->get_driver_name() == "sqlite" ? "bans." : ""); + $prefix = ($database->get_driver_name() == Database::SQLITE_DRIVER ? "bans." : ""); foreach ($bans as $ban) { $h_bans .= " diff --git a/ext/tips/main.php b/ext/tips/main.php index f4f7d619..04fb5124 100644 --- a/ext/tips/main.php +++ b/ext/tips/main.php @@ -10,7 +10,7 @@ class Tips extends Extension { - protected $db_support = ['mysql', 'sqlite']; // rand() ? + protected $db_support = [Database::MYSQL_DRIVER, Database::SQLITE_DRIVER]; // rand() ? public function onInitExt(InitExtEvent $event) { diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index 3321b409..0aef4530 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -44,7 +44,7 @@ class Upgrade extends Extension $config->set_bool("in_upgrade", true); $config->set_int("db_version", 9); - if ($database->get_driver_name() == 'mysql') { + if ($database->get_driver_name() == Database::MYSQL_DRIVER) { $tables = $database->get_col("SHOW TABLES"); foreach ($tables as $table) { log_info("upgrade", "converting $table to innodb"); @@ -84,7 +84,7 @@ class Upgrade extends Extension $config->set_bool("in_upgrade", true); $config->set_int("db_version", 12); - if ($database->get_driver_name() == 'pgsql') { + if ($database->get_driver_name() == Database::PGSQL_DRIVER) { log_info("upgrade", "Changing ext column to VARCHAR"); $database->execute("ALTER TABLE images ALTER COLUMN ext SET DATA TYPE VARCHAR(4)"); } @@ -101,9 +101,9 @@ class Upgrade extends Extension $config->set_int("db_version", 13); log_info("upgrade", "Changing password column to VARCHAR(250)"); - if ($database->get_driver_name() == 'pgsql') { + if ($database->get_driver_name() == Database::PGSQL_DRIVER) { $database->execute("ALTER TABLE users ALTER COLUMN pass SET DATA TYPE VARCHAR(250)"); - } elseif ($database->get_driver_name() == 'mysql') { + } elseif ($database->get_driver_name() == Database::MYSQL_DRIVER) { $database->execute("ALTER TABLE users CHANGE pass pass VARCHAR(250)"); } @@ -116,11 +116,11 @@ class Upgrade extends Extension $config->set_int("db_version", 14); log_info("upgrade", "Changing tag column to VARCHAR(255)"); - if ($database->get_driver_name() == 'pgsql') { + if ($database->get_driver_name() == Database::PGSQL_DRIVER) { $database->execute('ALTER TABLE tags ALTER COLUMN tag SET DATA TYPE VARCHAR(255)'); $database->execute('ALTER TABLE aliases ALTER COLUMN oldtag SET DATA TYPE VARCHAR(255)'); $database->execute('ALTER TABLE aliases ALTER COLUMN newtag SET DATA TYPE VARCHAR(255)'); - } elseif ($database->get_driver_name() == 'mysql') { + } elseif ($database->get_driver_name() == Database::MYSQL_DRIVER) { $database->execute('ALTER TABLE tags MODIFY COLUMN tag VARCHAR(255) NOT NULL'); $database->execute('ALTER TABLE aliases MODIFY COLUMN oldtag VARCHAR(255) NOT NULL'); $database->execute('ALTER TABLE aliases MODIFY COLUMN newtag VARCHAR(255) NOT NULL'); From e940d87c229daab775dfc7ad4876d91c54319c67 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 10:02:08 -0500 Subject: [PATCH 009/133] Added image_id null check to resize's data upload event, to prevent an error when merging is enabled --- ext/resize/main.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/resize/main.php b/ext/resize/main.php index 41eabde0..35fd537f 100644 --- a/ext/resize/main.php +++ b/ext/resize/main.php @@ -62,6 +62,10 @@ class ResizeImage extends Extension { global $config, $page; + if($event->image_id==null) { + return; + } + $image_obj = Image::by_id($event->image_id); if ($config->get_bool("resize_upload") == true && ($image_obj->ext == "jpg" || $image_obj->ext == "png" || $image_obj->ext == "gif" || $image_obj->ext == "webp")) { From 0202597f88b602d294117b32f06eacad9429f2b9 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 11:01:13 -0500 Subject: [PATCH 010/133] Added lock file usage to cron uploader to prevent concurrent runs. Changed extension manager to allow author to be a comma-separated list. --- ext/cron_uploader/main.php | 187 ++++++++++++++++++++----------------- ext/ext_manager/main.php | 54 +++++++---- ext/ext_manager/theme.php | 41 ++++---- 3 files changed, 162 insertions(+), 120 deletions(-) diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index f4bd3c51..fe1bbfbf 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -1,42 +1,44 @@ + * Authors: YaoiFox , Matthew Barbour * Link: http://www.yaoifox.com/ * License: GPLv2 * Description: Uploads images automatically using Cron Jobs * Documentation: Installation guide: activate this extension and navigate to www.yoursite.com/cron_upload */ + class CronUploader extends Extension { // TODO: Checkbox option to only allow localhost + a list of additional IP adresses that can be set in /cron_upload // TODO: Change logging to MySQL + display log at /cron_upload // TODO: Move stuff to theme.php - + /** * Lists all log events this session * @var string */ private $upload_info = ""; - + /** * Lists all files & info required to upload. * @var array */ private $image_queue = []; - + /** * Cron Uploader root directory * @var string */ private $root_dir = ""; - + /** * Key used to identify uploader * @var string */ private $upload_key = ""; - + /** * Checks if the cron upload page has been accessed * and initializes the upload. @@ -44,39 +46,50 @@ class CronUploader extends Extension public function onPageRequest(PageRequestEvent $event) { global $config, $user; - + if ($event->page_matches("cron_upload")) { $this->upload_key = $config->get_string("cron_uploader_key", ""); - + // If the key is in the url, upload if ($this->upload_key != "" && $event->get_arg(0) == $this->upload_key) { // log in as admin - $this->process_upload(); // Start upload + $this->set_dir(); + + $lockfile = fopen($this->root_dir . "/.lock", "w"); + try { + if (!flock($lockfile, LOCK_EX | LOCK_NB)) { + throw new Exception("Cron upload process is already running"); + } + $this->process_upload(); // Start upload + } finally { + flock($lockfile, LOCK_UN); + fclose($lockfile); + } } elseif ($user->is_admin()) { $this->set_dir(); $this->display_documentation(); } } } - + private function display_documentation() { global $page; $this->set_dir(); // Determines path to cron_uploader_dir - - + + $queue_dir = $this->root_dir . "/queue"; $uploaded_dir = $this->root_dir . "/uploaded"; $failed_dir = $this->root_dir . "/failed_to_upload"; - + $queue_dirinfo = $this->scan_dir($queue_dir); $uploaded_dirinfo = $this->scan_dir($uploaded_dir); $failed_dirinfo = $this->scan_dir($failed_dir); - + $cron_url = make_http(make_link("/cron_upload/" . $this->upload_key)); $cron_cmd = "curl --silent $cron_url"; $log_path = $this->root_dir . "/uploads.log"; - + $info_html = "Information
@@ -105,7 +118,7 @@ class CronUploader extends Extension
Cron Command:
Create a cron job with the command above.
Read the documentation if you're not sure what to do.
"; - + $install_html = " This cron uploader is fairly easy to use but has to be configured first.
1. Install & activate this plugin. @@ -130,8 +143,10 @@ class CronUploader extends Extension
So when you want to manually upload an image, all you have to do is open the link once.
This link can be found under 'Cron Command' in the board config, just remove the 'wget ' part and only the url remains.
($cron_url)"; - - + + $page->set_title("Cron Uploader"); + $page->set_heading("Cron Uploader"); + $block = new Block("Cron Uploader", $info_html, "main", 10); $block_install = new Block("Installation Guide", $install_html, "main", 20); $page->add_block($block); @@ -143,35 +158,35 @@ class CronUploader extends Extension global $config; // Set default values $this->upload_key = $config->get_string("cron_uploader_key", ""); - if (strlen($this->upload_key)<=0) { + if (strlen($this->upload_key) <= 0) { $this->upload_key = $this->generate_key(); - + $config->set_default_int('cron_uploader_count', 1); $config->set_default_string('cron_uploader_key', $this->upload_key); $this->set_dir(); } } - + public function onSetupBuilding(SetupBuildingEvent $event) { $this->set_dir(); - + $cron_url = make_http(make_link("/cron_upload/" . $this->upload_key)); $cron_cmd = "curl --silent $cron_url"; $documentation_link = make_http(make_link("cron_upload")); - + $sb = new SetupBlock("Cron Uploader"); $sb->add_label("Settings
"); $sb->add_int_option("cron_uploader_count", "How many to upload each time"); $sb->add_text_option("cron_uploader_dir", "
Set Cron Uploader root directory
"); - + $sb->add_label("
Cron Command:
Create a cron job with the command above.
Read the documentation if you're not sure what to do."); $event->panel->add_block($sb); } - + /* * Generates a unique key for the website to prevent unauthorized access. */ @@ -180,14 +195,14 @@ class CronUploader extends Extension $length = 20; $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $randomString = ''; - - for ($i = 0; $i < $length; $i ++) { + + for ($i = 0; $i < $length; $i++) { $randomString .= $characters [rand(0, strlen($characters) - 1)]; } - + return $randomString; } - + /* * Set the directory for the image queue. If no directory was given, set it to the default directory. */ @@ -195,15 +210,15 @@ class CronUploader extends Extension { global $config; // Determine directory (none = default) - + $dir = $config->get_string("cron_uploader_dir", ""); - + // Sets new default dir if not in config yet/anymore if ($dir == "") { $dir = data_path("cron_uploader"); $config->set_string('cron_uploader_dir', $dir); } - + // Make the directory if it doesn't exist yet if (!is_dir($dir . "/queue/")) { mkdir($dir . "/queue/", 0775, true); @@ -214,31 +229,31 @@ class CronUploader extends Extension if (!is_dir($dir . "/failed_to_upload/")) { mkdir($dir . "/failed_to_upload/", 0775, true); } - + $this->root_dir = $dir; return $dir; } - + /** * Returns amount of files & total size of dir. */ public function scan_dir(string $path): array { - $bytestotal=0; - $nbfiles=0; + $bytestotal = 0; + $nbfiles = 0; - $ite=new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS); - foreach (new RecursiveIteratorIterator($ite) as $filename=>$cur) { + $ite = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS); + foreach (new RecursiveIteratorIterator($ite) as $filename => $cur) { $filesize = $cur->getSize(); $bytestotal += $filesize; $nbfiles++; } - + $size_mb = $bytestotal / 1048576; // to mb $size_mb = number_format($size_mb, 2, '.', ''); - return ['total_files'=>$nbfiles,'total_mb'=>$size_mb]; + return ['total_files' => $nbfiles, 'total_mb' => $size_mb]; } - + /** * Uploads the image & handles everything */ @@ -246,24 +261,24 @@ class CronUploader extends Extension { global $config, $database; - set_time_limit(0); + //set_time_limit(0); - $output_subdir = date('Ymd-His', time())."/"; - $this->set_dir(); + + $output_subdir = date('Ymd-His', time()) . "/"; $this->generate_image_queue(); - + // Gets amount of imgs to upload if ($upload_count == 0) { $upload_count = $config->get_int("cron_uploader_count", 1); } - + // Throw exception if there's nothing in the queue if (count($this->image_queue) == 0) { $this->add_upload_info("Your queue is empty so nothing could be uploaded."); $this->handle_log(); return false; } - + // Randomize Images //shuffle($this->image_queue); @@ -274,15 +289,15 @@ class CronUploader extends Extension $failedItems = []; // Upload the file(s) - for ($i = 0; $i < $upload_count && sizeof($this->image_queue)>0; $i++) { + for ($i = 0; $i < $upload_count && sizeof($this->image_queue) > 0; $i++) { $img = array_pop($this->image_queue); - + try { $database->beginTransaction(); $result = $this->add_image($img[0], $img[1], $img[2]); $database->commit(); $this->move_uploaded($img[0], $img[1], $output_subdir, false); - if ($result==null) { + if ($result == null) { $merged++; } else { $added++; @@ -290,7 +305,7 @@ class CronUploader extends Extension } catch (Exception $e) { $failed++; $this->move_uploaded($img[0], $img[1], $output_subdir, true); - $msgNumber = $this->add_upload_info("(".gettype($e).") ".$e->getMessage()); + $msgNumber = $this->add_upload_info("(" . gettype($e) . ") " . $e->getMessage()); $msgNumber = $this->add_upload_info($e->getTraceAsString()); if (strpos($e->getMessage(), 'SQLSTATE') !== false) { // Postgres invalidates the transaction if there is an SQL error, @@ -310,40 +325,40 @@ class CronUploader extends Extension $msgNumber = $this->add_upload_info("Items failed: $failed"); - // Display & save upload log $this->handle_log(); - + return true; + } - + private function move_uploaded($path, $filename, $output_subdir, $corrupt = false) { global $config; - + // Create $newDir = $this->root_dir; - + $relativeDir = dirname(substr($path, strlen($this->root_dir) + 7)); // Determine which dir to move to if ($corrupt) { // Move to corrupt dir - $newDir .= "/failed_to_upload/".$output_subdir.$relativeDir; + $newDir .= "/failed_to_upload/" . $output_subdir . $relativeDir; $info = "ERROR: Image was not uploaded."; } else { - $newDir .= "/uploaded/".$output_subdir.$relativeDir; + $newDir .= "/uploaded/" . $output_subdir . $relativeDir; $info = "Image successfully uploaded. "; } - $newDir = str_replace("//", "/", $newDir."/"); + $newDir = str_replace("//", "/", $newDir . "/"); if (!is_dir($newDir)) { mkdir($newDir, 0775, true); } // move file to correct dir - rename($path, $newDir.$filename); - + rename($path, $newDir . $filename); + $this->add_upload_info($info . "Image \"$filename\" moved from queue to \"$newDir\"."); } @@ -353,7 +368,7 @@ class CronUploader extends Extension private function add_image(string $tmpname, string $filename, string $tags) { assert(file_exists($tmpname)); - + $pathinfo = pathinfo($filename); $metadata = []; $metadata ['filename'] = $pathinfo ['basename']; @@ -364,7 +379,7 @@ class CronUploader extends Extension $metadata ['source'] = null; $event = new DataUploadEvent($tmpname, $metadata); send_event($event); - + // Generate info message $infomsg = ""; // Will contain info message if ($event->image_id == -1) { @@ -377,18 +392,18 @@ class CronUploader extends Extension $msgNumber = $this->add_upload_info($infomsg); return $event->image_id; } - + private function generate_image_queue(): void { $base = $this->root_dir . "/queue"; - - if (! is_dir($base)) { + + if (!is_dir($base)) { $this->add_upload_info("Image Queue Directory could not be found at \"$base\"."); return; } - - $ite=new RecursiveDirectoryIterator($base, FilesystemIterator::SKIP_DOTS); - foreach (new RecursiveIteratorIterator($ite) as $fullpath=>$cur) { + + $ite = new RecursiveDirectoryIterator($base, FilesystemIterator::SKIP_DOTS); + foreach (new RecursiveIteratorIterator($ite) as $fullpath => $cur) { if (!is_link($fullpath) && !is_dir($fullpath)) { $pathinfo = pathinfo($fullpath); @@ -396,62 +411,62 @@ class CronUploader extends Extension $tags = path_to_tags($relativePath); $img = [ - 0 => $fullpath, - 1 => $pathinfo ["basename"], - 2 => $tags + 0 => $fullpath, + 1 => $pathinfo ["basename"], + 2 => $tags ]; array_push($this->image_queue, $img); } } } - + /** * Adds a message to the info being published at the end */ private function add_upload_info(string $text, int $addon = 0): int { $info = $this->upload_info; - $time = "[" .date('Y-m-d H:i:s'). "]"; - + $time = "[" . date('Y-m-d H:i:s') . "]"; + // If addon function is not used if ($addon == 0) { - $this->upload_info .= "$time $text\r\n"; - + $this->upload_info .= "$time $text\r\n"; + // Returns the number of the current line - $currentLine = substr_count($this->upload_info, "\n") -1; + $currentLine = substr_count($this->upload_info, "\n") - 1; return $currentLine; } - + // else if addon function is used, select the line & modify it $lines = substr($info, "\n"); // Seperate the string to array in lines $lines[$addon] = "$lines[$addon] $text"; // Add the content to the line $this->upload_info = implode("\n", $lines); // Put string back together & update - + return $addon; // Return line number } - + /** * This is run at the end to display & save the log. */ private function handle_log() { global $page; - + // Display message $page->set_mode("data"); $page->set_type("text/plain"); $page->set_data($this->upload_info); - + // Save log $log_path = $this->root_dir . "/uploads.log"; - + if (file_exists($log_path)) { $prev_content = file_get_contents($log_path); } else { $prev_content = ""; } - - $content = $prev_content ."\r\n".$this->upload_info; + + $content = $prev_content . "\r\n" . $this->upload_info; file_put_contents($log_path, $content); } } diff --git a/ext/ext_manager/main.php b/ext/ext_manager/main.php index f9ef6bba..dddefc70 100644 --- a/ext/ext_manager/main.php +++ b/ext/ext_manager/main.php @@ -22,8 +22,7 @@ class ExtensionInfo public $ext_name; public $name; public $link; - public $author; - public $email; + public $authors; public $description; public $documentation; public $version; @@ -39,8 +38,9 @@ class ExtensionInfo $this->ext_name = $matches[1]; $this->name = $this->ext_name; $this->enabled = $this->is_enabled($this->ext_name); + $this->authors = []; - for ($i=0; $i<$number_of_lines; $i++) { + for ($i = 0; $i < $number_of_lines; $i++) { $line = $lines[$i]; if (preg_match("/Name: (.*)/", $line, $matches)) { $this->name = $matches[1]; @@ -53,25 +53,31 @@ class ExtensionInfo } } elseif (preg_match("/Version: (.*)/", $line, $matches)) { $this->version = $matches[1]; - } elseif (preg_match("/Author: (.*) [<\(](.*@.*)[>\)]/", $line, $matches)) { - $this->author = $matches[1]; - $this->email = $matches[2]; - } elseif (preg_match("/Author: (.*)/", $line, $matches)) { - $this->author = $matches[1]; + } elseif (preg_match("/Authors?: (.*)/", $line, $matches)) { + $author_list = explode(',', $matches[1]); + foreach ($author_list as $author) { + if (preg_match("/(.*) [<\(](.*@.*)[>\)]/", $author, $matches)) { + $this->authors[] = new ExtensionAuthor($matches[1], $matches[2]); + } else { + $this->authors[] = new ExtensionAuthor($author, null); + } + } + + } elseif (preg_match("/(.*)Description: ?(.*)/", $line, $matches)) { $this->description = $matches[2]; - $start = $matches[1]." "; + $start = $matches[1] . " "; $start_len = strlen($start); - while (substr($lines[$i+1], 0, $start_len) == $start) { - $this->description .= " ".substr($lines[$i+1], $start_len); + while (substr($lines[$i + 1], 0, $start_len) == $start) { + $this->description .= " " . substr($lines[$i + 1], $start_len); $i++; } } elseif (preg_match("/(.*)Documentation: ?(.*)/", $line, $matches)) { $this->documentation = $matches[2]; - $start = $matches[1]." "; + $start = $matches[1] . " "; $start_len = strlen($start); - while (substr($lines[$i+1], 0, $start_len) == $start) { - $this->documentation .= " ".substr($lines[$i+1], $start_len); + while (substr($lines[$i + 1], 0, $start_len) == $start) { + $this->documentation .= " " . substr($lines[$i + 1], $start_len); $i++; } $this->documentation = str_replace('$site', make_http(get_base_href()), $this->documentation); @@ -96,6 +102,18 @@ class ExtensionInfo } } +class ExtensionAuthor +{ + public $name; + public $email; + + public function __construct(string $name, string $email) + { + $this->name = $name; + $this->email = $email; + } +} + class ExtManager extends Extension { public function onPageRequest(PageRequestEvent $event) @@ -166,7 +184,7 @@ class ExtManager extends Extension if ($all) { $exts = zglob("ext/*/main.php"); } else { - $exts = zglob("ext/{".ENABLED_EXTS."}/main.php"); + $exts = zglob("ext/{" . ENABLED_EXTS . "}/main.php"); } foreach ($exts as $main) { $extensions[] = new ExtensionInfo($main); @@ -200,9 +218,9 @@ class ExtManager extends Extension { file_put_contents( "data/config/extensions.conf.php", - '<'.'?php'."\n". - 'define("EXTRA_EXTS", "'.implode(",", $extras).'");'."\n". - '?'.">" + '<' . '?php' . "\n" . + 'define("EXTRA_EXTS", "' . implode(",", $extras) . '");' . "\n" . + '?' . ">" ); // when the list of active extensions changes, we can be diff --git a/ext/ext_manager/theme.php b/ext/ext_manager/theme.php index 3cc6d871..58bd79ab 100644 --- a/ext/ext_manager/theme.php +++ b/ext/ext_manager/theme.php @@ -9,7 +9,7 @@ class ExtManagerTheme extends Themelet { $h_en = $editable ? "" : ""; $html = " - ".make_form(make_link("ext_manager/set"))." + " . make_form(make_link("ext_manager/set")) . "
Enabled
@@ -26,17 +26,17 @@ class ExtManagerTheme extends Themelet continue; } - $h_name = html_escape(empty($extension->name) ? $extension->ext_name : $extension->name); + $h_name = html_escape(empty($extension->name) ? $extension->ext_name : $extension->name); $h_description = html_escape($extension->description); - $h_link = make_link("ext_doc/".url_escape($extension->ext_name)); - $h_enabled = ($extension->enabled === true ? " checked='checked'" : ($extension->enabled === false ? "" : " disabled checked='checked'")); - $h_enabled_box = $editable ? "" : ""; - $h_docs = ($extension->documentation ? "â– " : ""); //TODO: A proper "docs" symbol would be preferred here. + $h_link = make_link("ext_doc/" . url_escape($extension->ext_name)); + $h_enabled = ($extension->enabled === true ? " checked='checked'" : ($extension->enabled === false ? "" : " disabled checked='checked'")); + $h_enabled_box = $editable ? "" : ""; + $h_docs = ($extension->documentation ? "â– " : ""); //TODO: A proper "docs" symbol would be preferred here. $html .= " {$h_enabled_box} - + "; @@ -116,15 +116,24 @@ class ExtManagerTheme extends Themelet public function display_doc(Page $page, ExtensionInfo $info) { $author = ""; - if ($info->author) { - if ($info->email) { - $author = "
Author:email)."\">".html_escape($info->author).""; - } else { - $author = "
Author: ".html_escape($info->author); + if (count($info->authors) > 0) { + $author = "
Author"; + if (count($info->authors) > 1) { + $author .= "s"; } + $author .= ":"; + foreach ($info->authors as $auth) { + if (!empty($auth->email)) { + $author .= "email) . "\">" . html_escape($auth->name) . ""; + } else { + $author .= html_escape($auth->name); + } + } + } - $version = ($info->version) ? "
Version: ".html_escape($info->version) : ""; - $link = ($info->link) ? "
Home Page:link)."\">Link" : ""; + + $version = ($info->version) ? "
Version: " . html_escape($info->version) : ""; + $link = ($info->link) ? "
Home Page:link) . "\">Link" : ""; $doc = $info->documentation; $html = "
@@ -133,10 +142,10 @@ class ExtManagerTheme extends Themelet $link

$doc


-

Back to the list +

Back to the list

"; - $page->set_title("Documentation for ".html_escape($info->name)); + $page->set_title("Documentation for " . html_escape($info->name)); $page->set_heading(html_escape($info->name)); $page->add_block(new NavBlock()); $page->add_block(new Block("Documentation", $html)); From 4ade0090ccd924e3c7254054a1a10ed7ec51f6f8 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 11:03:09 -0500 Subject: [PATCH 011/133] Added float support to config --- core/config.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/config.php b/core/config.php index 695fa8f1..c9fb225b 100644 --- a/core/config.php +++ b/core/config.php @@ -144,6 +144,13 @@ abstract class BaseConfig implements Config } } + public function set_default_float(string $name, float $value): void + { + if (is_null($this->get($name))) { + $this->values[$name] = $value; + } + } + public function set_default_string(string $name, string $value): void { if (is_null($this->get($name))) { @@ -170,6 +177,11 @@ abstract class BaseConfig implements Config return (int)($this->get($name, $default)); } + public function get_float(string $name, ?float $default=null): ?float + { + return (float)($this->get($name, $default)); + } + public function get_string(string $name, ?string $default=null): ?string { return $this->get($name, $default); From 37fe743f6565d8b3e663fad0e08c8173d293c311 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 11:18:52 -0500 Subject: [PATCH 012/133] Changed "images" and "thumbs" usages to constants --- core/extension.php | 6 +++--- core/imageboard/image.php | 8 ++++++-- core/imageboard/misc.php | 10 +++++----- core/util.php | 7 +++++-- ext/admin/main.php | 2 +- ext/bulk_add_csv/main.php | 2 +- ext/handle_flash/main.php | 2 +- ext/handle_mp3/main.php | 2 +- ext/handle_pixel/main.php | 4 ++-- ext/handle_svg/main.php | 8 ++++---- ext/regen_thumb/main.php | 4 ++-- ext/resize/main.php | 6 +++--- ext/rotate/main.php | 4 ++-- ext/rule34/main.php | 4 ++-- ext/transcode/main.php | 4 ++-- 15 files changed, 40 insertions(+), 33 deletions(-) diff --git a/core/extension.php b/core/extension.php index af7bb6ad..d691bd68 100644 --- a/core/extension.php +++ b/core/extension.php @@ -182,7 +182,7 @@ abstract class DataHandlerExtension extends Extension // even more hax.. $event->metadata['tags'] = $existing->get_tag_list(); - $image = $this->create_image_from_data(warehouse_path("images", $event->metadata['hash']), $event->metadata); + $image = $this->create_image_from_data(warehouse_path(Image::IMAGE_DIR, $event->metadata['hash']), $event->metadata); if (is_null($image)) { throw new UploadException("Data handler failed to create image object from data"); @@ -192,7 +192,7 @@ abstract class DataHandlerExtension extends Extension send_event($ire); $event->image_id = $image_id; } else { - $image = $this->create_image_from_data(warehouse_path("images", $event->hash), $event->metadata); + $image = $this->create_image_from_data(warehouse_path(Image::IMAGE_DIR, $event->hash), $event->metadata); if (is_null($image)) { throw new UploadException("Data handler failed to create image object from data"); } @@ -224,7 +224,7 @@ abstract class DataHandlerExtension extends Extension if ($event->force) { $result = $this->create_thumb($event->hash, $event->type); } else { - $outname = warehouse_path("thumbs", $event->hash); + $outname = warehouse_path(Image::THUMBNAIL_DIR, $event->hash); if (file_exists($outname)) { return; } diff --git a/core/imageboard/image.php b/core/imageboard/image.php index af6a15d8..717abf7f 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -10,6 +10,10 @@ */ class Image { + public const DATA_DIR = "data"; + public const IMAGE_DIR = "images"; + public const THUMBNAIL_DIR = "thumbs"; + private static $tag_n = 0; // temp hack public static $order_sql = null; // this feels ugly @@ -502,7 +506,7 @@ class Image */ public function get_image_filename(): string { - return warehouse_path("images", $this->hash); + return warehouse_path(self::IMAGE_DIR, $this->hash); } /** @@ -510,7 +514,7 @@ class Image */ public function get_thumb_filename(): string { - return warehouse_path("thumbs", $this->hash); + return warehouse_path(self::THUMBNAIL_DIR, $this->hash); } /** diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index e9bd93c6..d08daf2b 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -12,7 +12,7 @@ */ function move_upload_to_archive(DataUploadEvent $event): void { - $target = warehouse_path("images", $event->hash); + $target = warehouse_path(Image::IMAGE_DIR, $event->hash); if (!@copy($event->tmpname, $target)) { $errors = error_get_last(); throw new UploadException( @@ -171,8 +171,8 @@ function create_thumbnail_convert($hash, $input_type = ""): bool { global $config; - $inname = warehouse_path("images", $hash); - $outname = warehouse_path("thumbs", $hash); + $inname = warehouse_path(Image::IMAGE_DIR, $hash); + $outname = warehouse_path(Image::THUMBNAIL_DIR, $hash); $q = $config->get_int("thumb_quality"); $convert = $config->get_string("thumb_convert_path"); @@ -236,8 +236,8 @@ function create_thumbnail_ffmpeg($hash): bool return false; } - $inname = warehouse_path("images", $hash); - $outname = warehouse_path("thumbs", $hash); + $inname = warehouse_path(Image::IMAGE_DIR, $hash); + $outname = warehouse_path(Image::THUMBNAIL_DIR, $hash); $orig_size = video_size($inname); $scaled_size = get_thumbnail_size($orig_size[0], $orig_size[1], true); diff --git a/core/util.php b/core/util.php index 299463d8..6dd74b26 100644 --- a/core/util.php +++ b/core/util.php @@ -163,10 +163,13 @@ function warehouse_path(string $base, string $hash, bool $create=true): string { $ab = substr($hash, 0, 2); $cd = substr($hash, 2, 2); + + $pa = Image::DATA_DIR.'/'.$base.'/'; + if (WH_SPLITS == 2) { - $pa = 'data/'.$base.'/'.$ab.'/'.$cd.'/'.$hash; + $pa .= $ab.'/'.$cd.'/'.$hash; } else { - $pa = 'data/'.$base.'/'.$ab.'/'.$hash; + $pa .= $ab.'/'.$hash; } if ($create && !file_exists(dirname($pa))) { mkdir(dirname($pa), 0755, true); diff --git a/ext/admin/main.php b/ext/admin/main.php index 2b484bc1..22845575 100644 --- a/ext/admin/main.php +++ b/ext/admin/main.php @@ -237,7 +237,7 @@ class AdminPage extends Extension $zip = new ZipArchive; if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) === true) { foreach ($images as $img) { - $img_loc = warehouse_path("images", $img["hash"], false); + $img_loc = warehouse_path(Image::IMAGE_DIR, $img["hash"], false); $zip->addFile($img_loc, $img["hash"].".".$img["ext"]); } $zip->close(); diff --git a/ext/bulk_add_csv/main.php b/ext/bulk_add_csv/main.php index 14db3591..d1648a7d 100644 --- a/ext/bulk_add_csv/main.php +++ b/ext/bulk_add_csv/main.php @@ -81,7 +81,7 @@ class BulkAddCSV extends Extension send_event($ratingevent); } if (file_exists($thumbfile)) { - copy($thumbfile, warehouse_path("thumbs", $event->hash)); + copy($thumbfile, warehouse_path(Image::THUMBNAIL_DIR, $event->hash)); } } } diff --git a/ext/handle_flash/main.php b/ext/handle_flash/main.php index 9476499e..e47b193b 100644 --- a/ext/handle_flash/main.php +++ b/ext/handle_flash/main.php @@ -13,7 +13,7 @@ class FlashFileHandler extends DataHandlerExtension global $config; if (!create_thumbnail_ffmpeg($hash)) { - copy("ext/handle_flash/thumb.jpg", warehouse_path("thumbs", $hash)); + copy("ext/handle_flash/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash)); } return true; } diff --git a/ext/handle_mp3/main.php b/ext/handle_mp3/main.php index 13e2bab4..e0fcd5a7 100644 --- a/ext/handle_mp3/main.php +++ b/ext/handle_mp3/main.php @@ -9,7 +9,7 @@ class MP3FileHandler extends DataHandlerExtension { protected function create_thumb(string $hash, string $type): bool { - copy("ext/handle_mp3/thumb.jpg", warehouse_path("thumbs", $hash)); + copy("ext/handle_mp3/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash)); return true; } diff --git a/ext/handle_pixel/main.php b/ext/handle_pixel/main.php index a3bc3bd2..ac72bcc1 100644 --- a/ext/handle_pixel/main.php +++ b/ext/handle_pixel/main.php @@ -58,8 +58,8 @@ class PixelFileHandler extends DataHandlerExtension { global $config; - $inname = warehouse_path("images", $hash); - $outname = warehouse_path("thumbs", $hash); + $inname = warehouse_path(Image::IMAGE_DIR, $hash); + $outname = warehouse_path(Image::THUMBNAIL_DIR, $hash); $ok = false; diff --git a/ext/handle_svg/main.php b/ext/handle_svg/main.php index f2151c06..a15942b1 100644 --- a/ext/handle_svg/main.php +++ b/ext/handle_svg/main.php @@ -19,10 +19,10 @@ class SVGFileHandler extends DataHandlerExtension $sanitizer->removeRemoteReferences(true); $dirtySVG = file_get_contents($event->tmpname); $cleanSVG = $sanitizer->sanitize($dirtySVG); - file_put_contents(warehouse_path("images", $hash), $cleanSVG); + file_put_contents(warehouse_path(Image::IMAGE_DIR, $hash), $cleanSVG); send_event(new ThumbnailGenerationEvent($event->hash, $event->type)); - $image = $this->create_image_from_data(warehouse_path("images", $hash), $event->metadata); + $image = $this->create_image_from_data(warehouse_path(Image::IMAGE_DIR, $hash), $event->metadata); if (is_null($image)) { throw new UploadException("SVG handler failed to create image object from data"); } @@ -35,7 +35,7 @@ class SVGFileHandler extends DataHandlerExtension protected function create_thumb(string $hash, string $type): bool { if (!create_thumbnail_convert($hash)) { - copy("ext/handle_svg/thumb.jpg", warehouse_path("thumbs", $hash)); + copy("ext/handle_svg/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash)); } return true; } @@ -61,7 +61,7 @@ class SVGFileHandler extends DataHandlerExtension $sanitizer = new Sanitizer(); $sanitizer->removeRemoteReferences(true); - $dirtySVG = file_get_contents(warehouse_path("images", $hash)); + $dirtySVG = file_get_contents(warehouse_path(Image::IMAGE_DIR, $hash)); $cleanSVG = $sanitizer->sanitize($dirtySVG); $page->set_data($cleanSVG); } diff --git a/ext/regen_thumb/main.php b/ext/regen_thumb/main.php index c7115b34..a653e902 100644 --- a/ext/regen_thumb/main.php +++ b/ext/regen_thumb/main.php @@ -133,7 +133,7 @@ class RegenThumb extends Extension $i = 0; foreach ($images as $image) { if (!$force) { - $path = warehouse_path("thumbs", $image["hash"], false); + $path = warehouse_path(Image::THUMBNAIL_DIR, $image["hash"], false); if (file_exists($path)) { continue; } @@ -157,7 +157,7 @@ class RegenThumb extends Extension $i = 0; foreach ($images as $image) { - $outname = warehouse_path("thumbs", $image["hash"]); + $outname = warehouse_path(Image::THUMBNAIL_DIR, $image["hash"]); if (file_exists($outname)) { unlink($outname); $i++; diff --git a/ext/resize/main.php b/ext/resize/main.php index 35fd537f..bad21f6b 100644 --- a/ext/resize/main.php +++ b/ext/resize/main.php @@ -79,7 +79,7 @@ class ResizeImage extends Extension } $isanigif = 0; if ($image_obj->ext == "gif") { - $image_filename = warehouse_path("images", $image_obj->hash); + $image_filename = warehouse_path(Image::IMAGE_DIR, $image_obj->hash); if (($fh = @fopen($image_filename, 'rb'))) { //check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) while (!feof($fh) && $isanigif < 2) { @@ -167,7 +167,7 @@ class ResizeImage extends Extension } $hash = $image_obj->hash; - $image_filename = warehouse_path("images", $hash); + $image_filename = warehouse_path(Image::IMAGE_DIR, $hash); $info = getimagesize($image_filename); if (($image_obj->width != $info[0]) || ($image_obj->height != $info[1])) { @@ -193,7 +193,7 @@ class ResizeImage extends Extension $new_image->ext = $image_obj->ext; /* Move the new image into the main storage location */ - $target = warehouse_path("images", $new_image->hash); + $target = warehouse_path(Image::IMAGE_DIR, $new_image->hash); if (!@copy($tmp_filename, $target)) { throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); } diff --git a/ext/rotate/main.php b/ext/rotate/main.php index 397639a3..b2b1df3d 100644 --- a/ext/rotate/main.php +++ b/ext/rotate/main.php @@ -120,7 +120,7 @@ class RotateImage extends Extension throw new ImageRotateException("Image does not have a hash associated with it."); } - $image_filename = warehouse_path("images", $hash); + $image_filename = warehouse_path(Image::IMAGE_DIR, $hash); if (file_exists($image_filename)==false) { throw new ImageRotateException("$image_filename does not exist."); } @@ -212,7 +212,7 @@ class RotateImage extends Extension $new_image->ext = $image_obj->ext; /* Move the new image into the main storage location */ - $target = warehouse_path("images", $new_image->hash); + $target = warehouse_path(Image::IMAGE_DIR, $new_image->hash); if (!@copy($tmp_filename, $target)) { throw new ImageRotateException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); } diff --git a/ext/rule34/main.php b/ext/rule34/main.php index 577ca5af..775fe0ec 100644 --- a/ext/rule34/main.php +++ b/ext/rule34/main.php @@ -116,8 +116,8 @@ class Rule34 extends Extension continue; } log_info("admin", "Cleaning {$hash}"); - @unlink(warehouse_path('images', $hash)); - @unlink(warehouse_path('thumbs', $hash)); + @unlink(warehouse_path(Image::IMAGE_DIR, $hash)); + @unlink(warehouse_path(Image::THUMBNAIL_DIR, $hash)); $database->execute("NOTIFY shm_image_bans, '{$hash}';"); } } diff --git a/ext/transcode/main.php b/ext/transcode/main.php index aa471d0a..ba7e0947 100644 --- a/ext/transcode/main.php +++ b/ext/transcode/main.php @@ -308,7 +308,7 @@ class TranscodeImage extends Extension private function transcode_and_replace_image(Image $image_obj, String $target_format) { $target_format = $this->clean_format($target_format); - $original_file = warehouse_path("images", $image_obj->hash); + $original_file = warehouse_path(Image::IMAGE_DIR, $image_obj->hash); $tmp_filename = $this->transcode_image($original_file, $image_obj->ext, $target_format); @@ -321,7 +321,7 @@ class TranscodeImage extends Extension $new_image->ext = $this->determine_ext($target_format); /* Move the new image into the main storage location */ - $target = warehouse_path("images", $new_image->hash); + $target = warehouse_path(Image::IMAGE_DIR, $new_image->hash); if (!@copy($tmp_filename, $target)) { throw new ImageTranscodeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); } From ed9bd5e78839b16cbf2adf1bec112ce9a00bc3ae Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 11:29:13 -0500 Subject: [PATCH 013/133] Fix in ExtensionAuthor --- ext/ext_manager/main.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ext_manager/main.php b/ext/ext_manager/main.php index dddefc70..4739fb9d 100644 --- a/ext/ext_manager/main.php +++ b/ext/ext_manager/main.php @@ -107,7 +107,7 @@ class ExtensionAuthor public $name; public $email; - public function __construct(string $name, string $email) + public function __construct(string $name, ?string $email) { $this->name = $name; $this->email = $email; From ab9389007f872488e8620d97949a4692d2e67f0a Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 11:35:36 -0500 Subject: [PATCH 014/133] Changed key-generation process for cron upload so it doesn't endlessly generate new keys before the user first hits the same buttons in settings. --- ext/cron_uploader/main.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index fe1bbfbf..1c12b05f 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -157,13 +157,14 @@ class CronUploader extends Extension { global $config; // Set default values + $config->set_default_int('cron_uploader_count', 1); + $this->set_dir(); + $this->upload_key = $config->get_string("cron_uploader_key", ""); - if (strlen($this->upload_key) <= 0) { + if (empty($this->upload_key)) { $this->upload_key = $this->generate_key(); - $config->set_default_int('cron_uploader_count', 1); - $config->set_default_string('cron_uploader_key', $this->upload_key); - $this->set_dir(); + $config->set_string('cron_uploader_key', $this->upload_key); } } @@ -180,7 +181,7 @@ class CronUploader extends Extension $sb->add_int_option("cron_uploader_count", "How many to upload each time"); $sb->add_text_option("cron_uploader_dir", "
Set Cron Uploader root directory
"); - $sb->add_label("
Cron Command:
+ $sb->add_label("
Cron Command:
Create a cron job with the command above.
Read the documentation if you're not sure what to do."); From 8b531c04a2e51e588079788e7f49f76ade39664d Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 12:15:47 -0500 Subject: [PATCH 015/133] removed SQLERROR escape from cron uploader, not necessary now that it is individualizing transactions. Change cron uploader to use constants for dir and config names --- ext/cron_uploader/main.php | 58 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index 1c12b05f..7b5f7061 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -15,6 +15,14 @@ class CronUploader extends Extension // TODO: Change logging to MySQL + display log at /cron_upload // TODO: Move stuff to theme.php + const QUEUE_DIR = "queue"; + const UPLOADED_DIR = "uploaded"; + const FAILED_DIR = "failed_to_upload"; + + const CONFIG_KEY = "cron_uploader_key"; + const CONFIG_COUNT = "cron_uploader_count"; + const CONFIG_DIR = "cron_uploader_dir"; + /** * Lists all log events this session * @var string @@ -78,9 +86,9 @@ class CronUploader extends Extension $this->set_dir(); // Determines path to cron_uploader_dir - $queue_dir = $this->root_dir . "/queue"; - $uploaded_dir = $this->root_dir . "/uploaded"; - $failed_dir = $this->root_dir . "/failed_to_upload"; + $queue_dir = $this->root_dir . "/" . self::QUEUE_DIR; + $uploaded_dir = $this->root_dir . "/" . self::UPLOADED_DIR; + $failed_dir = $this->root_dir . "/" . self::FAILED_DIR; $queue_dirinfo = $this->scan_dir($queue_dir); $uploaded_dirinfo = $this->scan_dir($uploaded_dir); @@ -157,14 +165,14 @@ class CronUploader extends Extension { global $config; // Set default values - $config->set_default_int('cron_uploader_count', 1); + $config->set_default_int(self::CONFIG_COUNT, 1); $this->set_dir(); - $this->upload_key = $config->get_string("cron_uploader_key", ""); + $this->upload_key = $config->get_string(self::CONFIG_KEY, ""); if (empty($this->upload_key)) { $this->upload_key = $this->generate_key(); - $config->set_string('cron_uploader_key', $this->upload_key); + $config->set_string(self::CONFIG_KEY, $this->upload_key); } } @@ -178,10 +186,10 @@ class CronUploader extends Extension $sb = new SetupBlock("Cron Uploader"); $sb->add_label("Settings
"); - $sb->add_int_option("cron_uploader_count", "How many to upload each time"); - $sb->add_text_option("cron_uploader_dir", "
Set Cron Uploader root directory
"); + $sb->add_int_option(self::CONFIG_COUNT, "How many to upload each time"); + $sb->add_text_option(self::CONFIG_DIR, "
Set Cron Uploader root directory
"); - $sb->add_label("
Cron Command:
+ $sb->add_label("
Cron Command:
Create a cron job with the command above.
Read the documentation if you're not sure what to do."); @@ -212,23 +220,23 @@ class CronUploader extends Extension global $config; // Determine directory (none = default) - $dir = $config->get_string("cron_uploader_dir", ""); + $dir = $config->get_string(self::CONFIG_DIR, ""); // Sets new default dir if not in config yet/anymore if ($dir == "") { $dir = data_path("cron_uploader"); - $config->set_string('cron_uploader_dir', $dir); + $config->set_string(self::CONFIG_DIR, $dir); } // Make the directory if it doesn't exist yet - if (!is_dir($dir . "/queue/")) { - mkdir($dir . "/queue/", 0775, true); + if (!is_dir($dir . "/" . self::QUEUE_DIR . "/")) { + mkdir($dir . "/" . self::QUEUE_DIR . "/", 0775, true); } - if (!is_dir($dir . "/uploaded/")) { - mkdir($dir . "/uploaded/", 0775, true); + if (!is_dir($dir . "/" . self::UPLOADED_DIR . "/")) { + mkdir($dir . "/" . self::UPLOADED_DIR . "/", 0775, true); } - if (!is_dir($dir . "/failed_to_upload/")) { - mkdir($dir . "/failed_to_upload/", 0775, true); + if (!is_dir($dir . "/" . self::FAILED_DIR . "/")) { + mkdir($dir . "/" . self::FAILED_DIR . "/", 0775, true); } $this->root_dir = $dir; @@ -270,7 +278,7 @@ class CronUploader extends Extension // Gets amount of imgs to upload if ($upload_count == 0) { - $upload_count = $config->get_int("cron_uploader_count", 1); + $upload_count = $config->get_int(self::CONFIG_COUNT, 1); } // Throw exception if there's nothing in the queue @@ -287,8 +295,6 @@ class CronUploader extends Extension $added = 0; $failed = 0; - $failedItems = []; - // Upload the file(s) for ($i = 0; $i < $upload_count && sizeof($this->image_queue) > 0; $i++) { $img = array_pop($this->image_queue); @@ -308,11 +314,7 @@ class CronUploader extends Extension $this->move_uploaded($img[0], $img[1], $output_subdir, true); $msgNumber = $this->add_upload_info("(" . gettype($e) . ") " . $e->getMessage()); $msgNumber = $this->add_upload_info($e->getTraceAsString()); - if (strpos($e->getMessage(), 'SQLSTATE') !== false) { - // Postgres invalidates the transaction if there is an SQL error, - // so all subsequence transactions will fail. - break; - } + try { $database->rollback(); } catch (Exception $e) { @@ -345,10 +347,10 @@ class CronUploader extends Extension // Determine which dir to move to if ($corrupt) { // Move to corrupt dir - $newDir .= "/failed_to_upload/" . $output_subdir . $relativeDir; + $newDir .= "/" . self::FAILED_DIR . "/" . $output_subdir . $relativeDir; $info = "ERROR: Image was not uploaded."; } else { - $newDir .= "/uploaded/" . $output_subdir . $relativeDir; + $newDir .= "/" . self::UPLOADED_DIR . "/" . $output_subdir . $relativeDir; $info = "Image successfully uploaded. "; } $newDir = str_replace("//", "/", $newDir . "/"); @@ -396,7 +398,7 @@ class CronUploader extends Extension private function generate_image_queue(): void { - $base = $this->root_dir . "/queue"; + $base = $this->root_dir . "/" . self::QUEUE_DIR; if (!is_dir($base)) { $this->add_upload_info("Image Queue Directory could not be found at \"$base\"."); From 1fe18e757302d74b1789cd6e80c0c9b22c581ddc Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Sat, 15 Jun 2019 12:51:59 -0500 Subject: [PATCH 016/133] Missed a dir name --- ext/cron_uploader/main.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index 7b5f7061..87947b96 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -56,7 +56,7 @@ class CronUploader extends Extension global $config, $user; if ($event->page_matches("cron_upload")) { - $this->upload_key = $config->get_string("cron_uploader_key", ""); + $this->upload_key = $config->get_string(self::CONFIG_KEY, ""); // If the key is in the url, upload if ($this->upload_key != "" && $event->get_arg(0) == $this->upload_key) { From 6b9d18b52e76127b36a8706ec6316ed45536a29a Mon Sep 17 00:00:00 2001 From: Shish Date: Sun, 16 Jun 2019 19:07:55 +0100 Subject: [PATCH 017/133] Parse tags first, then check accelerator, then check database Better than half-assed tag parsing in the accelerator then full parsing in the database --- core/imageboard/image.php | 154 ++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 72 deletions(-) diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 928d4914..0ec8c310 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -125,13 +125,11 @@ class Image } } - $result = null; - if (SEARCH_ACCEL) { - $result = Image::get_accelerated_result($tags, $start, $limit); - } + list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); + $result = Image::get_accelerated_result($tag_querylets, $img_querylets, $start, $limit); if (!$result) { - $querylet = Image::build_search_querylet($tags); + $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); $querylet->append(new Querylet(" ORDER BY ".(Image::$order_sql ?: "images.".$config->get_string("index_order")))); $querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", ["limit"=>$limit, "offset"=>$start])); #var_dump($querylet->sql); var_dump($querylet->variables); @@ -170,13 +168,11 @@ class Image } } - $result = null; - if (SEARCH_ACCEL) { - $result = Image::get_accelerated_result($tags, $start, $limit); - } + list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); + $result = Image::get_accelerated_result($tag_querylets, $img_querylets, $start, $limit); if (!$result) { - $querylet = Image::build_search_querylet($tags); + $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); $querylet->append(new Querylet(" ORDER BY ".(Image::$order_sql ?: "images.".$config->get_string("index_order")))); $querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", ["limit"=>$limit, "offset"=>$start])); #var_dump($querylet->sql); var_dump($querylet->variables); @@ -193,7 +189,7 @@ class Image /* * Accelerator stuff */ - public static function get_acceleratable(array $tags): ?array + public static function get_acceleratable(array $tag_querylets): ?array { $ret = [ "yays" => [], @@ -201,16 +197,13 @@ class Image ]; $yays = 0; $nays = 0; - foreach ($tags as $tag) { - if (!preg_match("/^-?[a-zA-Z0-9_'-]+$/", $tag)) { - return null; - } - if ($tag[0] == "-") { - $nays++; - $ret["nays"][] = substr($tag, 1); - } else { + foreach ($tag_querylets as $tq) { + if ($tq->positive) { $yays++; - $ret["yays"][] = $tag; + $ret["yays"][] = $tq->tag; + } else { + $nays++; + $ret["nays"][] = $tq->tag; } } if ($yays > 1 || $nays > 0) { @@ -219,11 +212,15 @@ class Image return null; } - public static function get_accelerated_result(array $tags, int $offset, int $limit): ?PDOStatement + public static function get_accelerated_result(array $tag_querylets, array $img_querylets, int $offset, int $limit): ?PDOStatement { + if (!SEARCH_ACCEL || !empty($img_querylets)) { + return null; + } + global $database; - $req = Image::get_acceleratable($tags); + $req = Image::get_acceleratable($tag_querylets); if (!$req) { return null; } @@ -240,9 +237,13 @@ class Image return $result; } - public static function get_accelerated_count(array $tags): ?int + public static function get_accelerated_count(array $tag_querylets, array $img_querylets): ?int { - $req = Image::get_acceleratable($tags); + if (!SEARCH_ACCEL || !empty($img_querylets)) { + return null; + } + + $req = Image::get_acceleratable($tag_querylets); if (!$req) { return null; } @@ -295,9 +296,10 @@ class Image ["tag"=>$tags[0]] ); } else { - $total = Image::get_accelerated_count($tags); + list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); + $total = Image::get_accelerated_count($tag_querylets, $img_querylets); if (is_null($total)) { - $querylet = Image::build_search_querylet($tags); + $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); $total = $database->get_one("SELECT COUNT(*) AS cnt FROM ($querylet->sql) AS tbl", $querylet->variables); } } @@ -318,6 +320,53 @@ class Image return ceil(Image::count_images($tags) / $config->get_int('index_images')); } + private static function parse_all_terms(array $terms): array + { + $tag_querylets = []; + $img_querylets = []; + + /* + * Turn a bunch of strings into a bunch of TagQuerylet + * and ImgQuerylet objects + */ + $stpe = new SearchTermParseEvent(null, $terms); + send_event($stpe); + if ($stpe->is_querylet_set()) { + foreach ($stpe->get_querylets() as $querylet) { + $img_querylets[] = new ImgQuerylet($querylet, true); + } + } + + foreach ($terms as $term) { + $positive = true; + if (is_string($term) && !empty($term) && ($term[0] == '-')) { + $positive = false; + $term = substr($term, 1); + } + if (strlen($term) === 0) { + continue; + } + + $stpe = new SearchTermParseEvent($term, $terms); + send_event($stpe); + if ($stpe->is_querylet_set()) { + foreach ($stpe->get_querylets() as $querylet) { + $img_querylets[] = new ImgQuerylet($querylet, $positive); + } + } else { + // if the whole match is wild, skip this; + // if not, translate into SQL + if (str_replace("*", "", $term) != "") { + $term = str_replace('_', '\_', $term); + $term = str_replace('%', '\%', $term); + $term = str_replace('*', '%', $term); + $tag_querylets[] = new TagQuerylet($term, $positive); + } + } + } + return [$tag_querylets, $img_querylets]; + } + /* * Accessors & mutators */ @@ -352,7 +401,8 @@ class Image '); } else { $tags[] = 'id'. $gtlt . $this->id; - $querylet = Image::build_search_querylet($tags); + list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); + $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); $querylet->append_sql(' ORDER BY images.id '.$dir.' LIMIT 1'); $row = $database->get_row($querylet->sql, $querylet->variables); } @@ -813,57 +863,17 @@ class Image /** * #param string[] $terms */ - private static function build_search_querylet(array $terms): Querylet + private static function build_search_querylet(array $tag_querylets, array $img_querylets): Querylet { global $database; - $tag_querylets = []; - $img_querylets = []; $positive_tag_count = 0; $negative_tag_count = 0; - - /* - * Turn a bunch of strings into a bunch of TagQuerylet - * and ImgQuerylet objects - */ - $stpe = new SearchTermParseEvent(null, $terms); - send_event($stpe); - if ($stpe->is_querylet_set()) { - foreach ($stpe->get_querylets() as $querylet) { - $img_querylets[] = new ImgQuerylet($querylet, true); - } - } - - foreach ($terms as $term) { - $positive = true; - if (is_string($term) && !empty($term) && ($term[0] == '-')) { - $positive = false; - $term = substr($term, 1); - } - if (strlen($term) === 0) { - continue; - } - - $stpe = new SearchTermParseEvent($term, $terms); - send_event($stpe); - if ($stpe->is_querylet_set()) { - foreach ($stpe->get_querylets() as $querylet) { - $img_querylets[] = new ImgQuerylet($querylet, $positive); - } + foreach ($tag_querylets as $tq) { + if ($tq->positive) { + $positive_tag_count++; } else { - // if the whole match is wild, skip this; - // if not, translate into SQL - if (str_replace("*", "", $term) != "") { - $term = str_replace('_', '\_', $term); - $term = str_replace('%', '\%', $term); - $term = str_replace('*', '%', $term); - $tag_querylets[] = new TagQuerylet($term, $positive); - if ($positive) { - $positive_tag_count++; - } else { - $negative_tag_count++; - } - } + $negative_tag_count++; } } From 6df119050139b7438446da8ca1fe8533ef4df141 Mon Sep 17 00:00:00 2001 From: Shish Date: Sun, 16 Jun 2019 19:11:16 +0100 Subject: [PATCH 018/133] Rename Tag/ImgQuerylet to Tag/ImgCondition It was confusing because Tag/ImgQuerylet (an abstract condition to use as part of image search filtering) were unrelated to Querylet (a fragment of SQL) --- core/imageboard/image.php | 86 +++++++++++++++++++------------------- core/imageboard/search.php | 4 +- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 0ec8c310..18c646a9 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -125,11 +125,11 @@ class Image } } - list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); + list($tag_conditions, $img_conditions) = self::terms_to_conditions($tags); - $result = Image::get_accelerated_result($tag_querylets, $img_querylets, $start, $limit); + $result = Image::get_accelerated_result($tag_conditions, $img_conditions, $start, $limit); if (!$result) { - $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); + $querylet = Image::build_search_querylet($tag_conditions, $img_conditions); $querylet->append(new Querylet(" ORDER BY ".(Image::$order_sql ?: "images.".$config->get_string("index_order")))); $querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", ["limit"=>$limit, "offset"=>$start])); #var_dump($querylet->sql); var_dump($querylet->variables); @@ -168,11 +168,11 @@ class Image } } - list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); + list($tag_conditions, $img_conditions) = self::terms_to_conditions($tags); - $result = Image::get_accelerated_result($tag_querylets, $img_querylets, $start, $limit); + $result = Image::get_accelerated_result($tag_conditions, $img_conditions, $start, $limit); if (!$result) { - $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); + $querylet = Image::build_search_querylet($tag_conditions, $img_conditions); $querylet->append(new Querylet(" ORDER BY ".(Image::$order_sql ?: "images.".$config->get_string("index_order")))); $querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", ["limit"=>$limit, "offset"=>$start])); #var_dump($querylet->sql); var_dump($querylet->variables); @@ -189,7 +189,7 @@ class Image /* * Accelerator stuff */ - public static function get_acceleratable(array $tag_querylets): ?array + public static function get_acceleratable(array $tag_conditions): ?array { $ret = [ "yays" => [], @@ -197,7 +197,7 @@ class Image ]; $yays = 0; $nays = 0; - foreach ($tag_querylets as $tq) { + foreach ($tag_conditions as $tq) { if ($tq->positive) { $yays++; $ret["yays"][] = $tq->tag; @@ -212,15 +212,15 @@ class Image return null; } - public static function get_accelerated_result(array $tag_querylets, array $img_querylets, int $offset, int $limit): ?PDOStatement + public static function get_accelerated_result(array $tag_conditions, array $img_conditions, int $offset, int $limit): ?PDOStatement { - if (!SEARCH_ACCEL || !empty($img_querylets)) { + if (!SEARCH_ACCEL || !empty($img_conditions)) { return null; } global $database; - $req = Image::get_acceleratable($tag_querylets); + $req = Image::get_acceleratable($tag_conditions); if (!$req) { return null; } @@ -237,13 +237,13 @@ class Image return $result; } - public static function get_accelerated_count(array $tag_querylets, array $img_querylets): ?int + public static function get_accelerated_count(array $tag_conditions, array $img_conditions): ?int { - if (!SEARCH_ACCEL || !empty($img_querylets)) { + if (!SEARCH_ACCEL || !empty($img_conditions)) { return null; } - $req = Image::get_acceleratable($tag_querylets); + $req = Image::get_acceleratable($tag_conditions); if (!$req) { return null; } @@ -296,10 +296,10 @@ class Image ["tag"=>$tags[0]] ); } else { - list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); - $total = Image::get_accelerated_count($tag_querylets, $img_querylets); + list($tag_conditions, $img_conditions) = self::terms_to_conditions($tags); + $total = Image::get_accelerated_count($tag_conditions, $img_conditions); if (is_null($total)) { - $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); + $querylet = Image::build_search_querylet($tag_conditions, $img_conditions); $total = $database->get_one("SELECT COUNT(*) AS cnt FROM ($querylet->sql) AS tbl", $querylet->variables); } } @@ -320,20 +320,20 @@ class Image return ceil(Image::count_images($tags) / $config->get_int('index_images')); } - private static function parse_all_terms(array $terms): array + private static function terms_to_conditions(array $terms): array { - $tag_querylets = []; - $img_querylets = []; + $tag_conditions = []; + $img_conditions = []; /* - * Turn a bunch of strings into a bunch of TagQuerylet - * and ImgQuerylet objects + * Turn a bunch of strings into a bunch of TagCondition + * and ImgCondition objects */ $stpe = new SearchTermParseEvent(null, $terms); send_event($stpe); if ($stpe->is_querylet_set()) { foreach ($stpe->get_querylets() as $querylet) { - $img_querylets[] = new ImgQuerylet($querylet, true); + $img_conditions[] = new ImgCondition($querylet, true); } } @@ -351,7 +351,7 @@ class Image send_event($stpe); if ($stpe->is_querylet_set()) { foreach ($stpe->get_querylets() as $querylet) { - $img_querylets[] = new ImgQuerylet($querylet, $positive); + $img_conditions[] = new ImgCondition($querylet, $positive); } } else { // if the whole match is wild, skip this; @@ -360,11 +360,11 @@ class Image $term = str_replace('_', '\_', $term); $term = str_replace('%', '\%', $term); $term = str_replace('*', '%', $term); - $tag_querylets[] = new TagQuerylet($term, $positive); + $tag_conditions[] = new TagCondition($term, $positive); } } } - return [$tag_querylets, $img_querylets]; + return [$tag_conditions, $img_conditions]; } /* @@ -401,8 +401,8 @@ class Image '); } else { $tags[] = 'id'. $gtlt . $this->id; - list($tag_querylets, $img_querylets) = self::parse_all_terms($tags); - $querylet = Image::build_search_querylet($tag_querylets, $img_querylets); + list($tag_conditions, $img_conditions) = self::terms_to_conditions($tags); + $querylet = Image::build_search_querylet($tag_conditions, $img_conditions); $querylet->append_sql(' ORDER BY images.id '.$dir.' LIMIT 1'); $row = $database->get_row($querylet->sql, $querylet->variables); } @@ -863,13 +863,13 @@ class Image /** * #param string[] $terms */ - private static function build_search_querylet(array $tag_querylets, array $img_querylets): Querylet + private static function build_search_querylet(array $tag_conditions, array $img_conditions): Querylet { global $database; $positive_tag_count = 0; $negative_tag_count = 0; - foreach ($tag_querylets as $tq) { + foreach ($tag_conditions as $tq) { if ($tq->positive) { $positive_tag_count++; } else { @@ -912,15 +912,15 @@ class Image GROUP BY images.id ) AS images WHERE 1=1 - "), ["tag"=>$tag_querylets[0]->tag]); + "), ["tag"=>$tag_conditions[0]->tag]); } // more than one positive tag, or more than zero negative tags else { if ($database->get_driver_name() === "mysql") { - $query = Image::build_ugly_search_querylet($tag_querylets); + $query = Image::build_ugly_search_querylet($tag_conditions); } else { - $query = Image::build_accurate_search_querylet($tag_querylets); + $query = Image::build_accurate_search_querylet($tag_conditions); } } @@ -928,11 +928,11 @@ class Image * Merge all the image metadata searches into one generic querylet * and append to the base querylet with "AND blah" */ - if (!empty($img_querylets)) { + if (!empty($img_conditions)) { $n = 0; $img_sql = ""; $img_vars = []; - foreach ($img_querylets as $iq) { + foreach ($img_conditions as $iq) { if ($n++ > 0) { $img_sql .= " AND"; } @@ -970,16 +970,16 @@ class Image * All the subqueries are executed every time for every row in the * images table. Yes, MySQL does suck this much. * - * #param TagQuerylet[] $tag_querylets + * #param TagQuerylet[] $tag_conditions */ - private static function build_accurate_search_querylet(array $tag_querylets): Querylet + private static function build_accurate_search_querylet(array $tag_conditions): Querylet { global $database; $positive_tag_id_array = []; $negative_tag_id_array = []; - foreach ($tag_querylets as $tq) { + foreach ($tag_conditions as $tq) { $tag_ids = $database->get_col( $database->scoreql_to_sql(" SELECT id @@ -1032,14 +1032,14 @@ class Image * this function exists because mysql is a turd, see the docs for * build_accurate_search_querylet() for a full explanation * - * #param TagQuerylet[] $tag_querylets + * #param TagQuerylet[] $tag_conditions */ - private static function build_ugly_search_querylet(array $tag_querylets): Querylet + private static function build_ugly_search_querylet(array $tag_conditions): Querylet { global $database; $positive_tag_count = 0; - foreach ($tag_querylets as $tq) { + foreach ($tag_conditions as $tq) { if ($tq->positive) { $positive_tag_count++; } @@ -1059,7 +1059,7 @@ class Image // merge all the tag querylets into one generic one $sql = "0"; $terms = []; - foreach ($tag_querylets as $tq) { + foreach ($tag_conditions as $tq) { $sign = $tq->positive ? "+" : "-"; $sql .= ' '.$sign.' IF(SUM(tag LIKE :tag'.Image::$tag_n.'), 1, 0)'; $terms['tag'.Image::$tag_n] = $tq->tag; @@ -1069,7 +1069,7 @@ class Image $tag_id_array = []; - foreach ($tag_querylets as $tq) { + foreach ($tag_conditions as $tq) { $tag_ids = $database->get_col( $database->scoreql_to_sql(" SELECT id diff --git a/core/imageboard/search.php b/core/imageboard/search.php index e3c63940..2960663f 100644 --- a/core/imageboard/search.php +++ b/core/imageboard/search.php @@ -29,7 +29,7 @@ class Querylet } } -class TagQuerylet +class TagCondition { /** @var string */ public $tag; @@ -43,7 +43,7 @@ class TagQuerylet } } -class ImgQuerylet +class ImgCondition { /** @var Querylet */ public $qlet; From e232811e8c1a9f26469d286d0a81ce6886963b40 Mon Sep 17 00:00:00 2001 From: Shish Date: Sun, 16 Jun 2019 18:22:44 +0100 Subject: [PATCH 019/133] silence errors from a broken client --- ext/view/main.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ext/view/main.php b/ext/view/main.php index 261565fa..0e81f6dc 100644 --- a/ext/view/main.php +++ b/ext/view/main.php @@ -126,6 +126,15 @@ class ViewImage extends Extension $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/{$image->id}", $query)); } elseif ($event->page_matches("post/view")) { + if(!is_numeric($event->get_arg(0))) { + // For some reason there exists some very broken mobile client + // who follows up every request to '/post/view/123' with + // '/post/view/12300000000000Image 123: tags' which spams the + // database log with 'integer out of range' + $this->theme->display_error(404, "Image not found", "Invalid image ID"); + return; + } + $image_id = int_escape($event->get_arg(0)); $image = Image::by_id($image_id); From 1d10baa719d22e5b63405db747fd749916a70fd6 Mon Sep 17 00:00:00 2001 From: Shish Date: Sun, 16 Jun 2019 19:25:40 +0100 Subject: [PATCH 020/133] only sql-escape if we're going to the database, not the accelerator --- core/imageboard/image.php | 18 +++++++++--------- core/imageboard/tag.php | 8 ++++++++ ext/view/main.php | 10 +++++----- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 18c646a9..cc2999dc 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -198,6 +198,10 @@ class Image $yays = 0; $nays = 0; foreach ($tag_conditions as $tq) { + if (strpos($tq->tag, "*") !== false) { + // can't deal with wildcards + return null; + } if ($tq->positive) { $yays++; $ret["yays"][] = $tq->tag; @@ -354,12 +358,8 @@ class Image $img_conditions[] = new ImgCondition($querylet, $positive); } } else { - // if the whole match is wild, skip this; - // if not, translate into SQL + // if the whole match is wild, skip this if (str_replace("*", "", $term) != "") { - $term = str_replace('_', '\_', $term); - $term = str_replace('%', '\%', $term); - $term = str_replace('*', '%', $term); $tag_conditions[] = new TagCondition($term, $positive); } } @@ -912,7 +912,7 @@ class Image GROUP BY images.id ) AS images WHERE 1=1 - "), ["tag"=>$tag_conditions[0]->tag]); + "), ["tag"=>Tag::sqlify($tag_conditions[0]->tag)]); } // more than one positive tag, or more than zero negative tags @@ -986,7 +986,7 @@ class Image FROM tags WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(:tag) "), - ["tag" => $tq->tag] + ["tag" => Tag::sqlify($tq->tag)] ); if ($tq->positive) { $positive_tag_id_array = array_merge($positive_tag_id_array, $tag_ids); @@ -1062,7 +1062,7 @@ class Image foreach ($tag_conditions as $tq) { $sign = $tq->positive ? "+" : "-"; $sql .= ' '.$sign.' IF(SUM(tag LIKE :tag'.Image::$tag_n.'), 1, 0)'; - $terms['tag'.Image::$tag_n] = $tq->tag; + $terms['tag'.Image::$tag_n] = Tag::sqlify($tq->tag); Image::$tag_n++; } $tag_search = new Querylet($sql, $terms); @@ -1076,7 +1076,7 @@ class Image FROM tags WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(:tag) "), - ["tag" => $tq->tag] + ["tag" => Tag::sqlify($tq->tag)] ); $tag_id_array = array_merge($tag_id_array, $tag_ids); diff --git a/core/imageboard/tag.php b/core/imageboard/tag.php index 3e32d524..ddce54f6 100644 --- a/core/imageboard/tag.php +++ b/core/imageboard/tag.php @@ -100,4 +100,12 @@ class Tag return $tag_array; } + + public static function sqlify(string $term): string + { + $term = str_replace('_', '\_', $term); + $term = str_replace('%', '\%', $term); + $term = str_replace('*', '%', $term); + return $term; + } } diff --git a/ext/view/main.php b/ext/view/main.php index 0e81f6dc..bfbe2fba 100644 --- a/ext/view/main.php +++ b/ext/view/main.php @@ -126,11 +126,11 @@ class ViewImage extends Extension $page->set_mode("redirect"); $page->set_redirect(make_link("post/view/{$image->id}", $query)); } elseif ($event->page_matches("post/view")) { - if(!is_numeric($event->get_arg(0))) { - // For some reason there exists some very broken mobile client - // who follows up every request to '/post/view/123' with - // '/post/view/12300000000000Image 123: tags' which spams the - // database log with 'integer out of range' + if (!is_numeric($event->get_arg(0))) { + // For some reason there exists some very broken mobile client + // who follows up every request to '/post/view/123' with + // '/post/view/12300000000000Image 123: tags' which spams the + // database log with 'integer out of range' $this->theme->display_error(404, "Image not found", "Invalid image ID"); return; } From 6313ebc339b926af074df01d40b743d1044a8307 Mon Sep 17 00:00:00 2001 From: Shish Date: Sun, 16 Jun 2019 19:39:28 +0100 Subject: [PATCH 021/133] LIMIT 1 when fetching a wiki page --- ext/wiki/main.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ext/wiki/main.php b/ext/wiki/main.php index e3253c9e..360c686a 100644 --- a/ext/wiki/main.php +++ b/ext/wiki/main.php @@ -213,7 +213,7 @@ class Wiki extends Extension return false; } - private function get_page(string $title, int $revision=-1): WikiPage + private function get_page(string $title): WikiPage { global $database; // first try and get the actual page @@ -222,17 +222,21 @@ class Wiki extends Extension SELECT * FROM wiki_pages WHERE SCORE_STRNORM(title) LIKE SCORE_STRNORM(:title) - ORDER BY revision DESC"), + ORDER BY revision DESC + LIMIT 1 + "), ["title"=>$title] ); // fall back to wiki:default if (empty($row)) { $row = $database->get_row(" - SELECT * - FROM wiki_pages - WHERE title LIKE :title - ORDER BY revision DESC", ["title"=>"wiki:default"]); + SELECT * + FROM wiki_pages + WHERE title LIKE :title + ORDER BY revision DESC + LIMIT 1 + ", ["title"=>"wiki:default"]); // fall further back to manual if (empty($row)) { From 014a4c2cd2bbb94d67c0280c47a6c29932f0d4ce Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Tue, 18 Jun 2019 08:06:05 -0500 Subject: [PATCH 022/133] Added extension constant lists to resize and rotate extensions so that they weren't rendering their controls ont he wrong image types --- ext/resize/main.php | 8 ++++++-- ext/rotate/main.php | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ext/resize/main.php b/ext/resize/main.php index bad21f6b..81db9007 100644 --- a/ext/resize/main.php +++ b/ext/resize/main.php @@ -16,6 +16,8 @@ */ class ResizeImage extends Extension { + const SUPPORTED_EXT = ["jpg","jpeg","png","gif","webp"]; + /** * Needs to be after the data processing extensions */ @@ -37,7 +39,8 @@ class ResizeImage extends Extension public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $user, $config; - if ($user->is_admin() && $config->get_bool("resize_enabled")) { + if ($user->is_admin() && $config->get_bool("resize_enabled") + && in_array($event->image->ext, self::SUPPORTED_EXT)) { /* Add a link to resize the image */ $event->add_part($this->theme->get_resize_html($event->image)); } @@ -68,7 +71,8 @@ class ResizeImage extends Extension $image_obj = Image::by_id($event->image_id); - if ($config->get_bool("resize_upload") == true && ($image_obj->ext == "jpg" || $image_obj->ext == "png" || $image_obj->ext == "gif" || $image_obj->ext == "webp")) { + if ($config->get_bool("resize_upload") == true + && in_array($event->type, self::SUPPORTED_EXT)) { $width = $height = 0; if ($config->get_int("resize_default_width") !== 0) { diff --git a/ext/rotate/main.php b/ext/rotate/main.php index b2b1df3d..d612de15 100644 --- a/ext/rotate/main.php +++ b/ext/rotate/main.php @@ -31,6 +31,8 @@ class ImageRotateException extends SCoreException */ class RotateImage extends Extension { + const SUPPORTED_EXT = ["jpg","jpeg","png","gif","webp"]; + public function onInitExt(InitExtEvent $event) { global $config; @@ -41,7 +43,8 @@ class RotateImage extends Extension public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $user, $config; - if ($user->is_admin() && $config->get_bool("rotate_enabled")) { + if ($user->is_admin() && $config->get_bool("rotate_enabled") + && in_array($event->image->ext, self::SUPPORTED_EXT)) { /* Add a link to rotate the image */ $event->add_part($this->theme->get_rotate_html($event->image->id)); } From 826c623538e3bea63b6b867eaf09b6924109abec Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Tue, 18 Jun 2019 20:58:28 -0500 Subject: [PATCH 023/133] PageMode constants --- core/page.php | 13 +++++++++---- ext/admin/main.php | 8 ++++---- ext/alias_editor/main.php | 8 ++++---- ext/artists/main.php | 30 +++++++++++++++--------------- ext/autocomplete/main.php | 2 +- ext/blocks/main.php | 4 ++-- ext/blotter/main.php | 4 ++-- ext/browser_search/main.php | 4 ++-- ext/bulk_actions/main.php | 2 +- ext/comment/main.php | 6 +++--- ext/cron_uploader/main.php | 2 +- ext/danbooru_api/main.php | 4 ++-- ext/downtime/theme.php | 2 +- ext/emoticons/theme.php | 2 +- ext/ext_manager/main.php | 2 +- ext/favorites/main.php | 2 +- ext/featured/main.php | 4 ++-- ext/forum/main.php | 10 +++++----- ext/handle_404/main.php | 2 +- ext/handle_static/main.php | 4 ++-- ext/handle_svg/main.php | 2 +- ext/home/theme.php | 2 +- ext/image/main.php | 6 +++--- ext/image_hash_ban/main.php | 4 ++-- ext/index/main.php | 6 +++--- ext/ipban/main.php | 4 ++-- ext/mail/main.php | 2 +- ext/mass_tagger/main.php | 2 +- ext/not_a_tag/main.php | 4 ++-- ext/notes/main.php | 16 ++++++++-------- ext/numeric_score/main.php | 6 +++--- ext/oekaki/main.php | 2 +- ext/ouroboros_api/main.php | 4 ++-- ext/pm/main.php | 4 ++-- ext/pools/main.php | 20 ++++++++++---------- ext/random_image/main.php | 4 ++-- ext/random_list/main.php | 4 ++-- ext/rating/main.php | 4 ++-- ext/regen_thumb/main.php | 2 +- ext/report_image/main.php | 6 +++--- ext/resize/main.php | 2 +- ext/rotate/main.php | 2 +- ext/rss_comments/main.php | 2 +- ext/rss_images/main.php | 2 +- ext/rule34/main.php | 6 +++--- ext/setup/main.php | 4 ++-- ext/shimmie_api/main.php | 4 ++-- ext/sitemap/main.php | 4 ++-- ext/source_history/main.php | 4 ++-- ext/tag_edit/main.php | 4 ++-- ext/tag_history/main.php | 4 ++-- ext/tag_list/main.php | 2 +- ext/tagger/main.php | 2 +- ext/tips/main.php | 6 +++--- ext/transcode/main.php | 2 +- ext/update/main.php | 4 ++-- ext/upload/theme.php | 2 +- ext/user/main.php | 12 ++++++------ ext/view/main.php | 4 ++-- ext/wiki/main.php | 22 +++++++++------------- tests/bootstrap.php | 4 ++-- themes/material/home.theme.php | 2 +- 62 files changed, 160 insertions(+), 159 deletions(-) diff --git a/core/page.php b/core/page.php index e9b3384b..998adc7d 100644 --- a/core/page.php +++ b/core/page.php @@ -26,6 +26,11 @@ * Various other common functions are available as part of the Themelet class. */ +abstract class PageMode { + const REDIRECT = 'redirect'; + const DATA = 'data'; + const PAGE = 'page'; +} /** * Class Page @@ -40,7 +45,7 @@ class Page /** @name Overall */ //@{ /** @var string */ - public $mode = "page"; + public $mode = PageMode::PAGE; /** @var string */ public $type = "text/html; charset=utf-8"; @@ -261,7 +266,7 @@ class Page } switch ($this->mode) { - case "page": + case PageMode::PAGE: if (CACHE_HTTP) { header("Vary: Cookie, Accept-Encoding"); if ($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") { @@ -285,14 +290,14 @@ class Page $layout = new Layout(); $layout->display_page($page); break; - case "data": + case PageMode::DATA: header("Content-Length: ".strlen($this->data)); if (!is_null($this->filename)) { header('Content-Disposition: attachment; filename='.$this->filename); } print $this->data; break; - case "redirect": + case PageMode::REDIRECT: header('Location: '.$this->redirect); print 'You should be redirected to '.$this->redirect.''; break; diff --git a/ext/admin/main.php b/ext/admin/main.php index 22845575..c9d2feff 100644 --- a/ext/admin/main.php +++ b/ext/admin/main.php @@ -70,7 +70,7 @@ class AdminPage extends Extension } if ($aae->redirect) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("admin")); } } @@ -149,7 +149,7 @@ class AdminPage extends Extension send_event(new ImageDeletionEvent($image)); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list")); return false; } @@ -218,7 +218,7 @@ class AdminPage extends Extension //FIXME: .SQL dump is empty if cmd doesn't exist if ($cmd) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("application/x-unknown"); $page->set_filename('shimmie-'.date('Ymd').'.sql'); $page->set_data(shell_exec($cmd)); @@ -243,7 +243,7 @@ class AdminPage extends Extension $zip->close(); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link($filename)); //TODO: Delete file after downloaded? return false; // we do want a redirect, but a manual one diff --git a/ext/alias_editor/main.php b/ext/alias_editor/main.php index 9e7139cf..07f9f289 100644 --- a/ext/alias_editor/main.php +++ b/ext/alias_editor/main.php @@ -41,7 +41,7 @@ class AliasEditor extends Extension try { $aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); send_event($aae); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("alias/list")); } catch (AddAliasException $ex) { $this->theme->display_error(500, "Error adding alias", $ex->getMessage()); @@ -54,7 +54,7 @@ class AliasEditor extends Extension $database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", ["oldtag" => $_POST['oldtag']]); log_info("alias_editor", "Deleted alias for ".$_POST['oldtag'], "Deleted alias"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("alias/list")); } } @@ -80,7 +80,7 @@ class AliasEditor extends Extension $this->theme->display_aliases($alias, $page_number + 1, $total_pages); } elseif ($event->get_arg(0) == "export") { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("text/csv"); $page->set_filename("aliases.csv"); $page->set_data($this->get_alias_csv($database)); @@ -91,7 +91,7 @@ class AliasEditor extends Extension $contents = file_get_contents($tmp); $this->add_alias_csv($database, $contents); log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many? - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("alias/list")); } else { $this->theme->display_error(400, "No File Specified", "You have to upload a file"); diff --git a/ext/artists/main.php b/ext/artists/main.php index 7a3f3377..568933de 100644 --- a/ext/artists/main.php +++ b/ext/artists/main.php @@ -172,7 +172,7 @@ class Artists extends Extension } case "new_artist": { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/new")); break; } @@ -183,7 +183,7 @@ class Artists extends Extension if ($newArtistID == -1) { $this->theme->display_error(400, "Error", "Error when entering artist data."); } else { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$newArtistID)); } } else { @@ -238,7 +238,7 @@ class Artists extends Extension case "edit_artist": { $artistID = $_POST['artist_id']; - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/edit/".$artistID)); break; } @@ -246,14 +246,14 @@ class Artists extends Extension { $artistID = int_escape($_POST['id']); $this->update_artist(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } case "nuke_artist": { $artistID = $_POST['artist_id']; - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/nuke/".$artistID)); break; } @@ -261,7 +261,7 @@ class Artists extends Extension { $artistID = $event->get_arg(1); $this->delete_artist($artistID); // this will delete the artist, its alias, its urls and its members - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/list")); break; } @@ -291,7 +291,7 @@ class Artists extends Extension { $artistID = $_POST['artistID']; $this->add_alias(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -300,7 +300,7 @@ class Artists extends Extension $aliasID = $event->get_arg(2); $artistID = $this->get_artistID_by_aliasID($aliasID); $this->delete_alias($aliasID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -316,7 +316,7 @@ class Artists extends Extension $this->update_alias(); $aliasID = int_escape($_POST['aliasID']); $artistID = $this->get_artistID_by_aliasID($aliasID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -332,7 +332,7 @@ class Artists extends Extension { $artistID = $_POST['artistID']; $this->add_urls(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -341,7 +341,7 @@ class Artists extends Extension $urlID = $event->get_arg(2); $artistID = $this->get_artistID_by_urlID($urlID); $this->delete_url($urlID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -357,7 +357,7 @@ class Artists extends Extension $this->update_url(); $urlID = int_escape($_POST['urlID']); $artistID = $this->get_artistID_by_urlID($urlID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -372,7 +372,7 @@ class Artists extends Extension { $artistID = $_POST['artistID']; $this->add_members(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -381,7 +381,7 @@ class Artists extends Extension $memberID = int_escape($event->get_arg(2)); $artistID = $this->get_artistID_by_memberID($memberID); $this->delete_member($memberID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } @@ -397,7 +397,7 @@ class Artists extends Extension $this->update_member(); $memberID = int_escape($_POST['memberID']); $artistID = $this->get_artistID_by_memberID($memberID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("artist/view/".$artistID)); break; } diff --git a/ext/autocomplete/main.php b/ext/autocomplete/main.php index eb71227b..a7c85050 100644 --- a/ext/autocomplete/main.php +++ b/ext/autocomplete/main.php @@ -21,7 +21,7 @@ class AutoComplete extends Extension return; } - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("application/json"); $s = strtolower($_GET["s"]); diff --git a/ext/blocks/main.php b/ext/blocks/main.php index 86e0a1c5..cb9c375c 100644 --- a/ext/blocks/main.php +++ b/ext/blocks/main.php @@ -61,7 +61,7 @@ class Blocks extends Extension ", [$_POST['pages'], $_POST['title'], $_POST['area'], (int)$_POST['priority'], $_POST['content']]); log_info("blocks", "Added Block #".($database->get_last_insert_id('blocks_id_seq'))." (".$_POST['title'].")"); $database->cache->delete("blocks"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("blocks/list")); } } @@ -81,7 +81,7 @@ class Blocks extends Extension log_info("blocks", "Updated Block #".$_POST['id']." (".$_POST['title'].")"); } $database->cache->delete("blocks"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("blocks/list")); } } elseif ($event->get_arg(0) == "list") { diff --git a/ext/blotter/main.php b/ext/blotter/main.php index 8f54576e..cb88490b 100644 --- a/ext/blotter/main.php +++ b/ext/blotter/main.php @@ -102,7 +102,7 @@ class Blotter extends Extension [$entry_text, $important] ); log_info("blotter", "Added Message: $entry_text"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("blotter/editor")); } break; @@ -119,7 +119,7 @@ class Blotter extends Extension } $database->Execute("DELETE FROM blotter WHERE id=:id", ["id"=>$id]); log_info("blotter", "Removed Entry #$id"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("blotter/editor")); } break; diff --git a/ext/browser_search/main.php b/ext/browser_search/main.php index 10950000..7c1fcc82 100644 --- a/ext/browser_search/main.php +++ b/ext/browser_search/main.php @@ -54,7 +54,7 @@ class BrowserSearch extends Extension "; // And now to send it to the browser - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("text/xml"); $page->set_data($xml); } elseif ( @@ -85,7 +85,7 @@ class BrowserSearch extends Extension // And now for the final output $json_string = "[\"$tag_search\",[\"$json_tag_list\"],[],[]]"; - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_data($json_string); } } diff --git a/ext/bulk_actions/main.php b/ext/bulk_actions/main.php index 2c93de4e..073a85f1 100644 --- a/ext/bulk_actions/main.php +++ b/ext/bulk_actions/main.php @@ -171,7 +171,7 @@ class BulkActions extends Extension } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); if (!isset($_SERVER['HTTP_REFERER'])) { $_SERVER['HTTP_REFERER'] = make_link(); } diff --git a/ext/comment/main.php b/ext/comment/main.php index 75b171d4..d4cef828 100644 --- a/ext/comment/main.php +++ b/ext/comment/main.php @@ -178,7 +178,7 @@ class CommentList extends Extension $i_iid = int_escape($_POST['image_id']); $cpe = new CommentPostingEvent($_POST['image_id'], $user, $_POST['comment']); send_event($cpe); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$i_iid#comment_on_$i_iid")); } catch (CommentPostingException $ex) { $this->theme->display_error(403, "Comment Blocked", $ex->getMessage()); @@ -194,7 +194,7 @@ class CommentList extends Extension if ($event->count_args() === 3) { send_event(new CommentDeletionEvent($event->get_arg(1))); flash_message("Deleted comment"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); if (!empty($_SERVER['HTTP_REFERER'])) { $page->set_redirect($_SERVER['HTTP_REFERER']); } else { @@ -224,7 +224,7 @@ class CommentList extends Extension } flash_message("Deleted $num comments"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("admin")); } else { $this->theme->display_permission_denied(); diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index 87947b96..977a4f7a 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -456,7 +456,7 @@ class CronUploader extends Extension global $page; // Display message - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("text/plain"); $page->set_data($this->upload_info); diff --git a/ext/danbooru_api/main.php b/ext/danbooru_api/main.php index a831f366..ce13295b 100644 --- a/ext/danbooru_api/main.php +++ b/ext/danbooru_api/main.php @@ -60,7 +60,7 @@ class DanbooruApi extends Extension private function api_danbooru(PageRequestEvent $event) { global $page; - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); if (($event->get_arg(1) == 'add_post') || (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'create.xml'))) { // No XML data is returned from this function @@ -80,7 +80,7 @@ class DanbooruApi extends Extension // This redirects that to http://shimmie/post/view/123 elseif (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'show')) { $fixedlocation = make_link("post/view/" . $event->get_arg(3)); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect($fixedlocation); } } diff --git a/ext/downtime/theme.php b/ext/downtime/theme.php index feb7e4ea..caedcfda 100644 --- a/ext/downtime/theme.php +++ b/ext/downtime/theme.php @@ -26,7 +26,7 @@ class DowntimeTheme extends Themelet $login_link = make_link("user_admin/login"); $auth = $user->get_auth_html(); - $page->set_mode('data'); + $page->set_mode(PageMode::DATA); $page->set_code(503); $page->set_data( <<set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_data($html); } } diff --git a/ext/ext_manager/main.php b/ext/ext_manager/main.php index 4739fb9d..b41b53dd 100644 --- a/ext/ext_manager/main.php +++ b/ext/ext_manager/main.php @@ -125,7 +125,7 @@ class ExtManager extends Extension if (is_writable("data/config")) { $this->set_things($_POST); log_warning("ext_manager", "Active extensions changed", "Active extensions changed"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("ext_manager")); } else { $this->theme->display_error( diff --git a/ext/favorites/main.php b/ext/favorites/main.php index 1ccf2031..e8b7f6fe 100644 --- a/ext/favorites/main.php +++ b/ext/favorites/main.php @@ -81,7 +81,7 @@ class Favorites extends Extension log_debug("favourite", "Favourite removed for $image_id", "Favourite removed"); } } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$image_id")); } } diff --git a/ext/featured/main.php b/ext/featured/main.php index c58be8b4..4b713424 100644 --- a/ext/featured/main.php +++ b/ext/featured/main.php @@ -37,7 +37,7 @@ class Featured extends Extension if ($id > 0) { $config->set_int("featured_id", $id); log_info("featured", "Featured image set to $id", "Featured image set"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$id")); } } @@ -45,7 +45,7 @@ class Featured extends Extension if ($event->get_arg(0) == "download") { $image = Image::by_id($config->get_int("featured_id")); if (!is_null($image)) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type($image->get_mime_type()); $page->set_data(file_get_contents($image->get_image_filename())); } diff --git a/ext/forum/main.php b/ext/forum/main.php index 95d79908..db2ff1a8 100644 --- a/ext/forum/main.php +++ b/ext/forum/main.php @@ -139,7 +139,7 @@ class Forum extends Extension $redirectTo = "forum/view/".$newThreadID."/1"; } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link($redirectTo)); break; @@ -151,7 +151,7 @@ class Forum extends Extension $this->delete_post($postID); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("forum/view/".$threadID)); break; case "nuke": @@ -161,7 +161,7 @@ class Forum extends Extension $this->delete_thread($threadID); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("forum/index")); break; case "answer": @@ -176,11 +176,11 @@ class Forum extends Extension } $this->save_new_post($threadID, $user); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("forum/view/".$threadID."/".$total_pages)); break; default: - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("forum/index")); //$this->theme->display_error(400, "Invalid action", "You should check forum/index."); break; diff --git a/ext/handle_404/main.php b/ext/handle_404/main.php index 4bc31dfd..a45ea7fb 100644 --- a/ext/handle_404/main.php +++ b/ext/handle_404/main.php @@ -14,7 +14,7 @@ class Handle404 extends Extension { global $config, $page; // hax. - if ($page->mode == "page" && (!isset($page->blocks) || $this->count_main($page->blocks) == 0)) { + if ($page->mode == PageMode::PAGE && (!isset($page->blocks) || $this->count_main($page->blocks) == 0)) { $h_pagename = html_escape(implode('/', $event->args)); log_debug("handle_404", "Hit 404: $h_pagename"); $page->set_code(404); diff --git a/ext/handle_static/main.php b/ext/handle_static/main.php index e2dd7de1..fb20dd59 100644 --- a/ext/handle_static/main.php +++ b/ext/handle_static/main.php @@ -14,7 +14,7 @@ class HandleStatic extends Extension { global $config, $page; // hax. - if ($page->mode == "page" && (!isset($page->blocks) || $this->count_main($page->blocks) == 0)) { + if ($page->mode == PageMode::PAGE && (!isset($page->blocks) || $this->count_main($page->blocks) == 0)) { $h_pagename = html_escape(implode('/', $event->args)); $f_pagename = preg_replace("/[^a-z_\-\.]+/", "_", $h_pagename); $theme_name = $config->get_string("theme", "default"); @@ -27,7 +27,7 @@ class HandleStatic extends Extension $page->add_http_header("Cache-control: public, max-age=600"); $page->add_http_header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 600) . ' GMT'); - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_data(file_get_contents($filename)); if (endsWith($filename, ".ico")) { $page->set_type("image/x-icon"); diff --git a/ext/handle_svg/main.php b/ext/handle_svg/main.php index a15942b1..96dea29a 100644 --- a/ext/handle_svg/main.php +++ b/ext/handle_svg/main.php @@ -57,7 +57,7 @@ class SVGFileHandler extends DataHandlerExtension $hash = $image->hash; $page->set_type("image/svg+xml"); - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $sanitizer = new Sanitizer(); $sanitizer->removeRemoteReferences(true); diff --git a/ext/home/theme.php b/ext/home/theme.php index e8f4086d..8dfc666d 100644 --- a/ext/home/theme.php +++ b/ext/home/theme.php @@ -4,7 +4,7 @@ class HomeTheme extends Themelet { public function display_page(Page $page, $sitename, $base_href, $theme_name, $body) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->add_auto_html_headers(); $hh = $page->get_all_html_headers(); $page->set_data( diff --git a/ext/image/main.php b/ext/image/main.php index 56405d65..f9b31180 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -43,7 +43,7 @@ class ImageIO extends Extension $image = Image::by_id($_POST['image_id']); if ($image) { send_event(new ImageDeletionEvent($image)); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); if (isset($_SERVER['HTTP_REFERER']) && !strstr($_SERVER['HTTP_REFERER'], 'post/view')) { $page->set_redirect($_SERVER['HTTP_REFERER']); } else { @@ -56,7 +56,7 @@ class ImageIO extends Extension if ($user->can("replace_image") && isset($_POST['image_id']) && $user->check_auth_token()) { $image = Image::by_id($_POST['image_id']); if ($image) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link('upload/replace/'.$image->id)); } else { /* Invalid image ID */ @@ -251,7 +251,7 @@ class ImageIO extends Extension global $page; if (!is_null($image)) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); if ($type == "thumb") { $ext = $config->get_string("thumb_type"); if (array_key_exists($ext, MIME_TYPE_MAP)) { diff --git a/ext/image_hash_ban/main.php b/ext/image_hash_ban/main.php index 6589ee16..c2e3ec3a 100644 --- a/ext/image_hash_ban/main.php +++ b/ext/image_hash_ban/main.php @@ -79,7 +79,7 @@ class ImageBan extends Extension flash_message("Image deleted"); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect($_SERVER['HTTP_REFERER']); } } elseif ($event->get_arg(0) == "remove") { @@ -87,7 +87,7 @@ class ImageBan extends Extension send_event(new RemoveImageHashBanEvent($_POST['hash'])); flash_message("Image ban removed"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect($_SERVER['HTTP_REFERER']); } } elseif ($event->get_arg(0) == "list") { diff --git a/ext/index/main.php b/ext/index/main.php index f8d77843..7e37f7ea 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -239,10 +239,10 @@ class Index extends Extension // implode(explode()) to resolve aliases and sanitise $search = url_escape(Tag::implode(Tag::explode($_GET['search'], false))); if (empty($search)) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list/1")); } else { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link('post/list/'.$search.'/1')); } return; @@ -278,7 +278,7 @@ class Index extends Extension $this->theme->display_intro($page); send_event(new PostListBuildingEvent($search_terms)); } elseif ($count_search_terms > 0 && $count_images === 1 && $page_number === 1) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link('post/view/'.$images[0]->id)); } else { $plbe = new PostListBuildingEvent($search_terms); diff --git a/ext/ipban/main.php b/ext/ipban/main.php index 541c853b..f86c10ff 100644 --- a/ext/ipban/main.php +++ b/ext/ipban/main.php @@ -77,7 +77,7 @@ class IPBan extends Extension send_event(new AddIPBanEvent($_POST['ip'], $_POST['reason'], $end)); flash_message("Ban for {$_POST['ip']} added"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("ip_ban/list")); } } elseif ($event->get_arg(0) == "remove" && $user->check_auth_token()) { @@ -85,7 +85,7 @@ class IPBan extends Extension send_event(new RemoveIPBanEvent($_POST['id'])); flash_message("Ban removed"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("ip_ban/list")); } } elseif ($event->get_arg(0) == "list") { diff --git a/ext/mail/main.php b/ext/mail/main.php index 3e51bcb4..35fb2061 100644 --- a/ext/mail/main.php +++ b/ext/mail/main.php @@ -35,7 +35,7 @@ class MailTest extends Extension { if ($event->page_matches("mail/test")) { global $page; - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); echo "Alert: uncomment this page's code on /ext/mail/main.php starting on line 33, and change the email address. Make sure you're using a server with a domain, not localhost."; /* echo "Preparing to send message:
"; diff --git a/ext/mass_tagger/main.php b/ext/mass_tagger/main.php index 648d7b79..fe91b366 100644 --- a/ext/mass_tagger/main.php +++ b/ext/mass_tagger/main.php @@ -64,7 +64,7 @@ class MassTagger extends Extension } } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); if (!isset($_SERVER['HTTP_REFERER'])) { $_SERVER['HTTP_REFERER'] = make_link(); } diff --git a/ext/not_a_tag/main.php b/ext/not_a_tag/main.php index c03b0e81..18486e9c 100644 --- a/ext/not_a_tag/main.php +++ b/ext/not_a_tag/main.php @@ -81,14 +81,14 @@ class NotATag extends Extension [$tag, $redirect] ); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect($_SERVER['HTTP_REFERER']); } elseif ($event->get_arg(0) == "remove") { if (isset($_POST['tag'])) { $database->Execute("DELETE FROM untags WHERE tag = ?", [$_POST['tag']]); flash_message("Image ban removed"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect($_SERVER['HTTP_REFERER']); } } elseif ($event->get_arg(0) == "list") { diff --git a/ext/notes/main.php b/ext/notes/main.php index 14285df2..aafa928f 100644 --- a/ext/notes/main.php +++ b/ext/notes/main.php @@ -100,7 +100,7 @@ class Notes extends Extension $this->revert_history($noteID, $reviewID); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("note/updated")); break; case "add_note": @@ -108,7 +108,7 @@ class Notes extends Extension $this->add_new_note(); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "add_request": @@ -116,7 +116,7 @@ class Notes extends Extension $this->add_note_request(); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "nuke_notes": @@ -124,7 +124,7 @@ class Notes extends Extension $this->nuke_notes(); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "nuke_requests": @@ -132,25 +132,25 @@ class Notes extends Extension $this->nuke_requests(); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); break; case "edit_note": if (!$user->is_anonymous()) { $this->update_note(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/" . $_POST["image_id"])); } break; case "delete_note": if ($user->is_admin()) { $this->delete_note(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$_POST["image_id"])); } break; default: - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("note/list")); break; } diff --git a/ext/numeric_score/main.php b/ext/numeric_score/main.php index f15a9d37..5275dfa7 100644 --- a/ext/numeric_score/main.php +++ b/ext/numeric_score/main.php @@ -94,7 +94,7 @@ class NumericScore extends Extension if (!is_null($score) && $image_id>0) { send_event(new NumericScoreSetEvent($image_id, $user, $score)); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$image_id")); } } elseif ($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) { @@ -108,13 +108,13 @@ class NumericScore extends Extension "UPDATE images SET numeric_score=0 WHERE id=?", [$image_id] ); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$image_id")); } } elseif ($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) { if ($user->can("edit_other_vote")) { $this->delete_votes_by(int_escape($_POST['user_id'])); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link()); } } elseif ($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) { diff --git a/ext/oekaki/main.php b/ext/oekaki/main.php index f18383e9..1da9cc90 100644 --- a/ext/oekaki/main.php +++ b/ext/oekaki/main.php @@ -41,7 +41,7 @@ class Oekaki extends Extension throw new UploadException("File type not recognised"); } else { unlink($tmpname); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$duev->image_id)); } } diff --git a/ext/ouroboros_api/main.php b/ext/ouroboros_api/main.php index 9434f6aa..91fd85ef 100644 --- a/ext/ouroboros_api/main.php +++ b/ext/ouroboros_api/main.php @@ -404,7 +404,7 @@ class OuroborosAPI extends Extension } elseif ($this->type == 'xml') { $page->set_type('text/xml; charset=utf-8'); } - $page->set_mode('data'); + $page->set_mode(PageMode::DATA); $this->tryAuth(); if ($event->page_matches('post')) { @@ -464,7 +464,7 @@ class OuroborosAPI extends Extension } } } elseif ($event->page_matches('post/show')) { - $page->set_mode('redirect'); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link(str_replace('post/show', 'post/view', implode('/', $event->args)))); $page->display(); die(); diff --git a/ext/pm/main.php b/ext/pm/main.php index 2cf8d0a7..123d6368 100644 --- a/ext/pm/main.php +++ b/ext/pm/main.php @@ -149,7 +149,7 @@ class PrivMsg extends Extension $database->execute("DELETE FROM private_message WHERE id = :id", ["id" => $pm_id]); $database->cache->delete("pm-count-{$user->id}"); log_info("pm", "Deleted PM #$pm_id", "PM deleted"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect($_SERVER["HTTP_REFERER"]); } } @@ -162,7 +162,7 @@ class PrivMsg extends Extension $message = $_POST["message"]; send_event(new SendPMEvent(new PM($from_id, $_SERVER["REMOTE_ADDR"], $to_id, $subject, $message))); flash_message("PM sent"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect($_SERVER["HTTP_REFERER"]); } break; diff --git a/ext/pools/main.php b/ext/pools/main.php index 6fd35b9e..bdf8ce87 100644 --- a/ext/pools/main.php +++ b/ext/pools/main.php @@ -130,7 +130,7 @@ class Pools extends Extension case "create": // ADD _POST try { $newPoolID = $this->add_pool(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/view/".$newPoolID)); } catch (PoolCreationException $e) { $this->theme->display_error(400, "Error", $e->error); @@ -150,7 +150,7 @@ class Pools extends Extension if (!$user->is_anonymous()) { $historyID = int_escape($event->get_arg(1)); $this->revert_history($historyID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/updated")); } break; @@ -159,7 +159,7 @@ class Pools extends Extension if ($this->have_permission($user, $pool)) { $this->theme->edit_pool($page, $this->get_pool($pool_id), $this->edit_posts($pool_id)); } else { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/view/".$pool_id)); } break; @@ -169,13 +169,13 @@ class Pools extends Extension if ($this->have_permission($user, $pool)) { $this->theme->edit_order($page, $this->get_pool($pool_id), $this->edit_order($pool_id)); } else { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/view/".$pool_id)); } } else { if ($this->have_permission($user, $pool)) { $this->order_posts(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/view/".$pool_id)); } else { $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); @@ -194,7 +194,7 @@ class Pools extends Extension case "add_posts": if ($this->have_permission($user, $pool)) { $this->add_posts(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/view/".$pool_id)); } else { $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); @@ -204,7 +204,7 @@ class Pools extends Extension case "remove_posts": if ($this->have_permission($user, $pool)) { $this->remove_posts(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/view/".$pool_id)); } else { $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); @@ -215,7 +215,7 @@ class Pools extends Extension case "edit_description": if ($this->have_permission($user, $pool)) { $this->edit_description(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/view/".$pool_id)); } else { $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); @@ -228,7 +228,7 @@ class Pools extends Extension // -> Only admins and owners may do this if ($user->is_admin() || $user->id == $pool['user_id']) { $this->nuke_pool($pool_id); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/list")); } else { $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); @@ -236,7 +236,7 @@ class Pools extends Extension break; default: - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("pool/list")); break; } diff --git a/ext/random_image/main.php b/ext/random_image/main.php index 6630b8cb..fc0424f7 100644 --- a/ext/random_image/main.php +++ b/ext/random_image/main.php @@ -40,7 +40,7 @@ class RandomImage extends Extension if ($action === "download") { if (!is_null($image)) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type($image->get_mime_type()); $page->set_data(file_get_contents($image->get_image_filename())); } @@ -50,7 +50,7 @@ class RandomImage extends Extension } } elseif ($action === "widget") { if (!is_null($image)) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("text/html"); $page->set_data($this->theme->build_thumb_html($image)); } diff --git a/ext/random_list/main.php b/ext/random_list/main.php index a4da5604..7333905d 100644 --- a/ext/random_list/main.php +++ b/ext/random_list/main.php @@ -21,10 +21,10 @@ class RandomList extends Extension // implode(explode()) to resolve aliases and sanitise $search = url_escape(Tag::implode(Tag::explode($_GET['search'], false))); if (empty($search)) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("random")); } else { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link('random/'.$search)); } return; diff --git a/ext/rating/main.php b/ext/rating/main.php index 9f32280d..794129e4 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -91,7 +91,7 @@ class Ratings extends Extension $user_view_level = Ratings::get_user_privs($user); $user_view_level = preg_split('//', $user_view_level, -1); if (!in_array($event->image->rating, $user_view_level)) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list")); } } @@ -228,7 +228,7 @@ class Ratings extends Extension # select image_id from image_tags join tags # on image_tags.tag_id = tags.id where tags.tag = ?); # ", array($_POST["rating"], $_POST["tag"])); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list")); } } diff --git a/ext/regen_thumb/main.php b/ext/regen_thumb/main.php index a653e902..b402281f 100644 --- a/ext/regen_thumb/main.php +++ b/ext/regen_thumb/main.php @@ -43,7 +43,7 @@ class RegenThumb extends Extension $this->regenerate_thumbnail($image); } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list")); } } diff --git a/ext/report_image/main.php b/ext/report_image/main.php index 0e716fec..d3ee2c81 100644 --- a/ext/report_image/main.php +++ b/ext/report_image/main.php @@ -67,7 +67,7 @@ class ReportImage extends Extension if (!empty($_POST['image_id']) && !empty($_POST['reason'])) { $image_id = int_escape($_POST['image_id']); send_event(new AddReportedImageEvent(new ImageReport($image_id, $user->id, $_POST['reason']))); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$image_id")); } else { $this->theme->display_error(500, "Missing input", "Missing image ID or report reason"); @@ -76,7 +76,7 @@ class ReportImage extends Extension if (!empty($_POST['id'])) { if ($user->can("view_image_report")) { send_event(new RemoveReportedImageEvent($_POST['id'])); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("image_report/list")); } } else { @@ -85,7 +85,7 @@ class ReportImage extends Extension } elseif ($event->get_arg(0) == "remove_reports_by" && $user->check_auth_token()) { if ($user->can("view_image_report")) { $this->delete_reports_by(int_escape($_POST['user_id'])); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link()); } } elseif ($event->get_arg(0) == "list") { diff --git a/ext/resize/main.php b/ext/resize/main.php index 81db9007..785fcc31 100644 --- a/ext/resize/main.php +++ b/ext/resize/main.php @@ -149,7 +149,7 @@ class ResizeImage extends Extension //$this->theme->display_resize_page($page, $image_id); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$image_id)); } catch (ImageResizeException $e) { $this->theme->display_resize_error($page, "Error Resizing", $e->error); diff --git a/ext/rotate/main.php b/ext/rotate/main.php index d612de15..65194bbc 100644 --- a/ext/rotate/main.php +++ b/ext/rotate/main.php @@ -96,7 +96,7 @@ class RotateImage extends Extension //$this->theme->display_rotate_page($page, $image_id); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$image_id)); } catch (ImageRotateException $e) { $this->theme->display_rotate_error($page, "Error Rotating", $e->error); diff --git a/ext/rss_comments/main.php b/ext/rss_comments/main.php index dfc37717..012bca93 100644 --- a/ext/rss_comments/main.php +++ b/ext/rss_comments/main.php @@ -24,7 +24,7 @@ class RSS_Comments extends Extension { global $config, $database, $page; if ($event->page_matches("rss/comments")) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("application/rss+xml"); $comments = $database->get_all(" diff --git a/ext/rss_images/main.php b/ext/rss_images/main.php index 292ecf05..b11fad92 100644 --- a/ext/rss_images/main.php +++ b/ext/rss_images/main.php @@ -39,7 +39,7 @@ class RSS_Images extends Extension { global $page; global $config; - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("application/rss+xml"); $data = ""; diff --git a/ext/rule34/main.php b/ext/rule34/main.php index 775fe0ec..4dc2a241 100644 --- a/ext/rule34/main.php +++ b/ext/rule34/main.php @@ -90,14 +90,14 @@ class Rule34 extends Extension 'UPDATE users SET comic_admin=? WHERE id=?', [$input['is_admin'] ? 't' : 'f', $input['user_id']] ); - $page->set_mode('redirect'); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(@$_SERVER['HTTP_REFERER']); } } if ($event->page_matches("tnc_agreed")) { setcookie("ui-tnc-agreed", "true", 0, "/"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(@$_SERVER['HTTP_REFERER'] ?? "/"); } @@ -123,7 +123,7 @@ class Rule34 extends Extension } } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("admin")); } } diff --git a/ext/setup/main.php b/ext/setup/main.php index b316c975..23999102 100644 --- a/ext/setup/main.php +++ b/ext/setup/main.php @@ -203,7 +203,7 @@ class Setup extends Extension global $config, $page, $user; if ($event->page_matches("nicetest")) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_data("ok"); } @@ -216,7 +216,7 @@ class Setup extends Extension $config->save(); flash_message("Config saved"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("setup")); } elseif ($event->get_arg(0) == "advanced") { $this->theme->display_advanced($page, $config->values); diff --git a/ext/shimmie_api/main.php b/ext/shimmie_api/main.php index ed5a3e1c..130c4971 100644 --- a/ext/shimmie_api/main.php +++ b/ext/shimmie_api/main.php @@ -53,7 +53,7 @@ class ShimmieApi extends Extension global $page, $user; if ($event->page_matches("api/shimmie")) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("text/plain"); if ($event->page_matches("api/shimmie/get_tags")) { @@ -100,7 +100,7 @@ class ShimmieApi extends Extension $all = $this->api_get_user($type, $query); $page->set_data(json_encode($all)); } else { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("ext_doc/shimmie_api")); } } diff --git a/ext/sitemap/main.php b/ext/sitemap/main.php index d7a17217..4ff80f88 100644 --- a/ext/sitemap/main.php +++ b/ext/sitemap/main.php @@ -152,7 +152,7 @@ class XMLSitemap extends Extension // Generate new sitemap file_put_contents($this->sitemap_filepath, $xml); - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("application/xml"); $page->set_data($xml); } @@ -188,7 +188,7 @@ class XMLSitemap extends Extension $xml = file_get_contents($this->sitemap_filepath); - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("application/xml"); $page->set_data($xml); } diff --git a/ext/source_history/main.php b/ext/source_history/main.php index d8de6b55..591fd217 100644 --- a/ext/source_history/main.php +++ b/ext/source_history/main.php @@ -132,7 +132,7 @@ class Source_History extends Extension // check for the nothing case if ($revert_id < 1) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link()); return; } @@ -165,7 +165,7 @@ class Source_History extends Extension send_event(new SourceSetEvent($image, $stored_source)); // all should be done now so redirect the user back to the image - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link('post/view/'.$stored_image_id)); } diff --git a/ext/tag_edit/main.php b/ext/tag_edit/main.php index 19f0dfa0..aa443797 100644 --- a/ext/tag_edit/main.php +++ b/ext/tag_edit/main.php @@ -165,14 +165,14 @@ class TagEdit extends Extension $search = $_POST['search']; $replace = $_POST['replace']; $this->mass_tag_edit($search, $replace); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("admin")); } } if ($event->get_arg(0) == "mass_source_set") { if ($user->can("mass_tag_edit") && isset($_POST['tags']) && isset($_POST['source'])) { $this->mass_source_edit($_POST['tags'], $_POST['source']); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list")); } } diff --git a/ext/tag_history/main.php b/ext/tag_history/main.php index 125c36c7..618bd85a 100644 --- a/ext/tag_history/main.php +++ b/ext/tag_history/main.php @@ -132,7 +132,7 @@ class Tag_History extends Extension // check for the nothing case if ($revert_id < 1) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link()); return; } @@ -162,7 +162,7 @@ class Tag_History extends Extension send_event(new TagSetEvent($image, Tag::explode($stored_tags))); // all should be done now so redirect the user back to the image - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link('post/view/'.$stored_image_id)); } diff --git a/ext/tag_list/main.php b/ext/tag_list/main.php index c546794e..a415d153 100644 --- a/ext/tag_list/main.php +++ b/ext/tag_list/main.php @@ -75,7 +75,7 @@ class TagList extends Extension $database->cache->set($cache_key, $res, 600); } - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("text/plain"); $page->set_data(implode("\n", $res)); } diff --git a/ext/tagger/main.php b/ext/tagger/main.php index e7a9148e..631da7b4 100644 --- a/ext/tagger/main.php +++ b/ext/tagger/main.php @@ -59,7 +59,7 @@ class TaggerXML extends Extension $tags. ""; - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->set_type("text/xml"); $page->set_data($xml); } diff --git a/ext/tips/main.php b/ext/tips/main.php index 04fb5124..5fd54e0d 100644 --- a/ext/tips/main.php +++ b/ext/tips/main.php @@ -51,7 +51,7 @@ class Tips extends Extension case "save": if ($user->check_auth_token()) { $this->saveTip(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("tips/list")); } break; @@ -59,14 +59,14 @@ class Tips extends Extension // FIXME: HTTP GET CSRF $tipID = int_escape($event->get_arg(1)); $this->setStatus($tipID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("tips/list")); break; case "delete": // FIXME: HTTP GET CSRF $tipID = int_escape($event->get_arg(1)); $this->deleteTip($tipID); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("tips/list")); break; } diff --git a/ext/transcode/main.php b/ext/transcode/main.php index ba7e0947..94520ba0 100644 --- a/ext/transcode/main.php +++ b/ext/transcode/main.php @@ -199,7 +199,7 @@ class TranscodeImage extends Extension if (isset($_POST['transcode_format'])) { try { $this->transcode_and_replace_image($image_obj, $_POST['transcode_format']); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/".$image_id)); } catch (ImageTranscodeException $e) { $this->theme->display_transcode_error($page, "Error Transcoding", $e->getMessage()); diff --git a/ext/update/main.php b/ext/update/main.php index cf995c10..00762620 100644 --- a/ext/update/main.php +++ b/ext/update/main.php @@ -38,7 +38,7 @@ class Update extends Extension if ($event->page_matches("update/download")) { $ok = $this->download_shimmie(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); if ($ok) { $page->set_redirect(make_link("update/update", "sha=".$_GET['sha'])); } else { @@ -47,7 +47,7 @@ class Update extends Extension } elseif ($event->page_matches("update/update")) { $ok = $this->update_shimmie(); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); if ($ok) { $page->set_redirect(make_link("admin")); } //TODO: Show success? diff --git a/ext/upload/theme.php b/ext/upload/theme.php index 71041030..6b3b503a 100644 --- a/ext/upload/theme.php +++ b/ext/upload/theme.php @@ -300,7 +300,7 @@ class UploadTheme extends Themelet public function display_upload_status(Page $page, bool $ok) { if ($ok) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link()); } else { $page->set_title("Upload Status"); diff --git a/ext/user/main.php b/ext/user/main.php index f9ecc54c..58c6ce38 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -372,7 +372,7 @@ class UserPage extends Extension if (!is_null($duser)) { $user = $duser; $this->set_login_cookie($duser->name, $pass); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); // Try returning to previous page if ($config->get_int("user_loginshowprofile", 0) == 0 && @@ -397,7 +397,7 @@ class UserPage extends Extension $page->add_cookie("user", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/"); } log_info("user", "Logged out"); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); // Try forwarding to same page on logout unless user comes from registration page if ($config->get_int("user_loginshowprofile", 0) == 0 && @@ -440,7 +440,7 @@ class UserPage extends Extension $uce = new UserCreationEvent($_POST['name'], $_POST['pass1'], $_POST['email']); send_event($uce); $this->set_login_cookie($uce->username, $uce->password); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("user")); } catch (UserCreationException $ex) { $this->theme->display_error(400, "User Creation Error", $ex->getMessage()); @@ -532,10 +532,10 @@ class UserPage extends Extension global $page, $user; if ($user->id == $duser->id) { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("user")); } else { - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("user/{$duser->name}")); } } @@ -698,7 +698,7 @@ class UserPage extends Extension ["id" => $_POST['id']] ); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list")); } } diff --git a/ext/view/main.php b/ext/view/main.php index bfbe2fba..bb2ee8c6 100644 --- a/ext/view/main.php +++ b/ext/view/main.php @@ -123,7 +123,7 @@ class ViewImage extends Extension return; } - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/{$image->id}", $query)); } elseif ($event->page_matches("post/view")) { if (!is_numeric($event->get_arg(0))) { @@ -157,7 +157,7 @@ class ViewImage extends Extension send_event(new ImageInfoSetEvent(Image::by_id($image_id))); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$image_id", url_escape(@$_POST['query']))); } } diff --git a/ext/wiki/main.php b/ext/wiki/main.php index 360c686a..7279b630 100644 --- a/ext/wiki/main.php +++ b/ext/wiki/main.php @@ -137,7 +137,7 @@ class Wiki extends Extension send_event(new WikiUpdateEvent($user, $wikipage)); $u_title = url_escape($title); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("wiki/$u_title")); } catch (WikiUpdateException $e) { $original = $this->get_page($title); @@ -159,7 +159,7 @@ class Wiki extends Extension ["title"=>$_POST["title"], "rev"=>$_POST["revision"]] ); $u_title = url_escape($_POST["title"]); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("wiki/$u_title")); } } elseif ($event->page_matches("wiki_admin/delete_all")) { @@ -170,7 +170,7 @@ class Wiki extends Extension ["title"=>$_POST["title"]] ); $u_title = url_escape($_POST["title"]); - $page->set_mode("redirect"); + $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("wiki/$u_title")); } } @@ -213,7 +213,7 @@ class Wiki extends Extension return false; } - private function get_page(string $title): WikiPage + private function get_page(string $title, int $revision=-1): WikiPage { global $database; // first try and get the actual page @@ -222,21 +222,17 @@ class Wiki extends Extension SELECT * FROM wiki_pages WHERE SCORE_STRNORM(title) LIKE SCORE_STRNORM(:title) - ORDER BY revision DESC - LIMIT 1 - "), + ORDER BY revision DESC"), ["title"=>$title] ); // fall back to wiki:default if (empty($row)) { $row = $database->get_row(" - SELECT * - FROM wiki_pages - WHERE title LIKE :title - ORDER BY revision DESC - LIMIT 1 - ", ["title"=>"wiki:default"]); + SELECT * + FROM wiki_pages + WHERE title LIKE :title + ORDER BY revision DESC", ["title"=>"wiki:default"]); // fall further back to manual if (empty($row)) { diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 28539364..e2bcb800 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -52,7 +52,7 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase $_POST = []; $page = class_exists("CustomPage") ? new CustomPage() : new Page(); send_event(new PageRequestEvent($page_name)); - if ($page->mode == "redirect") { + if ($page->mode == PageMode::REDIRECT) { $page->code = 302; } } @@ -68,7 +68,7 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase $_POST = $args; $page = class_exists("CustomPage") ? new CustomPage() : new Page(); send_event(new PageRequestEvent($page_name)); - if ($page->mode == "redirect") { + if ($page->mode == PageMode::REDIRECT) { $page->code = 302; } } diff --git a/themes/material/home.theme.php b/themes/material/home.theme.php index 68b700e1..ada70b17 100644 --- a/themes/material/home.theme.php +++ b/themes/material/home.theme.php @@ -4,7 +4,7 @@ class CustomHomeTheme extends HomeTheme { public function display_page(Page $page, $sitename, $base_href, $theme_name, $body) { - $page->set_mode("data"); + $page->set_mode(PageMode::DATA); $page->add_auto_html_headers(); $hh = $page->get_all_html_headers(); $page->set_data( From 5a30ce1c83a14fd2354971672ce3d1e4751ad49d Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 19 Jun 2019 18:59:18 -0500 Subject: [PATCH 024/133] Reverted removal of latter tag write --- ext/cron_uploader/main.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index 977a4f7a..a6130e3b 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -64,10 +64,10 @@ class CronUploader extends Extension $this->set_dir(); $lockfile = fopen($this->root_dir . "/.lock", "w"); + if (!flock($lockfile, LOCK_EX | LOCK_NB)) { + throw new Exception("Cron upload process is already running"); + } try { - if (!flock($lockfile, LOCK_EX | LOCK_NB)) { - throw new Exception("Cron upload process is already running"); - } $this->process_upload(); // Start upload } finally { flock($lockfile, LOCK_UN); @@ -301,6 +301,7 @@ class CronUploader extends Extension try { $database->beginTransaction(); + $this->add_upload_info("Adding file: {$img[1]} - tags: {$img[2]}"); $result = $this->add_image($img[0], $img[1], $img[2]); $database->commit(); $this->move_uploaded($img[0], $img[1], $output_subdir, false); @@ -378,7 +379,7 @@ class CronUploader extends Extension if (array_key_exists('extension', $pathinfo)) { $metadata ['extension'] = $pathinfo ['extension']; } - $metadata ['tags'] = Tag::explode($tags); + $metadata ['tags'] = Tag::explode($tags); // doesn't work when not logged in here, handled below $metadata ['source'] = null; $event = new DataUploadEvent($tmpname, $metadata); send_event($event); @@ -393,6 +394,13 @@ class CronUploader extends Extension $infomsg = "Image uploaded. ID: {$event->image_id} - Filename: {$filename}"; } $msgNumber = $this->add_upload_info($infomsg); + + // Set tags + $img = Image::by_id($event->image_id); + if(count($img->get_tag_array())==0) { + $img->set_tags(Tag::explode($tags)); + } + return $event->image_id; } From 5eb4a66ab7c19abb2fceb39d718f13aae89f6320 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 19 Jun 2019 19:40:25 -0500 Subject: [PATCH 025/133] Added merged indicator to DataUploadEvent and ImageAddEvent Changed merge process so that the ID of the merged image can make it back through the event chanin --- core/extension.php | 1 + core/imageboard/event.php | 2 ++ ext/cron_uploader/main.php | 4 ++-- ext/handle_svg/main.php | 1 + ext/image/main.php | 10 +++++++--- ext/resize/main.php | 4 ---- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/core/extension.php b/core/extension.php index d691bd68..5c8c61fa 100644 --- a/core/extension.php +++ b/core/extension.php @@ -199,6 +199,7 @@ abstract class DataHandlerExtension extends Extension $iae = new ImageAdditionEvent($image); send_event($iae); $event->image_id = $iae->image->id; + $event->merged = $iae->merged; // Rating Stuff. if (!empty($event->metadata['rating'])) { diff --git a/core/imageboard/event.php b/core/imageboard/event.php index 2fc40fef..ec663d6b 100644 --- a/core/imageboard/event.php +++ b/core/imageboard/event.php @@ -11,6 +11,8 @@ class ImageAdditionEvent extends Event /** @var Image */ public $image; + public $merged = false; + /** * Inserts a new image into the database with its associated * information. Also calls TagSetEvent to set the tags for diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index a6130e3b..3a6d5e42 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -388,8 +388,8 @@ class CronUploader extends Extension $infomsg = ""; // Will contain info message if ($event->image_id == -1) { throw new Exception("File type not recognised. Filename: {$filename}"); - } elseif ($event->image_id == null) { - $infomsg = "Image merged. Filename: {$filename}"; + } elseif ($event->merged === true) { + $infomsg = "Image merged. ID: {$event->image_id} Filename: {$filename}"; } else { $infomsg = "Image uploaded. ID: {$event->image_id} - Filename: {$filename}"; } diff --git a/ext/handle_svg/main.php b/ext/handle_svg/main.php index 96dea29a..9998a245 100644 --- a/ext/handle_svg/main.php +++ b/ext/handle_svg/main.php @@ -29,6 +29,7 @@ class SVGFileHandler extends DataHandlerExtension $iae = new ImageAdditionEvent($image); send_event($iae); $event->image_id = $iae->image->id; + $event->merged = $iae->merged; } } diff --git a/ext/image/main.php b/ext/image/main.php index f9b31180..3fc63325 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -88,7 +88,7 @@ class ImageIO extends Extension public function onImageAddition(ImageAdditionEvent $event) { try { - $this->add_image($event->image); + $this->add_image($event); } catch (ImageAdditionException $e) { throw new UploadException($e->error); } @@ -175,10 +175,12 @@ class ImageIO extends Extension // add image {{{ - private function add_image(Image $image) + private function add_image(ImageAdditionEvent $event) { global $user, $database, $config; + $image = $event->image; + /* * Validate things */ @@ -201,7 +203,9 @@ class ImageIO extends Extension if (isset($_GET['source']) && isset($_GET['update'])) { send_event(new SourceSetEvent($existing, $_GET['source'])); } - return null; + $event->merged = true; + $event->image = Image::by_id($existing->id); + return; } else { $error = "Image {$existing->id} ". "already has hash {$image->hash}:

".$this->theme->build_thumb_html($existing); diff --git a/ext/resize/main.php b/ext/resize/main.php index 785fcc31..a998814e 100644 --- a/ext/resize/main.php +++ b/ext/resize/main.php @@ -65,10 +65,6 @@ class ResizeImage extends Extension { global $config, $page; - if($event->image_id==null) { - return; - } - $image_obj = Image::by_id($event->image_id); if ($config->get_bool("resize_upload") == true From 921ec9a7bbff82573613a9586f965ca7765e6ac0 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 19 Jun 2019 20:14:19 -0500 Subject: [PATCH 026/133] Adjusted cron upload for new merged flag, and to make sure tags merge properly --- ext/cron_uploader/main.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index 3a6d5e42..560a15a3 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -305,7 +305,7 @@ class CronUploader extends Extension $result = $this->add_image($img[0], $img[1], $img[2]); $database->commit(); $this->move_uploaded($img[0], $img[1], $output_subdir, false); - if ($result == null) { + if ($result->merged) { $merged++; } else { $added++; @@ -369,17 +369,22 @@ class CronUploader extends Extension /** * Generate the necessary DataUploadEvent for a given image and tags. */ - private function add_image(string $tmpname, string $filename, string $tags) + private function add_image(string $tmpname, string $filename, string $tags): DataUploadEvent { assert(file_exists($tmpname)); + $tagArray = Tag::explode($tags); + if(count($tagArray)==0) { + $tagArray[] = "tagme"; + } + $pathinfo = pathinfo($filename); $metadata = []; $metadata ['filename'] = $pathinfo ['basename']; if (array_key_exists('extension', $pathinfo)) { $metadata ['extension'] = $pathinfo ['extension']; } - $metadata ['tags'] = Tag::explode($tags); // doesn't work when not logged in here, handled below + $metadata ['tags'] = $tagArray; // doesn't work when not logged in here, handled below $metadata ['source'] = null; $event = new DataUploadEvent($tmpname, $metadata); send_event($event); @@ -397,11 +402,9 @@ class CronUploader extends Extension // Set tags $img = Image::by_id($event->image_id); - if(count($img->get_tag_array())==0) { - $img->set_tags(Tag::explode($tags)); - } + $img->set_tags(array_merge($tagArray, $img->get_tag_array())); - return $event->image_id; + return $event; } private function generate_image_queue(): void From c951f7d13e18f3ae8bb21d95757a62331a2234e4 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 19 Jun 2019 19:35:45 -0500 Subject: [PATCH 027/133] Adjusted path-to-dir regex to prevent an error --- core/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/util.php b/core/util.php index 57c7577e..3c1ef7e1 100644 --- a/core/util.php +++ b/core/util.php @@ -282,7 +282,7 @@ function path_to_tags(string $path): string { $matches = []; $tags = []; - if(preg_match("/\d+ - (.*)\.([a-zA-Z0-9]+)/", basename($path), $matches)) { + if(preg_match("/\d+ - (.+)\.([a-zA-Z0-9]+)/", basename($path), $matches)) { $tags = explode($matches[1]," "); } From a2ac9776ff30c0468947715a6f702f4058168704 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 19 Jun 2019 23:26:30 -0500 Subject: [PATCH 028/133] path tag corrections --- core/util.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/util.php b/core/util.php index 3c1ef7e1..566474df 100644 --- a/core/util.php +++ b/core/util.php @@ -283,9 +283,9 @@ function path_to_tags(string $path): string $matches = []; $tags = []; if(preg_match("/\d+ - (.+)\.([a-zA-Z0-9]+)/", basename($path), $matches)) { - $tags = explode($matches[1]," "); + $tags = explode(" ",$matches[1]); } - + $path = dirname($path); $path = str_replace(";", ":", $path); $path = str_replace("__", " ", $path); @@ -310,7 +310,7 @@ function path_to_tags(string $path): string // So we attach the inherited category to the tag. $tag = $category.$tag; } - array_push($tags, $tag); + $tags[] = $tag; } } // Category inheritance only works on the immediate subfolder, @@ -318,6 +318,7 @@ function path_to_tags(string $path): string // it back to an empty string after that iteration $category = $category_to_inherit; } + return implode(" ",$tags); } From a834d1f81459b7c3ed624efd0ba9339289886e35 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 19 Jun 2019 23:37:33 -0500 Subject: [PATCH 029/133] Resolved issue with bulk rater --- ext/rating/main.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/rating/main.php b/ext/rating/main.php index 794129e4..99f2b218 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -170,7 +170,7 @@ class Ratings extends Extension global $user; if ($user->is_admin()) { - $event->add_action("bulk_rate", "Set Rating", "", $this->theme->get_selection_rater_html("bulk_rating")); + $event->add_action("bulk_rate","Set Rating","",$this->theme->get_selection_rater_html("u","bulk_rating")); } } @@ -191,7 +191,7 @@ class Ratings extends Extension if ($image==null) { continue; } - + send_event(new RatingSetEvent($image, $rating)); $total++; } From d128dfa78ec25d216e6d17d53e74da88e3ede9fe Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Thu, 20 Jun 2019 10:05:53 -0500 Subject: [PATCH 030/133] Added lower indexes for postgresql to tags.tag and users.name to speed up queries for them using lower() --- ext/upgrade/main.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index 0aef4530..42522ad9 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -129,6 +129,20 @@ class Upgrade extends Extension log_info("upgrade", "Database at version 14"); $config->set_bool("in_upgrade", false); } + + if ($config->get_int("db_version") < 15) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 15); + + log_info("upgrade", "Adding lower indexes for postgresql use"); + if ($database->get_driver_name() == Database::PGSQL_DRIVER) { + $database->execute('CREATE INDEX tags_lower_tag_idx ON tags ((lower(tag)))'); + $database->execute('CREATE INDEX users_lower_name_idx ON users ((lower(name)))'); + } + + log_info("upgrade", "Database at version 15"); + $config->set_bool("in_upgrade", false); + } } public function get_priority(): int From 1370afec72c3418f9d024c13ebb0f78707f04776 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Thu, 20 Jun 2019 10:42:32 -0500 Subject: [PATCH 031/133] Moved database driver constants to DatabaseDriver --- core/_install.php | 14 +++++++------- core/database.php | 28 ++++++++++++++++------------ core/dbengine.php | 6 +++--- core/imageboard/image.php | 4 ++-- core/user.php | 2 +- ext/admin/main.php | 12 ++++++------ ext/admin/theme.php | 2 +- ext/comment/main.php | 4 ++-- ext/index/test.php | 2 +- ext/ipban/main.php | 2 +- ext/ipban/theme.php | 2 +- ext/log_db/main.php | 2 +- ext/rating/main.php | 6 +++--- ext/relatationships/main.php | 2 +- ext/rss_comments/main.php | 2 +- ext/rule34/main.php | 2 +- ext/rule34/theme.php | 2 +- ext/tips/main.php | 2 +- ext/upgrade/main.php | 14 +++++++------- 19 files changed, 57 insertions(+), 53 deletions(-) diff --git a/core/_install.php b/core/_install.php index 99fa864d..a695c237 100644 --- a/core/_install.php +++ b/core/_install.php @@ -110,7 +110,7 @@ function do_install() { // {{{ if (file_exists("data/config/auto_install.conf.php")) { require_once "data/config/auto_install.conf.php"; - } elseif (@$_POST["database_type"] == Database::SQLITE_DRIVER) { + } elseif (@$_POST["database_type"] == DatabaseDriver::SQLITE) { $id = bin2hex(random_bytes(5)); define('DATABASE_DSN', "sqlite:data/shimmie.{$id}.sqlite"); } elseif (isset($_POST['database_type']) && isset($_POST['database_host']) && isset($_POST['database_user']) && isset($_POST['database_name'])) { @@ -153,9 +153,9 @@ function ask_questions() $drivers = PDO::getAvailableDrivers(); if ( - !in_array(Database::MYSQL_DRIVER, $drivers) && - !in_array(Database::PGSQL_DRIVER, $drivers) && - !in_array(Database::SQLITE_DRIVER, $drivers) + !in_array(DatabaseDriver::MYSQL, $drivers) && + !in_array(DatabaseDriver::PGSQL, $drivers) && + !in_array(DatabaseDriver::SQLITE, $drivers) ) { $errors[] = " No database connection library could be found; shimmie needs @@ -163,9 +163,9 @@ function ask_questions() "; } - $db_m = in_array(Database::MYSQL_DRIVER, $drivers) ? '' : ""; - $db_p = in_array(Database::PGSQL_DRIVER, $drivers) ? '' : ""; - $db_s = in_array(Database::SQLITE_DRIVER, $drivers) ? '' : ""; + $db_m = in_array(DatabaseDriver::MYSQL, $drivers) ? '' : ""; + $db_p = in_array(DatabaseDriver::PGSQL, $drivers) ? '' : ""; + $db_s = in_array(DatabaseDriver::SQLITE, $drivers) ? '' : ""; $warn_msg = $warnings ? "

Warnings

".implode("\n

", $warnings) : ""; $err_msg = $errors ? "

Errors

".implode("\n

", $errors) : ""; diff --git a/core/database.php b/core/database.php index 29381209..65405211 100644 --- a/core/database.php +++ b/core/database.php @@ -1,12 +1,16 @@ get_driver_name() == self::SQLITE_DRIVER) { + if (version_compare(PHP_VERSION, "6.9.9") == 1 && $this->get_driver_name() == DatabaseDriver::SQLITE) { $ka = false; } @@ -100,11 +104,11 @@ class Database throw new SCoreException("Can't figure out database engine"); } - if ($db_proto === self::MYSQL_DRIVER) { + if ($db_proto === DatabaseDriver::MYSQL) { $this->engine = new MySQL(); - } elseif ($db_proto === self::PGSQL_DRIVER) { + } elseif ($db_proto === DatabaseDriver::PGSQL) { $this->engine = new PostgreSQL(); - } elseif ($db_proto === self::SQLITE_DRIVER) { + } elseif ($db_proto === DatabaseDriver::SQLITE) { $this->engine = new SQLite(); } else { die('Unknown PDO driver: '.$db_proto); @@ -228,7 +232,7 @@ class Database } return $stmt; } catch (PDOException $pdoe) { - throw new SCoreException($pdoe->getMessage()."

Query: ".$query, $pdoe->getCode(), $pdoe); + throw new SCoreException($pdoe->getMessage()."

Query: ".$query); } } @@ -300,7 +304,7 @@ class Database */ public function get_last_insert_id(string $seq): int { - if ($this->engine->name == self::PGSQL_DRIVER) { + if ($this->engine->name == DatabaseDriver::PGSQL) { return $this->db->lastInsertId($seq); } else { return $this->db->lastInsertId(); @@ -330,15 +334,15 @@ class Database $this->connect_db(); } - if ($this->engine->name === self::MYSQL_DRIVER) { + if ($this->engine->name === DatabaseDriver::MYSQL) { return count( $this->get_all("SHOW TABLES") ); - } elseif ($this->engine->name === self::PGSQL_DRIVER) { + } elseif ($this->engine->name === DatabaseDriver::PGSQL) { return count( $this->get_all("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'") ); - } elseif ($this->engine->name === self::SQLITE_DRIVER) { + } elseif ($this->engine->name === DatabaseDriver::SQLITE) { return count( $this->get_all("SELECT name FROM sqlite_master WHERE type = 'table'") ); diff --git a/core/dbengine.php b/core/dbengine.php index d76a1a43..404adad9 100644 --- a/core/dbengine.php +++ b/core/dbengine.php @@ -22,7 +22,7 @@ class DBEngine class MySQL extends DBEngine { /** @var string */ - public $name = Database::MYSQL_DRIVER; + public $name = DatabaseDriver::MYSQL; public function init(PDO $db) { @@ -54,7 +54,7 @@ class MySQL extends DBEngine class PostgreSQL extends DBEngine { /** @var string */ - public $name = Database::PGSQL_DRIVER; + public $name = DatabaseDriver::PGSQL; public function init(PDO $db) { @@ -136,7 +136,7 @@ function _ln($n) class SQLite extends DBEngine { /** @var string */ - public $name = Database::SQLITE_DRIVER; + public $name = DatabaseDriver::SQLITE; public function init(PDO $db) { diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 72364d3a..2f224c8b 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -644,7 +644,7 @@ class Image public function delete_tags_from_image(): void { global $database; - if ($database->get_driver_name() == Database::MYSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::MYSQL) { //mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this $database->execute( " @@ -921,7 +921,7 @@ class Image // more than one positive tag, or more than zero negative tags else { - if ($database->get_driver_name() === Database::MYSQL_DRIVER) { + if ($database->get_driver_name() === DatabaseDriver::MYSQL) { $query = Image::build_ugly_search_querylet($tag_conditions); } else { $query = Image::build_accurate_search_querylet($tag_conditions); diff --git a/core/user.php b/core/user.php index a2a4d537..05f6e7f7 100644 --- a/core/user.php +++ b/core/user.php @@ -69,7 +69,7 @@ class User global $config, $database; $row = $database->cache->get("user-session:$name-$session"); if (!$row) { - if ($database->get_driver_name() === Database::MYSQL_DRIVER) { + if ($database->get_driver_name() === DatabaseDriver::MYSQL) { $query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess"; } else { $query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess"; diff --git a/ext/admin/main.php b/ext/admin/main.php index c9d2feff..c6c7f33f 100644 --- a/ext/admin/main.php +++ b/ext/admin/main.php @@ -201,14 +201,14 @@ class AdminPage extends Extension $database = $matches['dbname']; switch ($software) { - case Database::MYSQL_DRIVER: + case DatabaseDriver::MYSQL: $cmd = "mysqldump -h$hostname -u$username -p$password $database"; break; - case Database::PGSQL_DRIVER: + case DatabaseDriver::PGSQL: putenv("PGPASSWORD=$password"); $cmd = "pg_dump -h $hostname -U $username $database"; break; - case Database::SQLITE_DRIVER: + case DatabaseDriver::SQLITE: $cmd = "sqlite3 $database .dump"; break; default: @@ -257,7 +257,7 @@ class AdminPage extends Extension //TODO: Update score_log (Having an optional ID column for score_log would be nice..) preg_match("#^(?P\w+)\:(?:user=(?P\w+)(?:;|$)|password=(?P\w*)(?:;|$)|host=(?P[\w\.\-]+)(?:;|$)|dbname=(?P[\w_]+)(?:;|$))+#", DATABASE_DSN, $matches); - if ($matches['proto'] == Database::MYSQL_DRIVER) { + if ($matches['proto'] == DatabaseDriver::MYSQL) { $tables = $database->get_col("SELECT TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = :db @@ -280,9 +280,9 @@ class AdminPage extends Extension $i++; } $database->execute("ALTER TABLE images AUTO_INCREMENT=".(count($ids) + 1)); - } elseif ($matches['proto'] == Database::PGSQL_DRIVER) { + } elseif ($matches['proto'] == DatabaseDriver::PGSQL) { //TODO: Make this work with PostgreSQL - } elseif ($matches['proto'] == Database::SQLITE_DRIVER) { + } elseif ($matches['proto'] == DatabaseDriver::SQLITE) { //TODO: Make this work with SQLite } return true; diff --git a/ext/admin/theme.php b/ext/admin/theme.php index 5d3de30f..64191067 100644 --- a/ext/admin/theme.php +++ b/ext/admin/theme.php @@ -45,7 +45,7 @@ class AdminPageTheme extends Themelet $html .= $this->button("Download all images", "download_all_images", false); } $html .= $this->button("Download database contents", "database_dump", false); - if ($database->get_driver_name() == Database::MYSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::MYSQL) { $html .= $this->button("Reset image IDs", "reset_image_ids", true); } $page->add_block(new Block("Misc Admin Tools", $html)); diff --git a/ext/comment/main.php b/ext/comment/main.php index d4cef828..1dfdc03b 100644 --- a/ext/comment/main.php +++ b/ext/comment/main.php @@ -480,14 +480,14 @@ class CommentList extends Extension global $config, $database; // sqlite fails at intervals - if ($database->get_driver_name() === Database::SQLITE_DRIVER) { + if ($database->get_driver_name() === DatabaseDriver::SQLITE) { return false; } $window = int_escape($config->get_int('comment_window')); $max = int_escape($config->get_int('comment_limit')); - if ($database->get_driver_name() == Database::MYSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::MYSQL) { $window_sql = "interval $window minute"; } else { $window_sql = "interval '$window minute'"; diff --git a/ext/index/test.php b/ext/index/test.php index 8f57bdb2..5d54fd42 100644 --- a/ext/index/test.php +++ b/ext/index/test.php @@ -157,7 +157,7 @@ class IndexTest extends ShimmiePHPUnitTestCase global $database; $db = $database->get_driver_name(); - if ($db == Database::PGSQL_DRIVER || $db == Database::SQLITE_DRIVER) { + if ($db == DatabaseDriver::PGSQL || $db == DatabaseDriver::SQLITE) { $this->markTestIncomplete(); } diff --git a/ext/ipban/main.php b/ext/ipban/main.php index f86c10ff..d6feb092 100644 --- a/ext/ipban/main.php +++ b/ext/ipban/main.php @@ -235,7 +235,7 @@ class IPBan extends Extension { global $config, $database; - $prefix = ($database->get_driver_name() == Database::SQLITE_DRIVER ? "bans." : ""); + $prefix = ($database->get_driver_name() == DatabaseDriver::SQLITE ? "bans." : ""); $bans = $this->get_active_bans(); diff --git a/ext/ipban/theme.php b/ext/ipban/theme.php index 67979128..0373c94d 100644 --- a/ext/ipban/theme.php +++ b/ext/ipban/theme.php @@ -16,7 +16,7 @@ class IPBanTheme extends Themelet { global $database, $user; $h_bans = ""; - $prefix = ($database->get_driver_name() == Database::SQLITE_DRIVER ? "bans." : ""); + $prefix = ($database->get_driver_name() == DatabaseDriver::SQLITE ? "bans." : ""); foreach ($bans as $ban) { $end_human = date('Y-m-d', $ban[$prefix.'end_timestamp']); $h_bans .= " diff --git a/ext/log_db/main.php b/ext/log_db/main.php index 5b400b12..2f1d761a 100644 --- a/ext/log_db/main.php +++ b/ext/log_db/main.php @@ -68,7 +68,7 @@ class LogDatabase extends Extension $args["module"] = $_GET["module"]; } if (!empty($_GET["user"])) { - if ($database->get_driver_name() == Database::PGSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::PGSQL) { if (preg_match("#\d+\.\d+\.\d+\.\d+(/\d+)?#", $_GET["user"])) { $wheres[] = "(username = :user1 OR text(address) = :user2)"; $args["user1"] = $_GET["user"]; diff --git a/ext/rating/main.php b/ext/rating/main.php index 99f2b218..a5e173a1 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -37,7 +37,7 @@ class RatingSetEvent extends Event class Ratings extends Extension { - protected $db_support = [Database::MYSQL_DRIVER,Database::PGSQL_DRIVER]; + protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL]; public function get_priority(): int { @@ -331,10 +331,10 @@ class Ratings extends Extension if ($config->get_int("ext_ratings2_version") < 3) { $database->Execute("UPDATE images SET rating = 'u' WHERE rating is null"); switch ($database->get_driver_name()) { - case Database::MYSQL_DRIVER: + case DatabaseDriver::MYSQL: $database->Execute("ALTER TABLE images CHANGE rating rating CHAR(1) NOT NULL DEFAULT 'u'"); break; - case Database::PGSQL_DRIVER: + case DatabaseDriver::PGSQL: $database->Execute("ALTER TABLE images ALTER COLUMN rating SET DEFAULT 'u'"); $database->Execute("ALTER TABLE images ALTER COLUMN rating SET NOT NULL"); break; diff --git a/ext/relatationships/main.php b/ext/relatationships/main.php index 402f4fd0..5304e3a5 100644 --- a/ext/relatationships/main.php +++ b/ext/relatationships/main.php @@ -8,7 +8,7 @@ class Relationships extends Extension { - protected $db_support = [Database::MYSQL_DRIVER, Database::PGSQL_DRIVER]; + protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL]; public function onInitExt(InitExtEvent $event) { diff --git a/ext/rss_comments/main.php b/ext/rss_comments/main.php index 012bca93..b00f92aa 100644 --- a/ext/rss_comments/main.php +++ b/ext/rss_comments/main.php @@ -9,7 +9,7 @@ class RSS_Comments extends Extension { - protected $db_support = [Database::MYSQL_DRIVER, Database::SQLITE_DRIVER]; // pgsql has no UNIX_TIMESTAMP + protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::SQLITE]; // pgsql has no UNIX_TIMESTAMP public function onPostListBuilding(PostListBuildingEvent $event) { diff --git a/ext/rule34/main.php b/ext/rule34/main.php index 4dc2a241..529e6201 100644 --- a/ext/rule34/main.php +++ b/ext/rule34/main.php @@ -19,7 +19,7 @@ if ( // kill these glitched requests immediately class Rule34 extends Extension { - protected $db_support = [Database::PGSQL_DRIVER]; # Only PG has the NOTIFY pubsub system + protected $db_support = [DatabaseDriver::PGSQL]; # Only PG has the NOTIFY pubsub system public function onImageDeletion(ImageDeletionEvent $event) { diff --git a/ext/rule34/theme.php b/ext/rule34/theme.php index d4dd29e1..f71d8c15 100644 --- a/ext/rule34/theme.php +++ b/ext/rule34/theme.php @@ -19,7 +19,7 @@ class Rule34Theme extends Themelet { global $database, $user; $h_bans = ""; - $prefix = ($database->get_driver_name() == Database::SQLITE_DRIVER ? "bans." : ""); + $prefix = ($database->get_driver_name() == DatabaseDriver::SQLITE ? "bans." : ""); foreach ($bans as $ban) { $h_bans .= "

diff --git a/ext/tips/main.php b/ext/tips/main.php index 5fd54e0d..7e5610a6 100644 --- a/ext/tips/main.php +++ b/ext/tips/main.php @@ -10,7 +10,7 @@ class Tips extends Extension { - protected $db_support = [Database::MYSQL_DRIVER, Database::SQLITE_DRIVER]; // rand() ? + protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::SQLITE]; // rand() ? public function onInitExt(InitExtEvent $event) { diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index 42522ad9..160422b5 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -44,7 +44,7 @@ class Upgrade extends Extension $config->set_bool("in_upgrade", true); $config->set_int("db_version", 9); - if ($database->get_driver_name() == Database::MYSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::MYSQL) { $tables = $database->get_col("SHOW TABLES"); foreach ($tables as $table) { log_info("upgrade", "converting $table to innodb"); @@ -84,7 +84,7 @@ class Upgrade extends Extension $config->set_bool("in_upgrade", true); $config->set_int("db_version", 12); - if ($database->get_driver_name() == Database::PGSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::PGSQL) { log_info("upgrade", "Changing ext column to VARCHAR"); $database->execute("ALTER TABLE images ALTER COLUMN ext SET DATA TYPE VARCHAR(4)"); } @@ -101,9 +101,9 @@ class Upgrade extends Extension $config->set_int("db_version", 13); log_info("upgrade", "Changing password column to VARCHAR(250)"); - if ($database->get_driver_name() == Database::PGSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::PGSQL) { $database->execute("ALTER TABLE users ALTER COLUMN pass SET DATA TYPE VARCHAR(250)"); - } elseif ($database->get_driver_name() == Database::MYSQL_DRIVER) { + } elseif ($database->get_driver_name() == DatabaseDriver::MYSQL) { $database->execute("ALTER TABLE users CHANGE pass pass VARCHAR(250)"); } @@ -116,11 +116,11 @@ class Upgrade extends Extension $config->set_int("db_version", 14); log_info("upgrade", "Changing tag column to VARCHAR(255)"); - if ($database->get_driver_name() == Database::PGSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::PGSQL) { $database->execute('ALTER TABLE tags ALTER COLUMN tag SET DATA TYPE VARCHAR(255)'); $database->execute('ALTER TABLE aliases ALTER COLUMN oldtag SET DATA TYPE VARCHAR(255)'); $database->execute('ALTER TABLE aliases ALTER COLUMN newtag SET DATA TYPE VARCHAR(255)'); - } elseif ($database->get_driver_name() == Database::MYSQL_DRIVER) { + } elseif ($database->get_driver_name() == DatabaseDriver::MYSQL) { $database->execute('ALTER TABLE tags MODIFY COLUMN tag VARCHAR(255) NOT NULL'); $database->execute('ALTER TABLE aliases MODIFY COLUMN oldtag VARCHAR(255) NOT NULL'); $database->execute('ALTER TABLE aliases MODIFY COLUMN newtag VARCHAR(255) NOT NULL'); @@ -135,7 +135,7 @@ class Upgrade extends Extension $config->set_int("db_version", 15); log_info("upgrade", "Adding lower indexes for postgresql use"); - if ($database->get_driver_name() == Database::PGSQL_DRIVER) { + if ($database->get_driver_name() == DatabaseDriver::PGSQL) { $database->execute('CREATE INDEX tags_lower_tag_idx ON tags ((lower(tag)))'); $database->execute('CREATE INDEX users_lower_name_idx ON users ((lower(name)))'); } From c24a6e9b978b0137bd96a9101ad8bdc47fd9f303 Mon Sep 17 00:00:00 2001 From: Shish Date: Fri, 21 Jun 2019 09:12:44 +0100 Subject: [PATCH 032/133] formatting pass --- core/imageboard/misc.php | 13 +++++++------ core/page.php | 3 ++- core/util.php | 26 +++++++++++++------------- ext/cron_uploader/main.php | 3 +-- ext/ext_manager/main.php | 2 -- ext/ext_manager/theme.php | 1 - ext/rating/main.php | 2 +- 7 files changed, 24 insertions(+), 26 deletions(-) diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index d08daf2b..865a1c65 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -125,7 +125,7 @@ function get_thumbnail_size(int $orig_width, int $orig_height, bool $use_dpi_sca } - if($use_dpi_scaling) { + if ($use_dpi_scaling) { $max_size = get_thumbnail_max_size_scaled(); $max_width = $max_size[0]; $max_height = $max_size[1]; @@ -201,15 +201,15 @@ function create_thumbnail_convert($hash, $input_type = ""): bool if ($type=="webp") { $bg = "none"; } - if(!empty($input_type)) { + if (!empty($input_type)) { $input_type = $input_type.":"; } $format = '"%s" -flatten -strip -thumbnail %ux%u%s -quality %u -background %s %s"%s[0]" %s:"%s" 2>&1'; - $cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg,$input_type, $inname, $type, $outname); + $cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg, $input_type, $inname, $type, $outname); $cmd = str_replace("\"convert\"", "convert", $cmd); // quotes are only needed if the path to convert contains a space; some other times, quotes break things, see github bug #27 exec($cmd, $output, $ret); if ($ret!=0) { - log_warning('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret, outputting ".implode("\r\n",$output)); + log_warning('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret, outputting ".implode("\r\n", $output)); } else { log_debug('imageboard/misc', "Generating thumbnail with command `$cmd`, returns $ret"); } @@ -489,7 +489,8 @@ function image_resize_gd( * @param String $image_filename The path of the file to check. * @return bool true if the file is an animated gif, false if it is not. */ -function is_animated_gif(String $image_filename) { +function is_animated_gif(String $image_filename) +{ $is_anim_gif = 0; if (($fh = @fopen($image_filename, 'rb'))) { //check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) @@ -499,4 +500,4 @@ function is_animated_gif(String $image_filename) { } } return ($is_anim_gif == 0); -} \ No newline at end of file +} diff --git a/core/page.php b/core/page.php index 998adc7d..12189999 100644 --- a/core/page.php +++ b/core/page.php @@ -26,7 +26,8 @@ * Various other common functions are available as part of the Themelet class. */ -abstract class PageMode { +abstract class PageMode +{ const REDIRECT = 'redirect'; const DATA = 'data'; const PAGE = 'page'; diff --git a/core/util.php b/core/util.php index ca50a728..b16dbb8e 100644 --- a/core/util.php +++ b/core/util.php @@ -284,30 +284,30 @@ function manual_include(string $fname): ?string function path_to_tags(string $path): string { $matches = []; - $tags = []; - if(preg_match("/\d+ - (.+)\.([a-zA-Z0-9]+)/", basename($path), $matches)) { - $tags = explode(" ",$matches[1]); - } + $tags = []; + if (preg_match("/\d+ - (.+)\.([a-zA-Z0-9]+)/", basename($path), $matches)) { + $tags = explode(" ", $matches[1]); + } - $path = dirname($path); + $path = dirname($path); $path = str_replace(";", ":", $path); - $path = str_replace("__", " ", $path); + $path = str_replace("__", " ", $path); $category = ""; - foreach(explode("/", $path) as $dir) { + foreach (explode("/", $path) as $dir) { $category_to_inherit = ""; - foreach(explode(" ", $dir) as $tag) { + foreach (explode(" ", $dir) as $tag) { $tag = trim($tag); - if($tag=="") { + if ($tag=="") { continue; } - if(substr_compare($tag, ":", -1) === 0) { + if (substr_compare($tag, ":", -1) === 0) { // This indicates a tag that ends in a colon, // which is for inheriting to tags on the subfolder $category_to_inherit = $tag; } else { - if($category!=""&&strpos($tag, ":") === false) { + if ($category!=""&&strpos($tag, ":") === false) { // This indicates that category inheritance is active, // and we've encountered a tag that does not specify a category. // So we attach the inherited category to the tag. @@ -316,13 +316,13 @@ function path_to_tags(string $path): string $tags[] = $tag; } } - // Category inheritance only works on the immediate subfolder, + // Category inheritance only works on the immediate subfolder, // so we hold a category until the next iteration, and then set // it back to an empty string after that iteration $category = $category_to_inherit; } - return implode(" ",$tags); + return implode(" ", $tags); } diff --git a/ext/cron_uploader/main.php b/ext/cron_uploader/main.php index 560a15a3..99ed9697 100644 --- a/ext/cron_uploader/main.php +++ b/ext/cron_uploader/main.php @@ -333,7 +333,6 @@ class CronUploader extends Extension $this->handle_log(); return true; - } private function move_uploaded($path, $filename, $output_subdir, $corrupt = false) @@ -374,7 +373,7 @@ class CronUploader extends Extension assert(file_exists($tmpname)); $tagArray = Tag::explode($tags); - if(count($tagArray)==0) { + if (count($tagArray)==0) { $tagArray[] = "tagme"; } diff --git a/ext/ext_manager/main.php b/ext/ext_manager/main.php index b41b53dd..07bad29c 100644 --- a/ext/ext_manager/main.php +++ b/ext/ext_manager/main.php @@ -62,8 +62,6 @@ class ExtensionInfo $this->authors[] = new ExtensionAuthor($author, null); } } - - } elseif (preg_match("/(.*)Description: ?(.*)/", $line, $matches)) { $this->description = $matches[2]; $start = $matches[1] . " "; diff --git a/ext/ext_manager/theme.php b/ext/ext_manager/theme.php index 58bd79ab..9a326ffc 100644 --- a/ext/ext_manager/theme.php +++ b/ext/ext_manager/theme.php @@ -129,7 +129,6 @@ class ExtManagerTheme extends Themelet $author .= html_escape($auth->name); } } - } $version = ($info->version) ? "
Version: " . html_escape($info->version) : ""; diff --git a/ext/rating/main.php b/ext/rating/main.php index a5e173a1..092223f3 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -170,7 +170,7 @@ class Ratings extends Extension global $user; if ($user->is_admin()) { - $event->add_action("bulk_rate","Set Rating","",$this->theme->get_selection_rater_html("u","bulk_rating")); + $event->add_action("bulk_rate", "Set Rating", "", $this->theme->get_selection_rater_html("u", "bulk_rating")); } } From 97f8234778f08f3c52449fec1fad90d97ec5e421 Mon Sep 17 00:00:00 2001 From: Shish Date: Fri, 5 Jul 2019 15:47:47 +0100 Subject: [PATCH 033/133] bump phpunit to 7.x --- composer.json | 2 +- composer.lock | 527 ++++++++++++++++++++++++++------------------------ 2 files changed, 272 insertions(+), 257 deletions(-) diff --git a/composer.json b/composer.json index 114d990e..219f4b3b 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ }, "require-dev" : { - "phpunit/phpunit" : "6.*" + "phpunit/phpunit" : "7.*" }, "suggest": { diff --git a/composer.lock b/composer.lock index 2805f8e2..5fead0de 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fd0ccce172ded2999f5ced0884990541", + "content-hash": "b679340e0fc96ae78f8919db742d17da", "packages": [ { "name": "bower-asset/jquery", @@ -17,8 +17,7 @@ "dist": { "type": "zip", "url": "https://api.github.com/repos/jquery/jquery-dist/zipball/3a43d7e563314bf32970b773dd31ecf2b90813dd", - "reference": "3a43d7e563314bf32970b773dd31ecf2b90813dd", - "shasum": null + "reference": "3a43d7e563314bf32970b773dd31ecf2b90813dd" }, "type": "bower-asset", "license": [ @@ -36,8 +35,7 @@ "dist": { "type": "zip", "url": "https://api.github.com/repos/rmm5t/jquery-timeago/zipball/67c11951ae9b6020341c1056a42b5406162db40c", - "reference": "67c11951ae9b6020341c1056a42b5406162db40c", - "shasum": null + "reference": "67c11951ae9b6020341c1056a42b5406162db40c" }, "require": { "bower-asset/jquery": ">=1.4" @@ -58,8 +56,7 @@ "dist": { "type": "zip", "url": "https://api.github.com/repos/js-cookie/js-cookie/zipball/5c830fb71a2bd3acce9cb733d692e13316991891", - "reference": "5c830fb71a2bd3acce9cb733d692e13316991891", - "shasum": null + "reference": "5c830fb71a2bd3acce9cb733d692e13316991891" }, "type": "bower-asset", "license": [ @@ -77,8 +74,7 @@ "dist": { "type": "zip", "url": "https://api.github.com/repos/mediaelement/mediaelement/zipball/6e80b260172f4ddc3b0bbee046775d2ba4c6f9b7", - "reference": "6e80b260172f4ddc3b0bbee046775d2ba4c6f9b7", - "shasum": null + "reference": "6e80b260172f4ddc3b0bbee046775d2ba4c6f9b7" }, "type": "bower-asset", "license": [ @@ -96,8 +92,7 @@ "dist": { "type": "zip", "url": "https://api.github.com/repos/christianbach/tablesorter/zipball/07e0918254df3c2057d6d8e4653a0769f1881412", - "reference": "07e0918254df3c2057d6d8e4653a0769f1881412", - "shasum": null + "reference": "07e0918254df3c2057d6d8e4653a0769f1881412" }, "type": "bower-asset", "license": [ @@ -107,21 +102,21 @@ }, { "name": "dapphp/securimage", - "version": "3.6.6", + "version": "3.6.7", "source": { "type": "git", "url": "https://github.com/dapphp/securimage.git", - "reference": "6eea2798f56540fa88356c98f282d6391a72be15" + "reference": "1ecb884797c66e01a875c058def46c85aecea45b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dapphp/securimage/zipball/6eea2798f56540fa88356c98f282d6391a72be15", - "reference": "6eea2798f56540fa88356c98f282d6391a72be15", + "url": "https://api.github.com/repos/dapphp/securimage/zipball/1ecb884797c66e01a875c058def46c85aecea45b", + "reference": "1ecb884797c66e01a875c058def46c85aecea45b", "shasum": "" }, "require": { "ext-gd": "*", - "php": ">=5.2.0" + "php": ">=5.4" }, "suggest": { "ext-pdo": "For database storage support", @@ -136,7 +131,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "BSD-3-Clause" ], "authors": [ { @@ -147,10 +142,12 @@ "description": "PHP CAPTCHA Library", "homepage": "https://www.phpcaptcha.org", "keywords": [ + "Forms", + "anti-spam", "captcha", "security" ], - "time": "2017-11-21T02:29:19+00:00" + "time": "2018-03-09T06:07:41+00:00" }, { "name": "enshrined/svg-sanitize", @@ -248,24 +245,26 @@ "source": { "type": "git", "url": "https://github.com/google/recaptcha.git", - "reference": "6990961e664372ddbed7ebc1cd673da7077552e5" + "reference": "b1b674a50962a73e12125ad746f471c916478978" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/recaptcha/zipball/6990961e664372ddbed7ebc1cd673da7077552e5", - "reference": "6990961e664372ddbed7ebc1cd673da7077552e5", + "url": "https://api.github.com/repos/google/recaptcha/zipball/b1b674a50962a73e12125ad746f471c916478978", + "reference": "b1b674a50962a73e12125ad746f471c916478978", "shasum": "" }, "require": { "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.8" + "friendsofphp/php-cs-fixer": "^2.2.20|^2.15", + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^4.8.36|^5.7.27|^6.59|^7.5.11" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -277,15 +276,15 @@ "license": [ "BSD-3-Clause" ], - "description": "Client library for reCAPTCHA, a free service that protect websites from spam and abuse.", - "homepage": "http://www.google.com/recaptcha/", + "description": "Client library for reCAPTCHA, a free service that protects websites from spam and abuse.", + "homepage": "https://www.google.com/recaptcha/", "keywords": [ "Abuse", "captcha", "recaptcha", "spam" ], - "time": "2017-03-09T18:57:45+00:00" + "time": "2019-05-24T12:37:13+00:00" }, { "name": "ifixit/php-akismet", @@ -342,32 +341,34 @@ "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.0.x-dev", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "7c71fc2932158d00f24f10635bf3b3b8b6ee5b68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/7c71fc2932158d00f24f10635bf3b3b8b6ee5b68", + "reference": "7c71fc2932158d00f24f10635bf3b3b8b6ee5b68", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -387,34 +388,37 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2019-07-02T13:37:32+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.x-dev", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", + "reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -437,7 +441,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2019-04-07T13:18:21+00:00" }, { "name": "phar-io/manifest", @@ -445,18 +449,18 @@ "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "014feadb268809af7c8e2f7ccd396b8494901f58" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/014feadb268809af7c8e2f7ccd396b8494901f58", - "reference": "014feadb268809af7c8e2f7ccd396b8494901f58", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^1.0.1", + "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", @@ -492,20 +496,20 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-04-07T07:07:10+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { @@ -539,7 +543,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -597,16 +601,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "4.3.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", + "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", "shasum": "" }, "require": { @@ -644,7 +648,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2019-04-30T17:48:53+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -699,34 +703,34 @@ "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" + "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", - "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76", + "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -754,44 +758,44 @@ "spy", "stub" ], - "time": "2018-02-19T10:16:54+00:00" + "time": "2019-06-13T12:50:23+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.x-dev", + "version": "6.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "982ce790a6f31b8f1319a15d86e4614b109af25e" + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/982ce790a6f31b8f1319a15d86e4614b109af25e", - "reference": "982ce790a6f31b8f1319a15d86e4614b109af25e", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.0", - "phpunit/php-file-iterator": "^1.4.2", + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", + "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^3.1 || ^4.0", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -817,29 +821,32 @@ "testing", "xunit" ], - "time": "2017-12-07T10:13:30+00:00" + "time": "2018-10-31T16:06:48+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.x-dev", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "7f0f29702170e2786b2df813af970135765de6fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/7f0f29702170e2786b2df813af970135765de6fc", + "reference": "7f0f29702170e2786b2df813af970135765de6fc", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -854,7 +861,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -864,7 +871,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2019-07-02T07:44:20+00:00" }, { "name": "phpunit/php-text-template", @@ -909,28 +916,28 @@ }, { "name": "phpunit/php-timer", - "version": "1.0.x-dev", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "9513098641797ce5f459dbc1de5a54c29b0ec1fb" + "reference": "37d2894f3650acccb6e57207e63eb9699c1a82a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/9513098641797ce5f459dbc1de5a54c29b0ec1fb", - "reference": "9513098641797ce5f459dbc1de5a54c29b0ec1fb", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/37d2894f3650acccb6e57207e63eb9699c1a82a6", + "reference": "37d2894f3650acccb6e57207e63eb9699c1a82a6", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -945,7 +952,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -954,33 +961,33 @@ "keywords": [ "timer" ], - "time": "2018-01-06T05:27:16+00:00" + "time": "2019-07-02T07:42:03+00:00" }, { "name": "phpunit/php-token-stream", - "version": "2.0.x-dev", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "13eb9aba9626b1a3811c6a492acc9669d24bb85a" + "reference": "98831941cc60e07e7e94d4ff000440015f60da67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/13eb9aba9626b1a3811c6a492acc9669d24bb85a", - "reference": "13eb9aba9626b1a3811c6a492acc9669d24bb85a", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/98831941cc60e07e7e94d4ff000440015f60da67", + "reference": "98831941cc60e07e7e94d4ff000440015f60da67", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1003,57 +1010,57 @@ "keywords": [ "tokenizer" ], - "time": "2017-11-27T08:47:38+00:00" + "time": "2019-07-02T07:43:15+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.x-dev", + "version": "7.5.x-dev", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "80798b8043cb3b4e770c21e64d4fbc2efdda7942" + "reference": "e2e8fb619beae918f726d7c861ea72d310c5458d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/80798b8043cb3b4e770c21e64d4fbc2efdda7942", - "reference": "80798b8043cb3b4e770c21e64d4fbc2efdda7942", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e2e8fb619beae918f726d7c861ea72d310c5458d", + "reference": "e2e8fb619beae918f726d7c861ea72d310c5458d", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.0", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", - "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.5", - "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", - "sebastian/environment": "^3.1", + "phpunit/php-timer": "^2.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^4.0", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", + "sebastian/resource-operations": "^2.0", "sebastian/version": "^2.0.1" }, "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" + "phpunit/phpunit-mock-objects": "*" }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "phpunit/php-invoker": "^2.0" }, "bin": [ "phpunit" @@ -1061,7 +1068,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "7.5-dev" } }, "autoload": { @@ -1087,66 +1094,7 @@ "testing", "xunit" ], - "time": "2018-02-16T06:05:42+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "5.0.x-dev", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "e244c19aec6a1f0a2ff9e498b9b4bed22537730a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e244c19aec6a1f0a2ff9e498b9b4bed22537730a", - "reference": "e244c19aec6a1f0a2ff9e498b9b4bed22537730a", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.0", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "conflict": { - "phpunit/phpunit": "<6.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.5" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2018-01-07T17:10:51+00:00" + "time": "2019-07-05T14:16:20+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1154,12 +1102,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "3488be0a7b346cd6e5361510ed07e88f9bea2e88" + "reference": "5e860800beea5ea4c8590df866338c09c20d3a48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/3488be0a7b346cd6e5361510ed07e88f9bea2e88", - "reference": "3488be0a7b346cd6e5361510ed07e88f9bea2e88", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e860800beea5ea4c8590df866338c09c20d3a48", + "reference": "5e860800beea5ea4c8590df866338c09c20d3a48", "shasum": "" }, "require": { @@ -1191,7 +1139,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T10:23:55+00:00" + "time": "2019-07-02T07:44:03+00:00" }, { "name": "sebastian/comparator", @@ -1199,26 +1147,26 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "reference": "9a1267ac19ecd74163989bcb3e01c5c9587f9e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/9a1267ac19ecd74163989bcb3e01c5c9587f9e3b", + "reference": "9a1267ac19ecd74163989bcb3e01c5c9587f9e3b", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", + "php": "^7.1", + "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1255,32 +1203,33 @@ "compare", "equality" ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2019-07-02T07:45:15+00:00" }, { "name": "sebastian/diff", - "version": "2.0.x-dev", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "abcc70409ddfb310a8cb41ef0c2e857425438cf4" + "reference": "d7e7810940c78f3343420f76adf92dc437b7a557" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/abcc70409ddfb310a8cb41ef0c2e857425438cf4", - "reference": "abcc70409ddfb310a8cb41ef0c2e857425438cf4", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/d7e7810940c78f3343420f76adf92dc437b7a557", + "reference": "d7e7810940c78f3343420f76adf92dc437b7a557", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1305,9 +1254,12 @@ "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" ], - "time": "2017-12-14T11:32:19+00:00" + "time": "2019-07-02T07:43:30+00:00" }, { "name": "sebastian/environment", @@ -1315,25 +1267,27 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "eb71ad57e2b937a06c91a60efc647f28187626e9" + "reference": "1c91ab3fb351373cf86ead6006ea9daa8e4ce027" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/eb71ad57e2b937a06c91a60efc647f28187626e9", - "reference": "eb71ad57e2b937a06c91a60efc647f28187626e9", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1c91ab3fb351373cf86ead6006ea9daa8e4ce027", + "reference": "1c91ab3fb351373cf86ead6006ea9daa8e4ce027", "shasum": "" }, "require": { - "ext-posix": "*", - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -1358,7 +1312,7 @@ "environment", "hhvm" ], - "time": "2018-02-09T07:31:46+00:00" + "time": "2019-07-02T07:44:59+00:00" }, { "name": "sebastian/exporter", @@ -1366,12 +1320,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "573f8b71a29cc8afa5f8285d1aee4b4d52717637" + "reference": "97cc7aeb5bbc21a59df4e4e9e976831fa1b41fbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/573f8b71a29cc8afa5f8285d1aee4b4d52717637", - "reference": "573f8b71a29cc8afa5f8285d1aee4b4d52717637", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/97cc7aeb5bbc21a59df4e4e9e976831fa1b41fbe", + "reference": "97cc7aeb5bbc21a59df4e4e9e976831fa1b41fbe", "shasum": "" }, "require": { @@ -1425,20 +1379,20 @@ "export", "exporter" ], - "time": "2017-11-16T09:48:09+00:00" + "time": "2019-07-02T07:44:27+00:00" }, { "name": "sebastian/global-state", - "version": "dev-master", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "a27e666314b2df0ab686c2abdee43ffbda48ac10" + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a27e666314b2df0ab686c2abdee43ffbda48ac10", - "reference": "a27e666314b2df0ab686c2abdee43ffbda48ac10", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", "shasum": "" }, "require": { @@ -1476,7 +1430,7 @@ "keywords": [ "global state" ], - "time": "2017-11-16T09:49:42+00:00" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", @@ -1484,12 +1438,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "a496797f3bd6821bfe2acb594e0901dfb00572dd" + "reference": "63e5a3e0881ebf28c9fbb2a2e12b77d373850c12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/a496797f3bd6821bfe2acb594e0901dfb00572dd", - "reference": "a496797f3bd6821bfe2acb594e0901dfb00572dd", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/63e5a3e0881ebf28c9fbb2a2e12b77d373850c12", + "reference": "63e5a3e0881ebf28c9fbb2a2e12b77d373850c12", "shasum": "" }, "require": { @@ -1523,7 +1477,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-11-16T09:50:04+00:00" + "time": "2019-07-02T07:43:46+00:00" }, { "name": "sebastian/object-reflector", @@ -1531,12 +1485,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "ff755086ff55902772e3fae5dd5f29bcbae68285" + "reference": "3053ae3e6286fdf98769f18ec10894dbc6260a34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/ff755086ff55902772e3fae5dd5f29bcbae68285", - "reference": "ff755086ff55902772e3fae5dd5f29bcbae68285", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/3053ae3e6286fdf98769f18ec10894dbc6260a34", + "reference": "3053ae3e6286fdf98769f18ec10894dbc6260a34", "shasum": "" }, "require": { @@ -1568,7 +1522,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2018-01-07T16:00:13+00:00" + "time": "2019-07-02T07:44:36+00:00" }, { "name": "sebastian/recursion-context", @@ -1576,12 +1530,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "0f7f5eb7697036c570aff6812a8efe60c417725e" + "reference": "a58220ae18565f6004bbe15321efc4470bfe02fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0f7f5eb7697036c570aff6812a8efe60c417725e", - "reference": "0f7f5eb7697036c570aff6812a8efe60c417725e", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/a58220ae18565f6004bbe15321efc4470bfe02fd", + "reference": "a58220ae18565f6004bbe15321efc4470bfe02fd", "shasum": "" }, "require": { @@ -1621,7 +1575,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-11-16T10:04:08+00:00" + "time": "2019-07-02T07:43:54+00:00" }, { "name": "sebastian/resource-operations", @@ -1629,21 +1583,21 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "fadc83f7c41fb2924e542635fea47ae546816ece" + "reference": "d67fc89d3107c396d161411b620619f3e7a7c270" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/fadc83f7c41fb2924e542635fea47ae546816ece", - "reference": "fadc83f7c41fb2924e542635fea47ae546816ece", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/d67fc89d3107c396d161411b620619f3e7a7c270", + "reference": "d67fc89d3107c396d161411b620619f3e7a7c270", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1663,7 +1617,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2016-10-03T07:43:09+00:00" + "time": "2019-07-02T07:42:50+00:00" }, { "name": "sebastian/version", @@ -1709,17 +1663,75 @@ "time": "2016-10-03T07:35:21+00:00" }, { - "name": "theseer/tokenizer", - "version": "1.1.0", + "name": "symfony/polyfill-ctype", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "82ebae02209c21113908c229e9883c419720738a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a", + "reference": "82ebae02209c21113908c229e9883c419720738a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2019-02-06T07:57:58+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -1746,24 +1758,25 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", - "version": "dev-master", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { "phpunit/phpunit": "^4.6", @@ -1796,7 +1809,7 @@ "check", "validate" ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2018-12-25T11:19:39+00:00" } ], "aliases": [], @@ -1808,7 +1821,9 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.0" + "php": ">=7.1", + "ext-pdo": "*", + "ext-json": "*" }, "platform-dev": [] } From de6d6a051543825c505af3f420e87678f9378453 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Tue, 25 Jun 2019 13:50:52 -0500 Subject: [PATCH 034/133] Added new FILE page mode that allows sending files to the browser with these improvements: Reads the file and outputs it in chunks rather than all at once, reducing the amount of memory needed to very little, even for very very large files. Supports http request ranges so that only parts of the file will be returned if requested. This allows in-browser video players to seek to arbitrary points in the video without needing to download the whole file. Makes use of flush during send to allow the browser to being receiving file data immediately, allowing streamable video formats to begin playing before the server has finished sending the data. This could also be used in the future to add a transmission rate limiter. Has early-disconnect detection, to terminate sending file data if the client browser has disconnected or aborted (for instance, a user starts a video, then seeks to near the middle, the first request of data will be terminated rather than continuing to process the file). --- core/page.php | 109 +++++++++++++++++++++++++++++++++++++++------ ext/image/main.php | 14 +++--- 2 files changed, 103 insertions(+), 20 deletions(-) diff --git a/core/page.php b/core/page.php index 12189999..e31ed7d3 100644 --- a/core/page.php +++ b/core/page.php @@ -31,6 +31,7 @@ abstract class PageMode const REDIRECT = 'redirect'; const DATA = 'data'; const PAGE = 'page'; + const FILE = 'file'; } /** @@ -75,9 +76,14 @@ class Page /** @var string; public only for unit test */ public $data = ""; + /** @var string; */ + public $file = null; + /** @var string; public only for unit test */ public $filename = null; + private $disposition = null; + /** * Set the raw data to be sent. */ @@ -86,12 +92,18 @@ class Page $this->data = $data; } + public function set_file(string $file): void + { + $this->file = $file; + } + /** * Set the recommended download filename. */ - public function set_filename(string $filename): void + public function set_filename(string $filename, string $disposition = "attachment"): void { $this->filename = $filename; + $this->disposition = $disposition; } @@ -171,7 +183,7 @@ class Page /** * Add a line to the HTML head section. */ - public function add_html_header(string $line, int $position=50): void + public function add_html_header(string $line, int $position = 50): void { while (isset($this->html_headers[$position])) { $position++; @@ -182,7 +194,7 @@ class Page /** * Add a http header to be sent to the client. */ - public function add_http_header(string $line, int $position=50): void + public function add_http_header(string $line, int $position = 50): void { while (isset($this->http_headers[$position])) { $position++; @@ -197,13 +209,13 @@ class Page */ public function add_cookie(string $name, string $value, int $time, string $path): void { - $full_name = COOKIE_PREFIX."_".$name; + $full_name = COOKIE_PREFIX . "_" . $name; $this->cookies[] = [$full_name, $value, $time, $path]; } public function get_cookie(string $name): ?string { - $full_name = COOKIE_PREFIX."_".$name; + $full_name = COOKIE_PREFIX . "_" . $name; if (isset($_COOKIE[$full_name])) { return $_COOKIE[$full_name]; } else { @@ -252,8 +264,8 @@ class Page global $page, $user; header("HTTP/1.0 {$this->code} Shimmie"); - header("Content-type: ".$this->type); - header("X-Powered-By: SCore-".SCORE_VERSION); + header("Content-type: " . $this->type); + header("X-Powered-By: SCore-" . SCORE_VERSION); if (!headers_sent()) { foreach ($this->http_headers as $head) { @@ -292,15 +304,84 @@ class Page $layout->display_page($page); break; case PageMode::DATA: - header("Content-Length: ".strlen($this->data)); + header("Content-Length: " . strlen($this->data)); if (!is_null($this->filename)) { - header('Content-Disposition: attachment; filename='.$this->filename); + header('Content-Disposition: ' . $this->disposition . '; filename=' . $this->filename); } print $this->data; break; + case PageMode::FILE: + if (!is_null($this->filename)) { + header('Content-Disposition: ' . $this->disposition . '; filename=' . $this->filename); + } + + //https://gist.github.com/codler/3906826 + + $size = filesize($this->file); // File size + $length = $size; // Content length + $start = 0; // Start byte + $end = $size - 1; // End byte + + header("Content-Length: " . strlen($size)); + header('Accept-Ranges: bytes'); + + if (isset($_SERVER['HTTP_RANGE'])) { + + $c_start = $start; + $c_end = $end; + list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); + if (strpos($range, ',') !== false) { + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + break; + } + if ($range == '-') { + $c_start = $size - substr($range, 1); + } else { + $range = explode('-', $range); + $c_start = $range[0]; + $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; + } + $c_end = ($c_end > $end) ? $end : $c_end; + if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + break; + } + $start = $c_start; + $end = $c_end; + $length = $end - $start + 1; + header('HTTP/1.1 206 Partial Content'); + } + header("Content-Range: bytes $start-$end/$size"); + header("Content-Length: " . $length); + + + $fp = fopen($this->file, 'r'); + try { + fseek($fp, $start); + $buffer = 1024 * 64; + while (!feof($fp) && ($p = ftell($fp)) <= $end) { + if ($p + $buffer > $end) { + $buffer = $end - $p + 1; + } + set_time_limit(0); + echo fread($fp, $buffer); + flush(); + + // After flush, we can tell if the client browser has disconnected. + // This means we can start sending a large file, and if we detect they disappeared + // then we can just stop and not waste any more resources or bandwidth. + if (connection_status() != 0) + break; + } + } finally { + fclose($fp); + } + break; case PageMode::REDIRECT: - header('Location: '.$this->redirect); - print 'You should be redirected to '.$this->redirect.''; + header('Location: ' . $this->redirect); + print 'You should be redirected to ' . $this->redirect . ''; break; default: print "Invalid page mode"; @@ -341,7 +422,7 @@ class Page /*** Generate CSS cache files ***/ $css_latest = $config_latest; $css_files = array_merge( - zglob("ext/{".ENABLED_EXTS."}/style.css"), + zglob("ext/{" . ENABLED_EXTS . "}/style.css"), zglob("themes/$theme_name/style.css") ); foreach ($css_files as $css) { @@ -354,7 +435,7 @@ class Page foreach ($css_files as $file) { $file_data = file_get_contents($file); $pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/'; - $replace = 'url("../../../'.dirname($file).'/$1")'; + $replace = 'url("../../../' . dirname($file) . '/$1")'; $file_data = preg_replace($pattern, $replace, $file_data); $css_data .= $file_data . "\n"; } @@ -372,7 +453,7 @@ class Page "vendor/bower-asset/js-cookie/src/js.cookie.js", "ext/handle_static/modernizr-3.3.1.custom.js", ], - zglob("ext/{".ENABLED_EXTS."}/script.js"), + zglob("ext/{" . ENABLED_EXTS . "}/script.js"), zglob("themes/$theme_name/script.js") ); foreach ($js_files as $js) { diff --git a/ext/image/main.php b/ext/image/main.php index 3fc63325..c8d51126 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -255,7 +255,6 @@ class ImageIO extends Extension global $page; if (!is_null($image)) { - $page->set_mode(PageMode::DATA); if ($type == "thumb") { $ext = $config->get_string("thumb_type"); if (array_key_exists($ext, MIME_TYPE_MAP)) { @@ -263,7 +262,7 @@ class ImageIO extends Extension } else { $page->set_type("image/jpeg"); } - + $file = $image->get_thumb_filename(); } else { $page->set_type($image->get_mime_type()); @@ -278,26 +277,29 @@ class ImageIO extends Extension $gmdate_mod = gmdate('D, d M Y H:i:s', filemtime($file)) . ' GMT'; if ($if_modified_since == $gmdate_mod) { + $page->set_mode(PageMode::DATA); $page->set_code(304); $page->set_data(""); } else { + $page->set_mode(PageMode::FILE); $page->add_http_header("Last-Modified: $gmdate_mod"); if ($type != "thumb") { - $page->add_http_header("Content-Disposition: inline; filename=".$image->get_nice_image_name()); + $page->set_filename($image->get_nice_image_name(), 'inline'); } - $page->set_data(file_get_contents($file)); + + $page->set_file($file); if ($config->get_int("image_expires")) { $expires = date(DATE_RFC1123, time() + $config->get_int("image_expires")); } else { $expires = 'Fri, 2 Sep 2101 12:42:42 GMT'; // War was beginning } - $page->add_http_header('Expires: '.$expires); + $page->add_http_header('Expires: ' . $expires); } } else { $page->set_title("Not Found"); $page->set_heading("Not Found"); - $page->add_block(new Block("Navigation", "Index", "left", 0)); + $page->add_block(new Block("Navigation", "Index", "left", 0)); $page->add_block(new Block( "Image not in database", "The requested image was not found in the database" From a7c978c8d2362e3743e4f899ba912dac4107431c Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Tue, 25 Jun 2019 15:42:25 -0500 Subject: [PATCH 035/133] Added poster attribute to video element so thumbnail can show until video is loaded --- ext/handle_video/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/handle_video/theme.php b/ext/handle_video/theme.php index e91c24f9..64251769 100644 --- a/ext/handle_video/theme.php +++ b/ext/handle_video/theme.php @@ -48,7 +48,7 @@ class VideoFileHandlerTheme extends Themelet $loop = ($loop ? ' loop' : ''); $html .= " -
". - "". - "". - "". - "". + $html .= "" . + "" . + "" . + "" . + "" . ""; } @@ -96,7 +96,6 @@ class PoolsTheme extends Themelet $page->add_block(new Block("Pools", $html, "main", 10)); - $this->display_paginator($page, "pool/list", null, $pageNumber, $totalPages); } @@ -106,7 +105,7 @@ class PoolsTheme extends Themelet public function new_pool_composer(Page $page) { $create_html = " - ".make_form(make_link("pool/create"))." + " . make_form(make_link("pool/create")) . "
{$h_docs} {$h_description}
".$pool_link."".$user_link."".$pool['posts']."".$public."
" . $pool_link . "" . $user_link . "" . $pool['posts'] . "" . $public . "
@@ -120,7 +119,7 @@ class PoolsTheme extends Themelet $page->add_block(new Block("Create Pool", $create_html, "main", 20)); } - private function display_top(?array $pools, string $heading, bool $check_all=false) + private function display_top(?array $pools, string $heading, bool $check_all = false) { global $page, $user; @@ -128,9 +127,9 @@ class PoolsTheme extends Themelet $page->set_heading($heading); $poolnav_html = ' - Pool Index -
Create Pool -
Pool Changes + Pool Index +
Create Pool +
Pool Changes '; $page->add_block(new NavBlock()); @@ -157,16 +156,16 @@ class PoolsTheme extends Themelet { global $page; - $this->display_top($pools, "Pool: ".html_escape($pools[0]['title'])); + $this->display_top($pools, "Pool: " . html_escape($pools[0]['title'])); $pool_images = ''; foreach ($images as $image) { $thumb_html = $this->build_thumb_html($image); - $pool_images .= "\n".$thumb_html."\n"; + $pool_images .= "\n" . $thumb_html . "\n"; } $page->add_block(new Block("Viewing Posts", $pool_images, "main", 30)); - $this->display_paginator($page, "pool/view/".$pools[0]['id'], null, $pageNumber, $totalPages); + $this->display_paginator($page, "pool/view/" . $pools[0]['id'], null, $pageNumber, $totalPages); } @@ -177,22 +176,22 @@ class PoolsTheme extends Themelet { global $user; - $editor = "\n".make_form(make_link('pool/import')).' + $editor = "\n" . make_form(make_link('pool/import')) . ' - + - '.make_form(make_link('pool/edit')).' + ' . make_form(make_link('pool/edit')) . ' - + - '.make_form(make_link('pool/order')).' + ' . make_form(make_link('pool/order')) . ' - + '; @@ -206,9 +205,9 @@ class PoolsTheme extends Themelet //--> - ".make_form(make_link("pool/nuke"))." + " . make_form(make_link("pool/nuke")) . " - + "; } @@ -246,19 +245,19 @@ class PoolsTheme extends Themelet "; - $pool_images .= ""; + $pool_images .= ""; foreach ($images as $image) { $thumb_html = $this->build_thumb_html($image); - $pool_images .= ''. $thumb_html .'
'. - ''. + $pool_images .= '' . $thumb_html . '
' . + '' . '
'; } - $pool_images .= "
". - "". - "". + $pool_images .= "
" . + "" . + "" . ""; $page->add_block(new Block("Import", $pool_images, "main", 30)); @@ -273,21 +272,21 @@ class PoolsTheme extends Themelet { $this->display_top($pools, "Sorting Pool"); - $pool_images = "\n
"; + $pool_images = "\n"; $i = 0; foreach ($images as $pair) { $image = $pair[0]; $thumb_html = $this->build_thumb_html($image); - $pool_images .= ''."\n".$thumb_html."\n". - '
'. - ''. + $pool_images .= '' . "\n" . $thumb_html . "\n" . + '
' . + '' . '
'; $i++; } - $pool_images .= "
". - "". - "". + $pool_images .= "
" . + "" . + "" . ""; $page->add_block(new Block("Sorting Posts", $pool_images, "main", 30)); @@ -303,29 +302,29 @@ class PoolsTheme extends Themelet { /* EDIT POOL DESCRIPTION */ $desc_html = " - ".make_form(make_link("pool/edit_description"))." -
- + " . make_form(make_link("pool/edit_description")) . " +
+ "; /* REMOVE POOLS */ - $pool_images = "\n
"; + $pool_images = "\n"; foreach ($images as $pair) { $image = $pair[0]; $thumb_html = $this->build_thumb_html($image); - $pool_images .= ''."\n".$thumb_html."\n". - '
'. + $pool_images .= '' . "\n" . $thumb_html . "\n" . + '
' . '
'; } - $pool_images .= "
". - "". - "". + $pool_images .= "
" . + "" . + "" . ""; $pools[0]['description'] = ""; //This is a rough fix to avoid showing the description twice. @@ -353,9 +352,9 @@ class PoolsTheme extends Themelet
'; foreach ($histories as $history) { - $pool_link = "".html_escape($history['title']).""; - $user_link = "".html_escape($history['user_name']).""; - $revert_link = "Revert"; + $pool_link = "" . html_escape($history['title']) . ""; + $user_link = "" . html_escape($history['user_name']) . ""; + $revert_link = "Revert"; if ($history['action'] == 1) { $prefix = "+"; @@ -370,16 +369,16 @@ class PoolsTheme extends Themelet $image_link = ""; foreach ($images as $image) { - $image_link .= "".$prefix.$image." "; + $image_link .= "" . $prefix . $image . " "; } - $html .= "". - "". - "". - "". - "". - "". - "". + $html .= "" . + "" . + "" . + "" . + "" . + "" . + "" . ""; } @@ -390,4 +389,18 @@ class PoolsTheme extends Themelet $this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages); } + + public function get_bulk_pool_selector(array $pools) + { + $output = ""; + } + + public function get_bulk_pool_input() + { + return ""; + } } From c16d55995b7ff7c2bf5f25a9d9f1b22454f730c2 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 26 Jun 2019 23:00:49 -0500 Subject: [PATCH 051/133] Added table-building support to SetupBlock to allow easily building cleaner setup controls --- ext/handle_static/style.css | 2 +- ext/resize/main.php | 33 ++++++-- ext/setup/main.php | 161 +++++++++++++++++++++++++++--------- ext/transcode/main.php | 12 +-- 4 files changed, 153 insertions(+), 55 deletions(-) diff --git a/ext/handle_static/style.css b/ext/handle_static/style.css index 30315b6c..444fa296 100644 --- a/ext/handle_static/style.css +++ b/ext/handle_static/style.css @@ -13,7 +13,7 @@ TD>BUTTON {width: 100%;} TABLE.form {width: 300px;} TABLE.form TD, TABLE.form TH {vertical-align: middle;} TABLE.form TBODY TD {text-align: left;} -TABLE.form TBODY TH {text-align: right; padding-right: 4px; width: 1%;} +TABLE.form TBODY TH {text-align: right; padding-right: 4px; width: 1%; white-space: nowrap;} TABLE.form TD + TH {padding-left: 8px;} *[onclick], diff --git a/ext/resize/main.php b/ext/resize/main.php index a998814e..08036260 100644 --- a/ext/resize/main.php +++ b/ext/resize/main.php @@ -11,6 +11,16 @@ * Documentation: * This extension allows admins to resize images. */ + +abstract class ResizeConfig +{ + const ENABLED = 'resize_enabled'; + const UPLOAD = 'resize_upload'; + const ENGINE = 'resize_engine'; + const DEFAULT_WIDTH = 'resize_default_width'; + const DEFAULT_HEIGHT = 'resize_default_height'; +} + /** * This class handles image resize requests. */ @@ -49,15 +59,20 @@ class ResizeImage extends Extension public function onSetupBuilding(SetupBuildingEvent $event) { $sb = new SetupBlock("Image Resize"); - $sb->add_bool_option("resize_enabled", "Allow resizing images: "); - $sb->add_bool_option("resize_upload", "
Resize on upload: "); - $sb->add_label("
Preset/Default Width: "); - $sb->add_int_option("resize_default_width"); - $sb->add_label(" px"); - $sb->add_label("
Preset/Default Height: "); - $sb->add_int_option("resize_default_height"); - $sb->add_label(" px"); - $sb->add_label("
(enter 0 for no default)"); + $sb->start_table(); + $sb->add_bool_option(ResizeConfig::ENABLED, "Allow resizing images: ", true); + $sb->add_bool_option(ResizeConfig::UPLOAD, "Resize on upload: ", true); + $sb->end_table(); + $sb->start_table(); + $sb->add_table_header("Preset/Default Dimensions"); + $sb->add_label("
"); + $sb->add_label(""); + $sb->add_label(""); + $sb->end_table(); $event->panel->add_block($sb); } diff --git a/ext/setup/main.php b/ext/setup/main.php index 23999102..8af9513a 100644 --- a/ext/setup/main.php +++ b/ext/setup/main.php @@ -61,6 +61,8 @@ class SetupBlock extends Block /** @var string */ public $body; + + public function __construct(string $title) { $this->header = $title; @@ -74,38 +76,123 @@ class SetupBlock extends Block $this->body .= $text; } - public function add_text_option(string $name, string $label=null) + public function start_table() { + $this->body .= "
Title:
Public?
".$pool_link."".$history['count']."".$image_link."".$user_link."".$history['date']."".$revert_link."
" . $pool_link . "" . $history['count'] . "" . $image_link . "" . $user_link . "" . $history['date'] . "" . $revert_link . "
Width"); + $sb->add_int_option(ResizeConfig::DEFAULT_WIDTH); + $sb->add_label("px
Height"); + $sb->add_int_option(ResizeConfig::DEFAULT_HEIGHT); + $sb->add_label("px
(enter 0 for no default)
"; + } + public function end_table() + { + $this->body .= "
"; + } + public function start_table_row() + { + $this->body .= ""; + } + public function end_table_row() + { + $this->body .= ""; + } + public function start_table_head() + { + $this->body .= ""; + } + public function end_table_head() + { + $this->body .= ""; + } + public function add_table_header($content, int $colspan = 2) + { + $this->start_table_head(); + $this->start_table_row(); + $this->add_table_header_cell($content, $colspan); + $this->end_table_row(); + $this->end_table_head(); + } + + public function start_table_cell(int $colspan = 1) + { + $this->body .= ""; + } + public function end_table_cell() + { + $this->body .= ""; + } + public function add_table_cell($content, int $colspan = 1) + { + $this->start_table_cell($colspan); + $this->body .= $content; + $this->end_table_cell(); + } + public function start_table_header_cell(int $colspan = 1) + { + $this->body .= ""; + } + public function end_table_header_cell() + { + $this->body .= ""; + } + public function add_table_header_cell($content, int $colspan = 1) + { + $this->start_table_header_cell($colspan); + $this->body .= $content; + $this->end_table_header_cell(); + } + + + + private function format_option(string $name, $html, ?string $label, bool $table_row) { global $config; - $val = html_escape($config->get_string($name)); + + if($table_row) $this->start_table_row(); + if($table_row) $this->start_table_header_cell(); if (!is_null($label)) { $this->body .= ""; } - $this->body .= "\n"; - $this->body .= "\n"; + if($table_row) $this->end_table_header_cell(); + + if($table_row) $this->start_table_cell(); + $this->body .= $html; + if($table_row) $this->end_table_cell(); + if($table_row) $this->end_table_row(); } - public function add_longtext_option(string $name, string $label=null) + public function add_text_option(string $name, string $label=null, bool $table_row = false) { global $config; $val = html_escape($config->get_string($name)); - if (!is_null($label)) { - $this->body .= ""; - } - $rows = max(3, min(10, count(explode("\n", $val)))); - $this->body .= "\n"; - $this->body .= "\n"; + + $html = "\n"; + $html .= "\n"; + + $this->format_option($name, $html, $label, $table_row); } - public function add_bool_option(string $name, string $label=null) + public function add_longtext_option(string $name, string $label=null, bool $table_row = false) + { + global $config; + $val = html_escape($config->get_string($name)); + + $rows = max(3, min(10, count(explode("\n", $val)))); + $html = "\n"; + $html .= "\n"; + + $this->format_option($name, $html, $label, $table_row); + } + + public function add_bool_option(string $name, string $label=null, bool $table_row = false) { global $config; $checked = $config->get_bool($name) ? " checked" : ""; + + $html = "\n"; if (!is_null($label)) { - $this->body .= ""; + $html .= ""; + $label = null; } - $this->body .= "\n"; - $this->body .= "\n"; + + $html .= "\n"; + + $this->format_option($name, $html, $label, $table_row); } // public function add_hidden_option($name, $label=null) { @@ -114,36 +201,33 @@ class SetupBlock extends Block // $this->body .= ""; // } - public function add_int_option(string $name, string $label=null) + public function add_int_option(string $name, string $label=null, bool $table_row = false) { global $config; $val = html_escape($config->get_string($name)); - if (!is_null($label)) { - $this->body .= ""; - } - $this->body .= "\n"; - $this->body .= "\n"; + + $html = "\n"; + $html .= "\n"; + + $this->format_option($name, $html, $label, $table_row); + } - public function add_shorthand_int_option(string $name, string $label=null) + public function add_shorthand_int_option(string $name, string $label=null, bool $table_row = false) { global $config; $val = to_shorthand_int($config->get_string($name)); - if (!is_null($label)) { - $this->body .= ""; - } - $this->body .= "\n"; - $this->body .= "\n"; + $html = "\n"; + $html .= "\n"; + + $this->format_option($name, $html, $label, $table_row); } - public function add_choice_option(string $name, array $options, string $label=null) + public function add_choice_option(string $name, array $options, string $label=null, bool $table_row = false) { global $config; $current = $config->get_string($name); - if (!is_null($label)) { - $this->body .= ""; - } $html = ""; - $this->body .= "\n"; + $html .= "\n"; - $this->body .= $html; + $this->format_option($name, $html, $label, $table_row); } - public function add_multichoice_option(string $name, array $options, string $label=null) + public function add_multichoice_option(string $name, array $options, string $label=null, bool $table_row = false) { global $config; $current = $config->get_array($name); - if (!is_null($label)) { - $this->body .= ""; - } $html = ""; - $this->body .= "\n"; - $this->body .= "\n"; // setup page auto-layout counts
tags + $html .= "\n"; + $html .= "\n"; // setup page auto-layout counts
tags - $this->body .= $html; + $this->format_option($name, $html, $label, $table_row); } } // }}} diff --git a/ext/transcode/main.php b/ext/transcode/main.php index 94520ba0..b47efcb1 100644 --- a/ext/transcode/main.php +++ b/ext/transcode/main.php @@ -133,16 +133,18 @@ class TranscodeImage extends Extension $sb = new SetupBlock("Image Transcode"); - $sb->add_bool_option("transcode_enabled", "Allow transcoding images: "); - $sb->add_bool_option("transcode_upload", "
Transcode on upload: "); - $sb->add_choice_option('transcode_engine', self::CONVERSION_ENGINES, "
Transcode engine: "); + $sb->start_table(); + $sb->add_bool_option(TranscodeConfig::ENABLED, "Allow transcoding images: ", true); + $sb->add_bool_option(TranscodeConfig::UPLOAD, "Transcode on upload: ", true); + $sb->add_choice_option(TranscodeConfig::ENGINE, self::CONVERSION_ENGINES, "Engine", true); foreach (self::INPUT_FORMATS as $display=>$format) { if (in_array($format, self::ENGINE_INPUT_SUPPORT[$engine])) { $outputs = $this->get_supported_output_formats($engine, $format); - $sb->add_choice_option('transcode_upload_'.$format, $outputs, "
$display to: "); + $sb->add_choice_option(TranscodeConfig::UPLOAD_PREFIX.$format, $outputs, "$display", true); } } - $sb->add_int_option("transcode_quality", "
Lossy format quality: "); + $sb->add_int_option(TranscodeConfig::QUALITY, "Lossy format quality: "); + $sb->end_table(); $event->panel->add_block($sb); } From a7188a452b50f9f671656a8b7cf2069ee376dd57 Mon Sep 17 00:00:00 2001 From: matthew Date: Thu, 4 Jul 2019 12:56:45 -0500 Subject: [PATCH 052/133] Fixed issue with setup block checkbox generator --- ext/setup/main.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ext/setup/main.php b/ext/setup/main.php index 8af9513a..86af0141 100644 --- a/ext/setup/main.php +++ b/ext/setup/main.php @@ -184,15 +184,19 @@ class SetupBlock extends Block global $config; $checked = $config->get_bool($name) ? " checked" : ""; - $html = "\n"; - if (!is_null($label)) { + $html = ""; + if(!$table_row&&!is_null($label)) { + $html .= ""; + } + + $html .= "\n"; + if ($table_row && !is_null($label)) { $html .= ""; - $label = null; } $html .= "\n"; - $this->format_option($name, $html, $label, $table_row); + $this->format_option($name, $html, null, $table_row); } // public function add_hidden_option($name, $label=null) { From 02e2786cca14b7e81d16b16a7aeec1307a20dcd5 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Thu, 27 Jun 2019 12:26:09 -0500 Subject: [PATCH 053/133] Added missing constant --- ext/transcode/main.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/transcode/main.php b/ext/transcode/main.php index b47efcb1..8a04f884 100644 --- a/ext/transcode/main.php +++ b/ext/transcode/main.php @@ -22,6 +22,8 @@ class ImageTranscodeException extends SCoreException class TranscodeImage extends Extension { + const ACTION_BULK_TRANSCODE = "bulk_transcode"; + const CONVERSION_ENGINES = [ "GD" => "gd", "ImageMagick" => "convert", From 92bb96049f179563c63188e5b777e2d09feb78aa Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 26 Jun 2019 22:29:52 -0500 Subject: [PATCH 054/133] Added SCORE sql constants --- core/dbengine.php | 64 ++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/core/dbengine.php b/core/dbengine.php index 79b407ec..5286a8ad 100644 --- a/core/dbengine.php +++ b/core/dbengine.php @@ -1,4 +1,16 @@ BOOL_Y'", $data); - $data = str_replace("SCORE_BOOL_N", "'$this->BOOL_N'", $data); - $data = str_replace("SCORE_BOOL", "ENUM('Y', 'N')", $data); - $data = str_replace("SCORE_DATETIME", "DATETIME", $data); - $data = str_replace("SCORE_NOW", "\"1970-01-01\"", $data); - $data = str_replace("SCORE_STRNORM", "", $data); - $data = str_replace("SCORE_ILIKE", "LIKE", $data); + $data = str_replace(SCORE::AIPK, "INTEGER PRIMARY KEY auto_increment", $data); + $data = str_replace(SCORE::INET, "VARCHAR(45)", $data); + $data = str_replace(SCORE::BOOL_Y, "'$this->BOOL_Y'", $data); + $data = str_replace(SCORE::BOOL_N, "'$this->BOOL_N'", $data); + $data = str_replace(SCORE::BOOL, "ENUM('Y', 'N')", $data); + $data = str_replace(SCORE::DATETIME, "DATETIME", $data); + $data = str_replace(SCORE::NOW, "\"1970-01-01\"", $data); + $data = str_replace(SCORE::STRNORM, "", $data); + $data = str_replace(SCORE::ILIKE, "LIKE", $data); return $data; } @@ -79,15 +91,15 @@ class PostgreSQL extends DBEngine public function scoreql_to_sql(string $data): string { - $data = str_replace("SCORE_AIPK", "SERIAL PRIMARY KEY", $data); - $data = str_replace("SCORE_INET", "INET", $data); - $data = str_replace("SCORE_BOOL_Y", "'$this->BOOL_Y'", $data); - $data = str_replace("SCORE_BOOL_N", "'$this->BOOL_N'", $data); - $data = str_replace("SCORE_BOOL", "BOOL", $data); - $data = str_replace("SCORE_DATETIME", "TIMESTAMP", $data); - $data = str_replace("SCORE_NOW", "current_timestamp", $data); - $data = str_replace("SCORE_STRNORM", "lower", $data); - $data = str_replace("SCORE_ILIKE", "ILIKE", $data); + $data = str_replace(SCORE::AIPK, "SERIAL PRIMARY KEY", $data); + $data = str_replace(SCORE::INET, "INET", $data); + $data = str_replace(SCORE::BOOL_Y, "'$this->BOOL_Y'", $data); + $data = str_replace(SCORE::BOOL_N, "'$this->BOOL_N'", $data); + $data = str_replace(SCORE::BOOL, "BOOL", $data); + $data = str_replace(SCORE::DATETIME, "TIMESTAMP", $data); + $data = str_replace(SCORE::NOW, "current_timestamp", $data); + $data = str_replace(SCORE::STRNORM, "lower", $data); + $data = str_replace(SCORE::ILIKE, "ILIKE", $data); return $data; } @@ -171,14 +183,14 @@ class SQLite extends DBEngine public function scoreql_to_sql(string $data): string { - $data = str_replace("SCORE_AIPK", "INTEGER PRIMARY KEY", $data); - $data = str_replace("SCORE_INET", "VARCHAR(45)", $data); - $data = str_replace("SCORE_BOOL_Y", "'$this->BOOL_Y'", $data); - $data = str_replace("SCORE_BOOL_N", "'$this->BOOL_N'", $data); - $data = str_replace("SCORE_BOOL", "CHAR(1)", $data); - $data = str_replace("SCORE_NOW", "\"1970-01-01\"", $data); - $data = str_replace("SCORE_STRNORM", "lower", $data); - $data = str_replace("SCORE_ILIKE", "LIKE", $data); + $data = str_replace(SCORE::AIPK, "INTEGER PRIMARY KEY", $data); + $data = str_replace(SCORE::INET, "VARCHAR(45)", $data); + $data = str_replace(SCORE::BOOL_Y, "'$this->BOOL_Y'", $data); + $data = str_replace(SCORE::BOOL_N, "'$this->BOOL_N'", $data); + $data = str_replace(SCORE::BOOL, "CHAR(1)", $data); + $data = str_replace(SCORE::NOW, "\"1970-01-01\"", $data); + $data = str_replace(SCORE::STRNORM, "lower", $data); + $data = str_replace(SCORE::ILIKE, "LIKE", $data); return $data; } From 32d37254f744389a05f828e6c7462147cda52ebf Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Tue, 25 Jun 2019 18:47:06 -0500 Subject: [PATCH 055/133] New trash extension. For undelete-type stuff. --- core/event.php | 2 + core/send_event.php | 4 ++ ext/pools/main.php | 52 +++++++------- ext/trash/main.php | 164 ++++++++++++++++++++++++++++++++++++++++++++ ext/trash/theme.php | 14 ++++ 5 files changed, 207 insertions(+), 29 deletions(-) create mode 100644 ext/trash/main.php create mode 100644 ext/trash/theme.php diff --git a/core/event.php b/core/event.php index 292da5bf..349a6ce0 100644 --- a/core/event.php +++ b/core/event.php @@ -6,6 +6,8 @@ */ abstract class Event { + public $stop_processing = false; + public function __construct() { } diff --git a/core/send_event.php b/core/send_event.php index 6903a03c..3420df05 100644 --- a/core/send_event.php +++ b/core/send_event.php @@ -121,6 +121,7 @@ function send_event(Event $event): void // SHIT: http://bugs.php.net/bug.php?id=35106 $my_event_listeners = $_shm_event_listeners[get_class($event)]; ksort($my_event_listeners); + foreach ($my_event_listeners as $listener) { if ($ctx_enabled) { $_shm_ctx->log_start(get_class($listener)); @@ -131,6 +132,9 @@ function send_event(Event $event): void if ($ctx_enabled) { $_shm_ctx->log_endok(); } + if($event->stop_processing===true) { + break; + } } $_shm_event_count++; if ($ctx_enabled) { diff --git a/ext/pools/main.php b/ext/pools/main.php index 42220e6b..8cb464c1 100644 --- a/ext/pools/main.php +++ b/ext/pools/main.php @@ -768,44 +768,38 @@ class Pools extends Extension $imagesPerPage = $config->get_int(PoolsConfig::IMAGES_PER_PAGE); + + $query = " + INNER JOIN images AS i ON i.id = p.image_id + WHERE p.pool_id = :pid + "; + + // WE CHECK IF THE EXTENSION RATING IS INSTALLED, WHICH VERSION AND IF IT // WORKS TO SHOW/HIDE SAFE, QUESTIONABLE, EXPLICIT AND UNRATED IMAGES FROM USER if (ext_is_live("Ratings")) { - $rating = Ratings::privs_to_sql(Ratings::get_user_privs($user)); + $query .= "AND i.rating IN (".Ratings::privs_to_sql(Ratings::get_user_privs($user)).")"; } - if (isset($rating) && !empty($rating)) { - $result = $database->get_all( - " - SELECT p.image_id - FROM pool_images AS p - INNER JOIN images AS i ON i.id = p.image_id - WHERE p.pool_id = :pid AND i.rating IN ($rating) + if(ext_is_live("trash")) { + $query .= $database->scoreql_to_sql(" AND trash = SCORE_BOOL_N "); + } + + $result = $database->get_all( + " + SELECT p.image_id FROM pool_images p + $query ORDER BY p.image_order ASC LIMIT :l OFFSET :o", - ["pid" => $poolID, "l" => $imagesPerPage, "o" => $pageNumber * $imagesPerPage] - ); + ["pid" => $poolID, "l" => $imagesPerPage, "o" => $pageNumber * $imagesPerPage] + ); - $totalPages = ceil($database->get_one( - " - SELECT COUNT(*) - FROM pool_images AS p - INNER JOIN images AS i ON i.id = p.image_id - WHERE pool_id=:pid AND i.rating IN ($rating)", - ["pid" => $poolID] - ) / $imagesPerPage); - } else { - $result = $database->get_all( + $totalPages = ceil($database->get_one( " - SELECT image_id - FROM pool_images - WHERE pool_id=:pid - ORDER BY image_order ASC - LIMIT :l OFFSET :o", - ["pid" => $poolID, "l" => $imagesPerPage, "o" => $pageNumber * $imagesPerPage] - ); + SELECT COUNT(*) FROM pool_images p + $query", + ["pid" => $poolID] + ) / $imagesPerPage); - $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid" => $poolID]) / $imagesPerPage); - } $images = []; diff --git a/ext/trash/main.php b/ext/trash/main.php new file mode 100644 index 00000000..dc32000f --- /dev/null +++ b/ext/trash/main.php @@ -0,0 +1,164 @@ + + * License: MIT + * Description: Provides "Trash" or "Recycle Bin"-type functionality, storing delete images for later recovery + * Documentation: + */ + +abstract class TrashConfig +{ + const VERSION = "ext_trash_version"; +} + +class Trash extends Extension +{ + + protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL]; + + public function get_priority(): int + { + // Needs to be early to intercept delete events + return 10; + } + + public function onInitExt(InitExtEvent $event) + { + global $config; + + if ($config->get_int(TrashConfig::VERSION) < 1) { + $this->install(); + } + } + + + public function onPageRequest(PageRequestEvent $event) + { + global $page, $user; + + if ($event->page_matches("trash_restore") && $user->can("view_trash")) { + // Try to get the image ID + $image_id = int_escape($event->get_arg(0)); + if (empty($image_id)) { + $image_id = isset($_POST['image_id']) ? $_POST['image_id'] : null; + } + if (empty($image_id)) { + throw new SCoreException("Can not restore image: No valid Image ID given."); + } + + self::set_trash($image_id, false); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("post/view/".$image_id)); + } + } + + + + public function onDisplayingImage(DisplayingImageEvent $event) + { + global $user, $page; + + if(!$user->can("view_trash")) { + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("post/list")); + } + } + + public function onImageDeletion(ImageDeletionEvent $event) + { + if($event->image->trash===false) { + self::set_trash($event->image->id, true); + $event->stop_processing = true; + } + } + + + const SEARCH_REGEXP = "/^in:trash$/"; + public function onSearchTermParse(SearchTermParseEvent $event) + { + global $user, $database; + + $matches = []; + + if (is_null($event->term) && $this->no_trash_query($event->context)) { + $event->add_querylet(new Querylet($database->scoreql_to_sql("trash = SCORE_BOOL_N "))); + } + + + if (preg_match(self::SEARCH_REGEXP, strtolower($event->term), $matches)) { + if($user->can("view_trash")) { + $event->add_querylet(new Querylet($database->scoreql_to_sql("trash = SCORE_BOOL_Y "))); + } + } + } + + private function no_trash_query(array $context): bool + { + foreach ($context as $term) { + if (preg_match(self::SEARCH_REGEXP, $term)) { + return false; + } + } + return true; + } + + public static function set_trash($image_id, $trash) { + global $database; + + $database->execute("UPDATE images SET trash = :trash WHERE id = :id", + ["trash"=>$database->scoresql_value_prepare($trash),"id"=>$image_id]); + + + } + public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) + { + global $config, $database, $user; + if($event->image->trash===true && $user->can("view_trash")) { + $event->add_part($this->theme->get_image_admin_html($event->image->id)); + } + } + + public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event) + { + global $user; + + if ($user->can("view_trash")&&in_array("in:trash", $event->search_terms)) { + $event->add_action("bulk_trash_restore","Restore From Trash"); + } + } + + public function onBulkAction(BulkActionEvent $event) + { + global $user; + + switch ($event->action) { + case "bulk_trash_restore": + if ($user->can("view_trash")) { + $total = 0; + foreach ($event->items as $id) { + self::set_trash($id, false); + $total++; + } + flash_message("Restored $total items from trash"); + } + break; + } + } + + + private function install() + { + global $database, $config; + + if ($config->get_int(TrashConfig::VERSION) < 1) { + $database->Execute($database->scoreql_to_sql( + "ALTER TABLE images ADD COLUMN trash SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" + )); + $database->Execute("CREATE INDEX images_trash_idx ON images(trash)"); + $config->set_int(TrashConfig::VERSION, 1); + } + + } + +} diff --git a/ext/trash/theme.php b/ext/trash/theme.php new file mode 100644 index 00000000..5e4e2e15 --- /dev/null +++ b/ext/trash/theme.php @@ -0,0 +1,14 @@ + + + + "; + + return $html; } +} From 1bd9238b1756a2e07d7385478dfcbe4801ee4830 Mon Sep 17 00:00:00 2001 From: matthew Date: Thu, 27 Jun 2019 08:11:19 -0500 Subject: [PATCH 056/133] Additional trash stuff --- core/userclass.php | 11 +++++++++++ ext/trash/main.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/core/userclass.php b/core/userclass.php index de781aa2..fdb0ce28 100644 --- a/core/userclass.php +++ b/core/userclass.php @@ -128,6 +128,11 @@ new UserClass("base", null, [ "view_hellbanned" => false, "protected" => false, # only admins can modify protected users (stops a moderator changing an admin's password) + + "edit_image_rating" => false, + "bulk_edit_image_rating" => false, + + "view_trash" => false, ]); new UserClass("anonymous", "base", [ @@ -140,6 +145,8 @@ new UserClass("user", "base", [ "edit_image_tag" => true, "edit_image_source" => true, "create_image_report" => true, + "edit_image_rating" => true, + ]); new UserClass("admin", "base", [ @@ -184,6 +191,10 @@ new UserClass("admin", "base", [ "view_sysinfo" => true, "view_hellbanned" => true, "protected" => true, + "edit_image_rating" => true, + "bulk_edit_image_rating" => true, + "view_trash" => true, + ]); new UserClass("hellbanned", "user", [ diff --git a/ext/trash/main.php b/ext/trash/main.php index dc32000f..bda019b7 100644 --- a/ext/trash/main.php +++ b/ext/trash/main.php @@ -59,7 +59,7 @@ class Trash extends Extension { global $user, $page; - if(!$user->can("view_trash")) { + if($event->image->trash===true && !$user->can("view_trash")) { $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/list")); } From a82fb56063132f9700dc372297dc43f71679afbb Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Thu, 27 Jun 2019 13:34:25 -0500 Subject: [PATCH 057/133] Added force flag to image deletion event to override trash extension --- core/imageboard/event.php | 6 +++++- ext/trash/main.php | 2 +- tests/bootstrap.php | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/imageboard/event.php b/core/imageboard/event.php index ec663d6b..3064fa03 100644 --- a/core/imageboard/event.php +++ b/core/imageboard/event.php @@ -42,15 +42,19 @@ class ImageDeletionEvent extends Event /** @var Image */ public $image; + /** @var bool */ + public $force = false; + /** * Deletes an image. * * Used by things like tags and comments handlers to * clean out related rows in their tables. */ - public function __construct(Image $image) + public function __construct(Image $image, bool $force = false) { $this->image = $image; + $this->force = $force; } } diff --git a/ext/trash/main.php b/ext/trash/main.php index bda019b7..1c9484d3 100644 --- a/ext/trash/main.php +++ b/ext/trash/main.php @@ -67,7 +67,7 @@ class Trash extends Extension public function onImageDeletion(ImageDeletionEvent $event) { - if($event->image->trash===false) { + if($event->force===false && $event->image->trash===false) { self::set_trash($event->image->id, true); $event->stop_processing = true; } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e2bcb800..40166c21 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -167,7 +167,7 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase { $img = Image::by_id($image_id); if ($img) { - $ide = new ImageDeletionEvent($img); + $ide = new ImageDeletionEvent($img, true); send_event($ide); } } From c4111cc94816a9f0bd66bd1eb909e84661da2300 Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Wed, 26 Jun 2019 22:41:42 -0500 Subject: [PATCH 058/133] Added shortcut-key support to bulk action extension --- ext/bulk_actions/main.php | 32 +++++++++++++++++++++++--------- ext/bulk_actions/theme.php | 8 ++++---- ext/pools/main.php | 4 ++-- ext/rating/main.php | 8 ++++---- ext/regen_thumb/main.php | 2 +- ext/transcode/main.php | 11 ++++++++++- ext/trash/main.php | 2 +- 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/ext/bulk_actions/main.php b/ext/bulk_actions/main.php index b945f727..f9294ac1 100644 --- a/ext/bulk_actions/main.php +++ b/ext/bulk_actions/main.php @@ -16,22 +16,29 @@ class BulkActionBlockBuildingEvent extends Event public $search_terms = []; - public function add_action(String $action, string $button_text, String $confirmation_message = "", String $block = "", int $position = 40) + public function add_action(String $action, string $button_text, string $access_key = null, String $confirmation_message = "", String $block = "", int $position = 40) { if ($block == null) { $block = ""; } - array_push( - $this->actions, - [ + if(!empty($access_key)) { + assert(strlen($access_key)==1); + foreach ($this->actions as $existing) { + if($existing["access_key"]==$access_key) { + throw new SCoreException("Access key $access_key is already in use"); + } + } + } + + $this->actions[] =[ "block" => $block, + "access_key" => $access_key, "confirmation_message" => $confirmation_message, "action" => $action, "button_text" => $button_text, "position" => $position - ] - ); + ]; } } @@ -79,15 +86,22 @@ class BulkActions extends Extension global $user; if ($user->can("delete_image")) { - $event->add_action("bulk_delete", "Delete", "Delete selected images?", "", 10); + $event->add_action("bulk_delete", "(D)elete", "d", "Delete selected images?", "", 10); } if ($user->can("bulk_edit_image_tag")) { - $event->add_action("bulk_tag", "Tag", "", $this->theme->render_tag_input(), 10); + + $event->add_action( + "bulk_tag", + "Tag", + "t", + "", + $this->theme->render_tag_input(), + 10); } if ($user->can("bulk_edit_image_source")) { - $event->add_action("bulk_source", "Set Source", "", $this->theme->render_source_input(), 10); + $event->add_action("bulk_source", "Set (S)ource", "s","", $this->theme->render_source_input(), 10); } } diff --git a/ext/bulk_actions/theme.php b/ext/bulk_actions/theme.php index 538c74df..30eac633 100644 --- a/ext/bulk_actions/theme.php +++ b/ext/bulk_actions/theme.php @@ -2,14 +2,14 @@ class BulkActionsTheme extends Themelet { - public function display_selector(Page $page, $actions, $query) + public function display_selector(Page $page, array $actions, string $query) { global $user; $body = " - +