Merge pull request #663 from sanmadjack/bugfixes

Bugfixes and small changes
This commit is contained in:
Shish 2019-06-21 09:11:52 +01:00 committed by GitHub
commit 42a502953b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
88 changed files with 693 additions and 570 deletions

View File

@ -99,21 +99,21 @@ For example, one can override the default anonymous "allow nothing"
permissions like so: permissions like so:
```php ```php
new UserClass("anonymous", "base", array( new UserClass("anonymous", "base", [
"create_comment" => True, "create_comment" => True,
"edit_image_tag" => True, "edit_image_tag" => True,
"edit_image_source" => True, "edit_image_source" => True,
"create_image_report" => True, "create_image_report" => True,
)); ]);
``` ```
For a moderator class, being a regular user who can delete images and comments: For a moderator class, being a regular user who can delete images and comments:
```php ```php
new UserClass("moderator", "user", array( new UserClass("moderator", "user", [
"delete_image" => True, "delete_image" => True,
"delete_comment" => True, "delete_comment" => True,
)); ]);
``` ```
For a list of permissions, see `core/userclass.php` For a list of permissions, see `core/userclass.php`

View File

@ -110,7 +110,7 @@ function do_install()
{ // {{{ { // {{{
if (file_exists("data/config/auto_install.conf.php")) { if (file_exists("data/config/auto_install.conf.php")) {
require_once "data/config/auto_install.conf.php"; require_once "data/config/auto_install.conf.php";
} elseif (@$_POST["database_type"] == "sqlite") { } elseif (@$_POST["database_type"] == DatabaseDriver::SQLITE) {
$id = bin2hex(random_bytes(5)); $id = bin2hex(random_bytes(5));
define('DATABASE_DSN', "sqlite:data/shimmie.{$id}.sqlite"); 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'])) { } 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(); $drivers = PDO::getAvailableDrivers();
if ( if (
!in_array("mysql", $drivers) && !in_array(DatabaseDriver::MYSQL, $drivers) &&
!in_array("pgsql", $drivers) && !in_array(DatabaseDriver::PGSQL, $drivers) &&
!in_array("sqlite", $drivers) !in_array(DatabaseDriver::SQLITE, $drivers)
) { ) {
$errors[] = " $errors[] = "
No database connection library could be found; shimmie needs No database connection library could be found; shimmie needs
@ -163,9 +163,9 @@ function ask_questions()
"; ";
} }
$db_m = in_array("mysql", $drivers) ? '<option value="mysql">MySQL</option>' : ""; $db_m = in_array(DatabaseDriver::MYSQL, $drivers) ? '<option value="'. DatabaseDriver::MYSQL .'">MySQL</option>' : "";
$db_p = in_array("pgsql", $drivers) ? '<option value="pgsql">PostgreSQL</option>' : ""; $db_p = in_array(DatabaseDriver::PGSQL, $drivers) ? '<option value="'. DatabaseDriver::PGSQL .'">PostgreSQL</option>' : "";
$db_s = in_array("sqlite", $drivers) ? '<option value="sqlite">SQLite</option>' : ""; $db_s = in_array(DatabaseDriver::SQLITE, $drivers) ? '<option value="'. DatabaseDriver::SQLITE .'">SQLite</option>' : "";
$warn_msg = $warnings ? "<h3>Warnings</h3>".implode("\n<p>", $warnings) : ""; $warn_msg = $warnings ? "<h3>Warnings</h3>".implode("\n<p>", $warnings) : "";
$err_msg = $errors ? "<h3>Errors</h3>".implode("\n<p>", $errors) : ""; $err_msg = $errors ? "<h3>Errors</h3>".implode("\n<p>", $errors) : "";

View File

@ -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 public function set_default_string(string $name, string $value): void
{ {
if (is_null($this->get($name))) { if (is_null($this->get($name))) {
@ -170,6 +177,11 @@ abstract class BaseConfig implements Config
return (int)($this->get($name, $default)); 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 public function get_string(string $name, ?string $default=null): ?string
{ {
return $this->get($name, $default); return $this->get($name, $default);

View File

@ -1,9 +1,17 @@
<?php <?php
abstract class DatabaseDriver
{
public const MYSQL = "mysql";
public const PGSQL = "pgsql";
public const SQLITE = "sqlite";
}
/** /**
* A class for controlled database access * A class for controlled database access
*/ */
class Database class Database
{ {
/** /**
* The PDO database connection object, for anyone who wants direct access. * The PDO database connection object, for anyone who wants direct access.
* @var null|PDO * @var null|PDO
@ -72,7 +80,7 @@ class Database
// https://bugs.php.net/bug.php?id=70221 // https://bugs.php.net/bug.php?id=70221
$ka = DATABASE_KA; $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() == DatabaseDriver::SQLITE) {
$ka = false; $ka = false;
} }
@ -96,11 +104,11 @@ class Database
throw new SCoreException("Can't figure out database engine"); throw new SCoreException("Can't figure out database engine");
} }
if ($db_proto === "mysql") { if ($db_proto === DatabaseDriver::MYSQL) {
$this->engine = new MySQL(); $this->engine = new MySQL();
} elseif ($db_proto === "pgsql") { } elseif ($db_proto === DatabaseDriver::PGSQL) {
$this->engine = new PostgreSQL(); $this->engine = new PostgreSQL();
} elseif ($db_proto === "sqlite") { } elseif ($db_proto === DatabaseDriver::SQLITE) {
$this->engine = new SQLite(); $this->engine = new SQLite();
} else { } else {
die('Unknown PDO driver: '.$db_proto); die('Unknown PDO driver: '.$db_proto);
@ -296,7 +304,7 @@ class Database
*/ */
public function get_last_insert_id(string $seq): int public function get_last_insert_id(string $seq): int
{ {
if ($this->engine->name == "pgsql") { if ($this->engine->name == DatabaseDriver::PGSQL) {
return $this->db->lastInsertId($seq); return $this->db->lastInsertId($seq);
} else { } else {
return $this->db->lastInsertId(); return $this->db->lastInsertId();
@ -326,15 +334,15 @@ class Database
$this->connect_db(); $this->connect_db();
} }
if ($this->engine->name === "mysql") { if ($this->engine->name === DatabaseDriver::MYSQL) {
return count( return count(
$this->get_all("SHOW TABLES") $this->get_all("SHOW TABLES")
); );
} elseif ($this->engine->name === "pgsql") { } elseif ($this->engine->name === DatabaseDriver::PGSQL) {
return count( return count(
$this->get_all("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'") $this->get_all("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")
); );
} elseif ($this->engine->name === "sqlite") { } elseif ($this->engine->name === DatabaseDriver::SQLITE) {
return count( return count(
$this->get_all("SELECT name FROM sqlite_master WHERE type = 'table'") $this->get_all("SELECT name FROM sqlite_master WHERE type = 'table'")
); );

View File

@ -22,7 +22,7 @@ class DBEngine
class MySQL extends DBEngine class MySQL extends DBEngine
{ {
/** @var string */ /** @var string */
public $name = "mysql"; public $name = DatabaseDriver::MYSQL;
public function init(PDO $db) public function init(PDO $db)
{ {
@ -54,7 +54,7 @@ class MySQL extends DBEngine
class PostgreSQL extends DBEngine class PostgreSQL extends DBEngine
{ {
/** @var string */ /** @var string */
public $name = "pgsql"; public $name = DatabaseDriver::PGSQL;
public function init(PDO $db) public function init(PDO $db)
{ {
@ -136,7 +136,7 @@ function _ln($n)
class SQLite extends DBEngine class SQLite extends DBEngine
{ {
/** @var string */ /** @var string */
public $name = "sqlite"; public $name = DatabaseDriver::SQLITE;
public function init(PDO $db) public function init(PDO $db)
{ {

View File

@ -182,7 +182,7 @@ abstract class DataHandlerExtension extends Extension
// even more hax.. // even more hax..
$event->metadata['tags'] = $existing->get_tag_list(); $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)) { if (is_null($image)) {
throw new UploadException("Data handler failed to create image object from data"); throw new UploadException("Data handler failed to create image object from data");
@ -192,13 +192,14 @@ abstract class DataHandlerExtension extends Extension
send_event($ire); send_event($ire);
$event->image_id = $image_id; $event->image_id = $image_id;
} else { } 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)) { if (is_null($image)) {
throw new UploadException("Data handler failed to create image object from data"); throw new UploadException("Data handler failed to create image object from data");
} }
$iae = new ImageAdditionEvent($image); $iae = new ImageAdditionEvent($image);
send_event($iae); send_event($iae);
$event->image_id = $iae->image->id; $event->image_id = $iae->image->id;
$event->merged = $iae->merged;
// Rating Stuff. // Rating Stuff.
if (!empty($event->metadata['rating'])) { if (!empty($event->metadata['rating'])) {
@ -222,13 +223,13 @@ abstract class DataHandlerExtension extends Extension
$result = false; $result = false;
if ($this->supported_ext($event->type)) { if ($this->supported_ext($event->type)) {
if ($event->force) { if ($event->force) {
$result = $this->create_thumb($event->hash); $result = $this->create_thumb($event->hash, $event->type);
} else { } else {
$outname = warehouse_path("thumbs", $event->hash); $outname = warehouse_path(Image::THUMBNAIL_DIR, $event->hash);
if (file_exists($outname)) { if (file_exists($outname)) {
return; return;
} }
$result = $this->create_thumb($event->hash); $result = $this->create_thumb($event->hash, $event->type);
} }
} }
if ($result) { if ($result) {
@ -256,5 +257,5 @@ abstract class DataHandlerExtension extends Extension
abstract protected function supported_ext(string $ext): bool; abstract protected function supported_ext(string $ext): bool;
abstract protected function check_contents(string $tmpname): bool; abstract protected function check_contents(string $tmpname): bool;
abstract protected function create_image_from_data(string $filename, array $metadata); 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;
} }

View File

@ -11,6 +11,8 @@ class ImageAdditionEvent extends Event
/** @var Image */ /** @var Image */
public $image; public $image;
public $merged = false;
/** /**
* Inserts a new image into the database with its associated * Inserts a new image into the database with its associated
* information. Also calls TagSetEvent to set the tags for * information. Also calls TagSetEvent to set the tags for

View File

@ -10,6 +10,10 @@
*/ */
class Image class Image
{ {
public const DATA_DIR = "data";
public const IMAGE_DIR = "images";
public const THUMBNAIL_DIR = "thumbs";
private static $tag_n = 0; // temp hack private static $tag_n = 0; // temp hack
public static $order_sql = null; // this feels ugly public static $order_sql = null; // this feels ugly
@ -552,7 +556,7 @@ class Image
*/ */
public function get_image_filename(): string public function get_image_filename(): string
{ {
return warehouse_path("images", $this->hash); return warehouse_path(self::IMAGE_DIR, $this->hash);
} }
/** /**
@ -560,7 +564,7 @@ class Image
*/ */
public function get_thumb_filename(): string public function get_thumb_filename(): string
{ {
return warehouse_path("thumbs", $this->hash); return warehouse_path(self::THUMBNAIL_DIR, $this->hash);
} }
/** /**
@ -640,7 +644,7 @@ class Image
public function delete_tags_from_image(): void public function delete_tags_from_image(): void
{ {
global $database; global $database;
if ($database->get_driver_name() == "mysql") { if ($database->get_driver_name() == DatabaseDriver::MYSQL) {
//mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this //mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this
$database->execute( $database->execute(
" "
@ -917,7 +921,7 @@ class Image
// more than one positive tag, or more than zero negative tags // more than one positive tag, or more than zero negative tags
else { else {
if ($database->get_driver_name() === "mysql") { if ($database->get_driver_name() === DatabaseDriver::MYSQL) {
$query = Image::build_ugly_search_querylet($tag_conditions); $query = Image::build_ugly_search_querylet($tag_conditions);
} else { } else {
$query = Image::build_accurate_search_querylet($tag_conditions); $query = Image::build_accurate_search_querylet($tag_conditions);

View File

@ -7,11 +7,12 @@
* Move a file from PHP's temporary area into shimmie's image storage * Move a file from PHP's temporary area into shimmie's image storage
* hierarchy, or throw an exception trying. * hierarchy, or throw an exception trying.
* *
* @param DataUploadEvent $event
* @throws UploadException * @throws UploadException
*/ */
function move_upload_to_archive(DataUploadEvent $event): void 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)) { if (!@copy($event->tmpname, $target)) {
$errors = error_get_last(); $errors = error_get_last();
throw new UploadException( throw new UploadException(
@ -24,7 +25,8 @@ function move_upload_to_archive(DataUploadEvent $event): void
/** /**
* Add a directory full of images * Add a directory full of images
* *
* #return string[] * @param string $base
* @return array
*/ */
function add_dir(string $base): array function add_dir(string $base): array
{ {
@ -48,6 +50,14 @@ function add_dir(string $base): array
return $results; 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 function add_image(string $tmpname, string $filename, string $tags): void
{ {
assert(file_exists($tmpname)); assert(file_exists($tmpname));
@ -65,10 +75,15 @@ function add_image(string $tmpname, string $filename, string $tags): void
send_event($event); 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); $mime = mime_content_type($file_path);
if (!empty($mime)) { if (!empty($mime)) {
$ext = get_extension($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 * 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; global $config;
@ -105,8 +124,15 @@ function get_thumbnail_size(int $orig_width, int $orig_height): array
$orig_height = $orig_width * 5; $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); $xscale = ($max_height / $orig_height);
$yscale = ($max_width / $orig_width); $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 * Fetches the thumbnails height and width settings and applies the High-DPI scaling setting before returning the dimensions.
* into the configured thumbnail square, with ratio intact, using thumb_scaling
* *
* #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 function get_thumbnail_max_size_scaled(): array
{ {
global $config; global $config;
@ -168,12 +160,19 @@ function get_thumbnail_max_size_scaled(): array
return [$max_width, $max_height]; return [$max_width, $max_height];
} }
function create_thumbnail_convert($hash): bool /**
* 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, $input_type = ""): bool
{ {
global $config; global $config;
$inname = warehouse_path("images", $hash); $inname = warehouse_path(Image::IMAGE_DIR, $hash);
$outname = warehouse_path("thumbs", $hash); $outname = warehouse_path(Image::THUMBNAIL_DIR, $hash);
$q = $config->get_int("thumb_quality"); $q = $config->get_int("thumb_quality");
$convert = $config->get_string("thumb_convert_path"); $convert = $config->get_string("thumb_convert_path");
@ -187,9 +186,7 @@ function create_thumbnail_convert($hash): bool
//$cmd = sprintf($format, $convert, $inname); //$cmd = sprintf($format, $convert, $inname);
//$size = shell_exec($cmd); //$size = shell_exec($cmd);
//$size = explode(" ", trim($size)); //$size = explode(" ", trim($size));
$tsize = get_thumbnail_max_size_scaled(); list($w, $h) = get_thumbnail_max_size_scaled();
$w = $tsize[0];
$h = $tsize[1];
// running the call with cmd.exe requires quoting for our paths // running the call with cmd.exe requires quoting for our paths
@ -204,13 +201,18 @@ function create_thumbnail_convert($hash): bool
if ($type=="webp") { if ($type=="webp") {
$bg = "none"; $bg = "none";
} }
$format = '"%s" -flatten -strip -thumbnail %ux%u%s -quality %u -background %s "%s[0]" %s:"%s"'; if(!empty($input_type)) {
$input_type = $input_type.":";
$cmd = sprintf($format, $convert, $w, $h, $options, $q, $bg, $inname, $type, $outname); }
$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 $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); exec($cmd, $output, $ret);
if ($ret!=0) {
log_debug('handle_pixel', "Generating thumbnail with command `$cmd`, returns $ret"); 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)) { if ($config->get_bool("thumb_optim", false)) {
exec("jpegoptim $outname", $output, $ret); exec("jpegoptim $outname", $output, $ret);
@ -219,6 +221,12 @@ function create_thumbnail_convert($hash): bool
return true; return true;
} }
/**
* Creates a thumbnail using ffmpeg.
*
* @param $hash
* @return bool true if successful, false if not.
*/
function create_thumbnail_ffmpeg($hash): bool function create_thumbnail_ffmpeg($hash): bool
{ {
global $config; global $config;
@ -228,11 +236,11 @@ function create_thumbnail_ffmpeg($hash): bool
return false; return false;
} }
$inname = warehouse_path("images", $hash); $inname = warehouse_path(Image::IMAGE_DIR, $hash);
$outname = warehouse_path("thumbs", $hash); $outname = warehouse_path(Image::THUMBNAIL_DIR, $hash);
$orig_size = video_size($inname); $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"; $codec = "mjpeg";
$quality = $config->get_int("thumb_quality"); $quality = $config->get_int("thumb_quality");
@ -270,6 +278,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 function video_size(string $filename): array
{ {
global $config; global $config;
@ -307,6 +321,9 @@ function video_size(string $filename): array
* *
* The factor of 2.5 is simply a rough guideline. * The factor of 2.5 is simply a rough guideline.
* http://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize * 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 function calc_memory_use(array $info): int
{ {
@ -320,12 +337,25 @@ function calc_memory_use(array $info): int
return (int)$memory_use; 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( function image_resize_gd(
String $image_filename, String $image_filename,
array $info, array $info,
int $new_width, int $new_width,
int $new_height, int $new_height,
string $output_filename=null, string $output_filename,
string $output_type=null, string $output_type=null,
int $output_quality = 80 int $output_quality = 80
) { ) {
@ -423,7 +453,7 @@ function image_resize_gd(
throw new ImageResizeException("Unable to copy resized image data to new image"); throw new ImageResizeException("Unable to copy resized image data to new image");
} }
$result = false;
switch ($output_type) { switch ($output_type) {
case "bmp": case "bmp":
$result = imagebmp($image_resized, $output_filename, true); $result = imagebmp($image_resized, $output_filename, true);
@ -453,15 +483,20 @@ function image_resize_gd(
} }
} }
function is_animated_gif(String $image_filename) /**
{ * Determines if a file is an animated gif.
$isanigif = 0; *
* @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'))) { if (($fh = @fopen($image_filename, 'rb'))) {
//check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) //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); $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);
} }

View File

@ -26,6 +26,11 @@
* Various other common functions are available as part of the Themelet class. * 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 * Class Page
@ -40,7 +45,7 @@ class Page
/** @name Overall */ /** @name Overall */
//@{ //@{
/** @var string */ /** @var string */
public $mode = "page"; public $mode = PageMode::PAGE;
/** @var string */ /** @var string */
public $type = "text/html; charset=utf-8"; public $type = "text/html; charset=utf-8";
@ -261,7 +266,7 @@ class Page
} }
switch ($this->mode) { switch ($this->mode) {
case "page": case PageMode::PAGE:
if (CACHE_HTTP) { if (CACHE_HTTP) {
header("Vary: Cookie, Accept-Encoding"); header("Vary: Cookie, Accept-Encoding");
if ($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") { if ($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") {
@ -285,14 +290,14 @@ class Page
$layout = new Layout(); $layout = new Layout();
$layout->display_page($page); $layout->display_page($page);
break; break;
case "data": case PageMode::DATA:
header("Content-Length: ".strlen($this->data)); header("Content-Length: ".strlen($this->data));
if (!is_null($this->filename)) { if (!is_null($this->filename)) {
header('Content-Disposition: attachment; filename='.$this->filename); header('Content-Disposition: attachment; filename='.$this->filename);
} }
print $this->data; print $this->data;
break; break;
case "redirect": case PageMode::REDIRECT:
header('Location: '.$this->redirect); header('Location: '.$this->redirect);
print 'You should be redirected to <a href="'.$this->redirect.'">'.$this->redirect.'</a>'; print 'You should be redirected to <a href="'.$this->redirect.'">'.$this->redirect.'</a>';
break; break;

View File

@ -69,7 +69,7 @@ class User
global $config, $database; global $config, $database;
$row = $database->cache->get("user-session:$name-$session"); $row = $database->cache->get("user-session:$name-$session");
if (!$row) { if (!$row) {
if ($database->get_driver_name() === "mysql") { if ($database->get_driver_name() === DatabaseDriver::MYSQL) {
$query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess"; $query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess";
} else { } else {
$query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess"; $query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess";

View File

@ -163,10 +163,13 @@ function warehouse_path(string $base, string $hash, bool $create=true): string
{ {
$ab = substr($hash, 0, 2); $ab = substr($hash, 0, 2);
$cd = substr($hash, 2, 2); $cd = substr($hash, 2, 2);
$pa = Image::DATA_DIR.'/'.$base.'/';
if (WH_SPLITS == 2) { if (WH_SPLITS == 2) {
$pa = 'data/'.$base.'/'.$ab.'/'.$cd.'/'.$hash; $pa .= $ab.'/'.$cd.'/'.$hash;
} else { } else {
$pa = 'data/'.$base.'/'.$ab.'/'.$hash; $pa .= $ab.'/'.$hash;
} }
if ($create && !file_exists(dirname($pa))) { if ($create && !file_exists(dirname($pa))) {
mkdir(dirname($pa), 0755, true); mkdir(dirname($pa), 0755, true);

View File

@ -70,7 +70,7 @@ class AdminPage extends Extension
} }
if ($aae->redirect) { if ($aae->redirect) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin")); $page->set_redirect(make_link("admin"));
} }
} }
@ -149,7 +149,7 @@ class AdminPage extends Extension
send_event(new ImageDeletionEvent($image)); send_event(new ImageDeletionEvent($image));
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/list")); $page->set_redirect(make_link("post/list"));
return false; return false;
} }
@ -201,14 +201,14 @@ class AdminPage extends Extension
$database = $matches['dbname']; $database = $matches['dbname'];
switch ($software) { switch ($software) {
case 'mysql': case DatabaseDriver::MYSQL:
$cmd = "mysqldump -h$hostname -u$username -p$password $database"; $cmd = "mysqldump -h$hostname -u$username -p$password $database";
break; break;
case 'pgsql': case DatabaseDriver::PGSQL:
putenv("PGPASSWORD=$password"); putenv("PGPASSWORD=$password");
$cmd = "pg_dump -h $hostname -U $username $database"; $cmd = "pg_dump -h $hostname -U $username $database";
break; break;
case 'sqlite': case DatabaseDriver::SQLITE:
$cmd = "sqlite3 $database .dump"; $cmd = "sqlite3 $database .dump";
break; break;
default: default:
@ -218,7 +218,7 @@ class AdminPage extends Extension
//FIXME: .SQL dump is empty if cmd doesn't exist //FIXME: .SQL dump is empty if cmd doesn't exist
if ($cmd) { if ($cmd) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("application/x-unknown"); $page->set_type("application/x-unknown");
$page->set_filename('shimmie-'.date('Ymd').'.sql'); $page->set_filename('shimmie-'.date('Ymd').'.sql');
$page->set_data(shell_exec($cmd)); $page->set_data(shell_exec($cmd));
@ -237,13 +237,13 @@ class AdminPage extends Extension
$zip = new ZipArchive; $zip = new ZipArchive;
if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) === true) { if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE) === true) {
foreach ($images as $img) { 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->addFile($img_loc, $img["hash"].".".$img["ext"]);
} }
$zip->close(); $zip->close();
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link($filename)); //TODO: Delete file after downloaded? $page->set_redirect(make_link($filename)); //TODO: Delete file after downloaded?
return false; // we do want a redirect, but a manual one return false; // we do want a redirect, but a manual one
@ -257,7 +257,7 @@ class AdminPage extends Extension
//TODO: Update score_log (Having an optional ID column for score_log would be nice..) //TODO: Update score_log (Having an optional ID column for score_log would be nice..)
preg_match("#^(?P<proto>\w+)\:(?:user=(?P<user>\w+)(?:;|$)|password=(?P<password>\w*)(?:;|$)|host=(?P<host>[\w\.\-]+)(?:;|$)|dbname=(?P<dbname>[\w_]+)(?:;|$))+#", DATABASE_DSN, $matches); preg_match("#^(?P<proto>\w+)\:(?:user=(?P<user>\w+)(?:;|$)|password=(?P<password>\w*)(?:;|$)|host=(?P<host>[\w\.\-]+)(?:;|$)|dbname=(?P<dbname>[\w_]+)(?:;|$))+#", DATABASE_DSN, $matches);
if ($matches['proto'] == "mysql") { if ($matches['proto'] == DatabaseDriver::MYSQL) {
$tables = $database->get_col("SELECT TABLE_NAME $tables = $database->get_col("SELECT TABLE_NAME
FROM information_schema.KEY_COLUMN_USAGE FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = :db WHERE TABLE_SCHEMA = :db
@ -280,9 +280,9 @@ class AdminPage extends Extension
$i++; $i++;
} }
$database->execute("ALTER TABLE images AUTO_INCREMENT=".(count($ids) + 1)); $database->execute("ALTER TABLE images AUTO_INCREMENT=".(count($ids) + 1));
} elseif ($matches['proto'] == "pgsql") { } elseif ($matches['proto'] == DatabaseDriver::PGSQL) {
//TODO: Make this work with PostgreSQL //TODO: Make this work with PostgreSQL
} elseif ($matches['proto'] == "sqlite") { } elseif ($matches['proto'] == DatabaseDriver::SQLITE) {
//TODO: Make this work with SQLite //TODO: Make this work with SQLite
} }
return true; return true;

View File

@ -45,7 +45,7 @@ class AdminPageTheme extends Themelet
$html .= $this->button("Download all images", "download_all_images", false); $html .= $this->button("Download all images", "download_all_images", false);
} }
$html .= $this->button("Download database contents", "database_dump", false); $html .= $this->button("Download database contents", "database_dump", false);
if ($database->get_driver_name() == "mysql") { if ($database->get_driver_name() == DatabaseDriver::MYSQL) {
$html .= $this->button("Reset image IDs", "reset_image_ids", true); $html .= $this->button("Reset image IDs", "reset_image_ids", true);
} }
$page->add_block(new Block("Misc Admin Tools", $html)); $page->add_block(new Block("Misc Admin Tools", $html));

View File

@ -41,7 +41,7 @@ class AliasEditor extends Extension
try { try {
$aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); $aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']);
send_event($aae); send_event($aae);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("alias/list")); $page->set_redirect(make_link("alias/list"));
} catch (AddAliasException $ex) { } catch (AddAliasException $ex) {
$this->theme->display_error(500, "Error adding alias", $ex->getMessage()); $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']]); $database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", ["oldtag" => $_POST['oldtag']]);
log_info("alias_editor", "Deleted alias for ".$_POST['oldtag'], "Deleted alias"); 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")); $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); $this->theme->display_aliases($alias, $page_number + 1, $total_pages);
} elseif ($event->get_arg(0) == "export") { } elseif ($event->get_arg(0) == "export") {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("text/csv"); $page->set_type("text/csv");
$page->set_filename("aliases.csv"); $page->set_filename("aliases.csv");
$page->set_data($this->get_alias_csv($database)); $page->set_data($this->get_alias_csv($database));
@ -91,7 +91,7 @@ class AliasEditor extends Extension
$contents = file_get_contents($tmp); $contents = file_get_contents($tmp);
$this->add_alias_csv($database, $contents); $this->add_alias_csv($database, $contents);
log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many? 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")); $page->set_redirect(make_link("alias/list"));
} else { } else {
$this->theme->display_error(400, "No File Specified", "You have to upload a file"); $this->theme->display_error(400, "No File Specified", "You have to upload a file");

View File

@ -172,7 +172,7 @@ class Artists extends Extension
} }
case "new_artist": case "new_artist":
{ {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/new")); $page->set_redirect(make_link("artist/new"));
break; break;
} }
@ -183,7 +183,7 @@ class Artists extends Extension
if ($newArtistID == -1) { if ($newArtistID == -1) {
$this->theme->display_error(400, "Error", "Error when entering artist data."); $this->theme->display_error(400, "Error", "Error when entering artist data.");
} else { } else {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$newArtistID)); $page->set_redirect(make_link("artist/view/".$newArtistID));
} }
} else { } else {
@ -238,7 +238,7 @@ class Artists extends Extension
case "edit_artist": case "edit_artist":
{ {
$artistID = $_POST['artist_id']; $artistID = $_POST['artist_id'];
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/edit/".$artistID)); $page->set_redirect(make_link("artist/edit/".$artistID));
break; break;
} }
@ -246,14 +246,14 @@ class Artists extends Extension
{ {
$artistID = int_escape($_POST['id']); $artistID = int_escape($_POST['id']);
$this->update_artist(); $this->update_artist();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
case "nuke_artist": case "nuke_artist":
{ {
$artistID = $_POST['artist_id']; $artistID = $_POST['artist_id'];
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/nuke/".$artistID)); $page->set_redirect(make_link("artist/nuke/".$artistID));
break; break;
} }
@ -261,7 +261,7 @@ class Artists extends Extension
{ {
$artistID = $event->get_arg(1); $artistID = $event->get_arg(1);
$this->delete_artist($artistID); // this will delete the artist, its alias, its urls and its members $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")); $page->set_redirect(make_link("artist/list"));
break; break;
} }
@ -291,7 +291,7 @@ class Artists extends Extension
{ {
$artistID = $_POST['artistID']; $artistID = $_POST['artistID'];
$this->add_alias(); $this->add_alias();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -300,7 +300,7 @@ class Artists extends Extension
$aliasID = $event->get_arg(2); $aliasID = $event->get_arg(2);
$artistID = $this->get_artistID_by_aliasID($aliasID); $artistID = $this->get_artistID_by_aliasID($aliasID);
$this->delete_alias($aliasID); $this->delete_alias($aliasID);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -316,7 +316,7 @@ class Artists extends Extension
$this->update_alias(); $this->update_alias();
$aliasID = int_escape($_POST['aliasID']); $aliasID = int_escape($_POST['aliasID']);
$artistID = $this->get_artistID_by_aliasID($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)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -332,7 +332,7 @@ class Artists extends Extension
{ {
$artistID = $_POST['artistID']; $artistID = $_POST['artistID'];
$this->add_urls(); $this->add_urls();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -341,7 +341,7 @@ class Artists extends Extension
$urlID = $event->get_arg(2); $urlID = $event->get_arg(2);
$artistID = $this->get_artistID_by_urlID($urlID); $artistID = $this->get_artistID_by_urlID($urlID);
$this->delete_url($urlID); $this->delete_url($urlID);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -357,7 +357,7 @@ class Artists extends Extension
$this->update_url(); $this->update_url();
$urlID = int_escape($_POST['urlID']); $urlID = int_escape($_POST['urlID']);
$artistID = $this->get_artistID_by_urlID($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)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -372,7 +372,7 @@ class Artists extends Extension
{ {
$artistID = $_POST['artistID']; $artistID = $_POST['artistID'];
$this->add_members(); $this->add_members();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -381,7 +381,7 @@ class Artists extends Extension
$memberID = int_escape($event->get_arg(2)); $memberID = int_escape($event->get_arg(2));
$artistID = $this->get_artistID_by_memberID($memberID); $artistID = $this->get_artistID_by_memberID($memberID);
$this->delete_member($memberID); $this->delete_member($memberID);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("artist/view/".$artistID)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }
@ -397,7 +397,7 @@ class Artists extends Extension
$this->update_member(); $this->update_member();
$memberID = int_escape($_POST['memberID']); $memberID = int_escape($_POST['memberID']);
$artistID = $this->get_artistID_by_memberID($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)); $page->set_redirect(make_link("artist/view/".$artistID));
break; break;
} }

View File

@ -21,7 +21,7 @@ class AutoComplete extends Extension
return; return;
} }
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("application/json"); $page->set_type("application/json");
$s = strtolower($_GET["s"]); $s = strtolower($_GET["s"]);

View File

@ -61,7 +61,7 @@ class Blocks extends Extension
", [$_POST['pages'], $_POST['title'], $_POST['area'], (int)$_POST['priority'], $_POST['content']]); ", [$_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'].")"); log_info("blocks", "Added Block #".($database->get_last_insert_id('blocks_id_seq'))." (".$_POST['title'].")");
$database->cache->delete("blocks"); $database->cache->delete("blocks");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blocks/list")); $page->set_redirect(make_link("blocks/list"));
} }
} }
@ -81,7 +81,7 @@ class Blocks extends Extension
log_info("blocks", "Updated Block #".$_POST['id']." (".$_POST['title'].")"); log_info("blocks", "Updated Block #".$_POST['id']." (".$_POST['title'].")");
} }
$database->cache->delete("blocks"); $database->cache->delete("blocks");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blocks/list")); $page->set_redirect(make_link("blocks/list"));
} }
} elseif ($event->get_arg(0) == "list") { } elseif ($event->get_arg(0) == "list") {

View File

@ -102,7 +102,7 @@ class Blotter extends Extension
[$entry_text, $important] [$entry_text, $important]
); );
log_info("blotter", "Added Message: $entry_text"); log_info("blotter", "Added Message: $entry_text");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blotter/editor")); $page->set_redirect(make_link("blotter/editor"));
} }
break; break;
@ -119,7 +119,7 @@ class Blotter extends Extension
} }
$database->Execute("DELETE FROM blotter WHERE id=:id", ["id"=>$id]); $database->Execute("DELETE FROM blotter WHERE id=:id", ["id"=>$id]);
log_info("blotter", "Removed Entry #$id"); log_info("blotter", "Removed Entry #$id");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("blotter/editor")); $page->set_redirect(make_link("blotter/editor"));
} }
break; break;

View File

@ -54,7 +54,7 @@ class BrowserSearch extends Extension
"; ";
// And now to send it to the browser // And now to send it to the browser
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("text/xml"); $page->set_type("text/xml");
$page->set_data($xml); $page->set_data($xml);
} elseif ( } elseif (
@ -85,7 +85,7 @@ class BrowserSearch extends Extension
// And now for the final output // And now for the final output
$json_string = "[\"$tag_search\",[\"$json_tag_list\"],[],[]]"; $json_string = "[\"$tag_search\",[\"$json_tag_list\"],[],[]]";
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_data($json_string); $page->set_data($json_string);
} }
} }

View File

@ -171,7 +171,7 @@ class BulkActions extends Extension
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
if (!isset($_SERVER['HTTP_REFERER'])) { if (!isset($_SERVER['HTTP_REFERER'])) {
$_SERVER['HTTP_REFERER'] = make_link(); $_SERVER['HTTP_REFERER'] = make_link();
} }

View File

@ -81,7 +81,7 @@ class BulkAddCSV extends Extension
send_event($ratingevent); send_event($ratingevent);
} }
if (file_exists($thumbfile)) { if (file_exists($thumbfile)) {
copy($thumbfile, warehouse_path("thumbs", $event->hash)); copy($thumbfile, warehouse_path(Image::THUMBNAIL_DIR, $event->hash));
} }
} }
} }

View File

@ -178,7 +178,7 @@ class CommentList extends Extension
$i_iid = int_escape($_POST['image_id']); $i_iid = int_escape($_POST['image_id']);
$cpe = new CommentPostingEvent($_POST['image_id'], $user, $_POST['comment']); $cpe = new CommentPostingEvent($_POST['image_id'], $user, $_POST['comment']);
send_event($cpe); 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")); $page->set_redirect(make_link("post/view/$i_iid#comment_on_$i_iid"));
} catch (CommentPostingException $ex) { } catch (CommentPostingException $ex) {
$this->theme->display_error(403, "Comment Blocked", $ex->getMessage()); $this->theme->display_error(403, "Comment Blocked", $ex->getMessage());
@ -194,7 +194,7 @@ class CommentList extends Extension
if ($event->count_args() === 3) { if ($event->count_args() === 3) {
send_event(new CommentDeletionEvent($event->get_arg(1))); send_event(new CommentDeletionEvent($event->get_arg(1)));
flash_message("Deleted comment"); flash_message("Deleted comment");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
if (!empty($_SERVER['HTTP_REFERER'])) { if (!empty($_SERVER['HTTP_REFERER'])) {
$page->set_redirect($_SERVER['HTTP_REFERER']); $page->set_redirect($_SERVER['HTTP_REFERER']);
} else { } else {
@ -224,7 +224,7 @@ class CommentList extends Extension
} }
flash_message("Deleted $num comments"); flash_message("Deleted $num comments");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin")); $page->set_redirect(make_link("admin"));
} else { } else {
$this->theme->display_permission_denied(); $this->theme->display_permission_denied();
@ -480,14 +480,14 @@ class CommentList extends Extension
global $config, $database; global $config, $database;
// sqlite fails at intervals // sqlite fails at intervals
if ($database->get_driver_name() === "sqlite") { if ($database->get_driver_name() === DatabaseDriver::SQLITE) {
return false; return false;
} }
$window = int_escape($config->get_int('comment_window')); $window = int_escape($config->get_int('comment_window'));
$max = int_escape($config->get_int('comment_limit')); $max = int_escape($config->get_int('comment_limit'));
if ($database->get_driver_name() == "mysql") { if ($database->get_driver_name() == DatabaseDriver::MYSQL) {
$window_sql = "interval $window minute"; $window_sql = "interval $window minute";
} else { } else {
$window_sql = "interval '$window minute'"; $window_sql = "interval '$window minute'";

View File

@ -1,18 +1,28 @@
<?php <?php
/* /*
* Name: Cron Uploader * Name: Cron Uploader
* Author: YaoiFox <admin@yaoifox.com> * Authors: YaoiFox <admin@yaoifox.com>, Matthew Barbour <matthew@darkholme.net>
* Link: http://www.yaoifox.com/ * Link: http://www.yaoifox.com/
* License: GPLv2 * License: GPLv2
* Description: Uploads images automatically using Cron Jobs * Description: Uploads images automatically using Cron Jobs
* Documentation: Installation guide: activate this extension and navigate to www.yoursite.com/cron_upload * Documentation: Installation guide: activate this extension and navigate to www.yoursite.com/cron_upload
*/ */
class CronUploader extends Extension 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: 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: Change logging to MySQL + display log at /cron_upload
// TODO: Move stuff to theme.php // 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 * Lists all log events this session
* @var string * @var string
@ -46,12 +56,23 @@ class CronUploader extends Extension
global $config, $user; global $config, $user;
if ($event->page_matches("cron_upload")) { 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 the key is in the url, upload
if ($this->upload_key != "" && $event->get_arg(0) == $this->upload_key) { if ($this->upload_key != "" && $event->get_arg(0) == $this->upload_key) {
// log in as admin // log in as admin
$this->process_upload(); // Start upload $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 {
$this->process_upload(); // Start upload
} finally {
flock($lockfile, LOCK_UN);
fclose($lockfile);
}
} elseif ($user->is_admin()) { } elseif ($user->is_admin()) {
$this->set_dir(); $this->set_dir();
$this->display_documentation(); $this->display_documentation();
@ -65,9 +86,9 @@ class CronUploader extends Extension
$this->set_dir(); // Determines path to cron_uploader_dir $this->set_dir(); // Determines path to cron_uploader_dir
$queue_dir = $this->root_dir . "/queue"; $queue_dir = $this->root_dir . "/" . self::QUEUE_DIR;
$uploaded_dir = $this->root_dir . "/uploaded"; $uploaded_dir = $this->root_dir . "/" . self::UPLOADED_DIR;
$failed_dir = $this->root_dir . "/failed_to_upload"; $failed_dir = $this->root_dir . "/" . self::FAILED_DIR;
$queue_dirinfo = $this->scan_dir($queue_dir); $queue_dirinfo = $this->scan_dir($queue_dir);
$uploaded_dirinfo = $this->scan_dir($uploaded_dir); $uploaded_dirinfo = $this->scan_dir($uploaded_dir);
@ -131,6 +152,8 @@ class CronUploader extends Extension
<br />This link can be found under 'Cron Command' in the board config, just remove the 'wget ' part and only the url remains. <br />This link can be found under 'Cron Command' in the board config, just remove the 'wget ' part and only the url remains.
<br />(<b>$cron_url</b>)"; <br />(<b>$cron_url</b>)";
$page->set_title("Cron Uploader");
$page->set_heading("Cron Uploader");
$block = new Block("Cron Uploader", $info_html, "main", 10); $block = new Block("Cron Uploader", $info_html, "main", 10);
$block_install = new Block("Installation Guide", $install_html, "main", 20); $block_install = new Block("Installation Guide", $install_html, "main", 20);
@ -142,13 +165,14 @@ class CronUploader extends Extension
{ {
global $config; global $config;
// Set default values // Set default values
$this->upload_key = $config->get_string("cron_uploader_key", ""); $config->set_default_int(self::CONFIG_COUNT, 1);
if (strlen($this->upload_key)<=0) { $this->set_dir();
$this->upload_key = $config->get_string(self::CONFIG_KEY, "");
if (empty($this->upload_key)) {
$this->upload_key = $this->generate_key(); $this->upload_key = $this->generate_key();
$config->set_default_int('cron_uploader_count', 1); $config->set_string(self::CONFIG_KEY, $this->upload_key);
$config->set_default_string('cron_uploader_key', $this->upload_key);
$this->set_dir();
} }
} }
@ -162,10 +186,10 @@ class CronUploader extends Extension
$sb = new SetupBlock("Cron Uploader"); $sb = new SetupBlock("Cron Uploader");
$sb->add_label("<b>Settings</b><br>"); $sb->add_label("<b>Settings</b><br>");
$sb->add_int_option("cron_uploader_count", "How many to upload each time"); $sb->add_int_option(self::CONFIG_COUNT, "How many to upload each time");
$sb->add_text_option("cron_uploader_dir", "<br>Set Cron Uploader root directory<br>"); $sb->add_text_option(self::CONFIG_DIR, "<br>Set Cron Uploader root directory<br>");
$sb->add_label("<br>Cron Command: <input type='text' size='60' value='$cron_cmd'><br> $sb->add_label("<br>Cron Command: <input type='text' size='60' readonly='readonly' value='" . html_escape($cron_cmd) . "'><br>
Create a cron job with the command above.<br/> Create a cron job with the command above.<br/>
<a href='$documentation_link'>Read the documentation</a> if you're not sure what to do."); <a href='$documentation_link'>Read the documentation</a> if you're not sure what to do.");
@ -181,7 +205,7 @@ class CronUploader extends Extension
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = ''; $randomString = '';
for ($i = 0; $i < $length; $i ++) { for ($i = 0; $i < $length; $i++) {
$randomString .= $characters [rand(0, strlen($characters) - 1)]; $randomString .= $characters [rand(0, strlen($characters) - 1)];
} }
@ -196,23 +220,23 @@ class CronUploader extends Extension
global $config; global $config;
// Determine directory (none = default) // 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 // Sets new default dir if not in config yet/anymore
if ($dir == "") { if ($dir == "") {
$dir = data_path("cron_uploader"); $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 // Make the directory if it doesn't exist yet
if (!is_dir($dir . "/queue/")) { if (!is_dir($dir . "/" . self::QUEUE_DIR . "/")) {
mkdir($dir . "/queue/", 0775, true); mkdir($dir . "/" . self::QUEUE_DIR . "/", 0775, true);
} }
if (!is_dir($dir . "/uploaded/")) { if (!is_dir($dir . "/" . self::UPLOADED_DIR . "/")) {
mkdir($dir . "/uploaded/", 0775, true); mkdir($dir . "/" . self::UPLOADED_DIR . "/", 0775, true);
} }
if (!is_dir($dir . "/failed_to_upload/")) { if (!is_dir($dir . "/" . self::FAILED_DIR . "/")) {
mkdir($dir . "/failed_to_upload/", 0775, true); mkdir($dir . "/" . self::FAILED_DIR . "/", 0775, true);
} }
$this->root_dir = $dir; $this->root_dir = $dir;
@ -224,11 +248,11 @@ class CronUploader extends Extension
*/ */
public function scan_dir(string $path): array public function scan_dir(string $path): array
{ {
$bytestotal=0; $bytestotal = 0;
$nbfiles=0; $nbfiles = 0;
$ite=new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS); $ite = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
foreach (new RecursiveIteratorIterator($ite) as $filename=>$cur) { foreach (new RecursiveIteratorIterator($ite) as $filename => $cur) {
$filesize = $cur->getSize(); $filesize = $cur->getSize();
$bytestotal += $filesize; $bytestotal += $filesize;
$nbfiles++; $nbfiles++;
@ -236,7 +260,7 @@ class CronUploader extends Extension
$size_mb = $bytestotal / 1048576; // to mb $size_mb = $bytestotal / 1048576; // to mb
$size_mb = number_format($size_mb, 2, '.', ''); $size_mb = number_format($size_mb, 2, '.', '');
return ['total_files'=>$nbfiles,'total_mb'=>$size_mb]; return ['total_files' => $nbfiles, 'total_mb' => $size_mb];
} }
/** /**
@ -246,15 +270,15 @@ class CronUploader extends Extension
{ {
global $config, $database; 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(); $this->generate_image_queue();
// Gets amount of imgs to upload // Gets amount of imgs to upload
if ($upload_count == 0) { 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 // Throw exception if there's nothing in the queue
@ -271,18 +295,17 @@ class CronUploader extends Extension
$added = 0; $added = 0;
$failed = 0; $failed = 0;
$failedItems = [];
// Upload the file(s) // 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); $img = array_pop($this->image_queue);
try { try {
$database->beginTransaction(); $database->beginTransaction();
$this->add_upload_info("Adding file: {$img[1]} - tags: {$img[2]}");
$result = $this->add_image($img[0], $img[1], $img[2]); $result = $this->add_image($img[0], $img[1], $img[2]);
$database->commit(); $database->commit();
$this->move_uploaded($img[0], $img[1], $output_subdir, false); $this->move_uploaded($img[0], $img[1], $output_subdir, false);
if ($result==null) { if ($result->merged) {
$merged++; $merged++;
} else { } else {
$added++; $added++;
@ -290,13 +313,9 @@ class CronUploader extends Extension
} catch (Exception $e) { } catch (Exception $e) {
$failed++; $failed++;
$this->move_uploaded($img[0], $img[1], $output_subdir, true); $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()); $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 { try {
$database->rollback(); $database->rollback();
} catch (Exception $e) { } catch (Exception $e) {
@ -310,11 +329,11 @@ class CronUploader extends Extension
$msgNumber = $this->add_upload_info("Items failed: $failed"); $msgNumber = $this->add_upload_info("Items failed: $failed");
// Display & save upload log // Display & save upload log
$this->handle_log(); $this->handle_log();
return true; return true;
} }
private function move_uploaded($path, $filename, $output_subdir, $corrupt = false) private function move_uploaded($path, $filename, $output_subdir, $corrupt = false)
@ -329,20 +348,20 @@ class CronUploader extends Extension
// Determine which dir to move to // Determine which dir to move to
if ($corrupt) { if ($corrupt) {
// Move to corrupt dir // Move to corrupt dir
$newDir .= "/failed_to_upload/".$output_subdir.$relativeDir; $newDir .= "/" . self::FAILED_DIR . "/" . $output_subdir . $relativeDir;
$info = "ERROR: Image was not uploaded."; $info = "ERROR: Image was not uploaded.";
} else { } else {
$newDir .= "/uploaded/".$output_subdir.$relativeDir; $newDir .= "/" . self::UPLOADED_DIR . "/" . $output_subdir . $relativeDir;
$info = "Image successfully uploaded. "; $info = "Image successfully uploaded. ";
} }
$newDir = str_replace("//", "/", $newDir."/"); $newDir = str_replace("//", "/", $newDir . "/");
if (!is_dir($newDir)) { if (!is_dir($newDir)) {
mkdir($newDir, 0775, true); mkdir($newDir, 0775, true);
} }
// move file to correct dir // 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\"."); $this->add_upload_info($info . "Image \"$filename\" moved from queue to \"$newDir\".");
} }
@ -350,17 +369,22 @@ class CronUploader extends Extension
/** /**
* Generate the necessary DataUploadEvent for a given image and tags. * 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)); assert(file_exists($tmpname));
$tagArray = Tag::explode($tags);
if(count($tagArray)==0) {
$tagArray[] = "tagme";
}
$pathinfo = pathinfo($filename); $pathinfo = pathinfo($filename);
$metadata = []; $metadata = [];
$metadata ['filename'] = $pathinfo ['basename']; $metadata ['filename'] = $pathinfo ['basename'];
if (array_key_exists('extension', $pathinfo)) { if (array_key_exists('extension', $pathinfo)) {
$metadata ['extension'] = $pathinfo ['extension']; $metadata ['extension'] = $pathinfo ['extension'];
} }
$metadata ['tags'] = Tag::explode($tags); $metadata ['tags'] = $tagArray; // doesn't work when not logged in here, handled below
$metadata ['source'] = null; $metadata ['source'] = null;
$event = new DataUploadEvent($tmpname, $metadata); $event = new DataUploadEvent($tmpname, $metadata);
send_event($event); send_event($event);
@ -369,26 +393,31 @@ class CronUploader extends Extension
$infomsg = ""; // Will contain info message $infomsg = ""; // Will contain info message
if ($event->image_id == -1) { if ($event->image_id == -1) {
throw new Exception("File type not recognised. Filename: {$filename}"); throw new Exception("File type not recognised. Filename: {$filename}");
} elseif ($event->image_id == null) { } elseif ($event->merged === true) {
$infomsg = "Image merged. Filename: {$filename}"; $infomsg = "Image merged. ID: {$event->image_id} Filename: {$filename}";
} else { } else {
$infomsg = "Image uploaded. ID: {$event->image_id} - Filename: {$filename}"; $infomsg = "Image uploaded. ID: {$event->image_id} - Filename: {$filename}";
} }
$msgNumber = $this->add_upload_info($infomsg); $msgNumber = $this->add_upload_info($infomsg);
return $event->image_id;
// Set tags
$img = Image::by_id($event->image_id);
$img->set_tags(array_merge($tagArray, $img->get_tag_array()));
return $event;
} }
private function generate_image_queue(): void private function generate_image_queue(): void
{ {
$base = $this->root_dir . "/queue"; $base = $this->root_dir . "/" . self::QUEUE_DIR;
if (! is_dir($base)) { if (!is_dir($base)) {
$this->add_upload_info("Image Queue Directory could not be found at \"$base\"."); $this->add_upload_info("Image Queue Directory could not be found at \"$base\".");
return; return;
} }
$ite=new RecursiveDirectoryIterator($base, FilesystemIterator::SKIP_DOTS); $ite = new RecursiveDirectoryIterator($base, FilesystemIterator::SKIP_DOTS);
foreach (new RecursiveIteratorIterator($ite) as $fullpath=>$cur) { foreach (new RecursiveIteratorIterator($ite) as $fullpath => $cur) {
if (!is_link($fullpath) && !is_dir($fullpath)) { if (!is_link($fullpath) && !is_dir($fullpath)) {
$pathinfo = pathinfo($fullpath); $pathinfo = pathinfo($fullpath);
@ -396,9 +425,9 @@ class CronUploader extends Extension
$tags = path_to_tags($relativePath); $tags = path_to_tags($relativePath);
$img = [ $img = [
0 => $fullpath, 0 => $fullpath,
1 => $pathinfo ["basename"], 1 => $pathinfo ["basename"],
2 => $tags 2 => $tags
]; ];
array_push($this->image_queue, $img); array_push($this->image_queue, $img);
} }
@ -411,14 +440,14 @@ class CronUploader extends Extension
private function add_upload_info(string $text, int $addon = 0): int private function add_upload_info(string $text, int $addon = 0): int
{ {
$info = $this->upload_info; $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 function is not used
if ($addon == 0) { if ($addon == 0) {
$this->upload_info .= "$time $text\r\n"; $this->upload_info .= "$time $text\r\n";
// Returns the number of the current line // 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; return $currentLine;
} }
@ -438,7 +467,7 @@ class CronUploader extends Extension
global $page; global $page;
// Display message // Display message
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("text/plain"); $page->set_type("text/plain");
$page->set_data($this->upload_info); $page->set_data($this->upload_info);
@ -451,7 +480,7 @@ class CronUploader extends Extension
$prev_content = ""; $prev_content = "";
} }
$content = $prev_content ."\r\n".$this->upload_info; $content = $prev_content . "\r\n" . $this->upload_info;
file_put_contents($log_path, $content); file_put_contents($log_path, $content);
} }
} }

View File

@ -60,7 +60,7 @@ class DanbooruApi extends Extension
private function api_danbooru(PageRequestEvent $event) private function api_danbooru(PageRequestEvent $event)
{ {
global $page; 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'))) { 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 // 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 // This redirects that to http://shimmie/post/view/123
elseif (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'show')) { elseif (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'show')) {
$fixedlocation = make_link("post/view/" . $event->get_arg(3)); $fixedlocation = make_link("post/view/" . $event->get_arg(3));
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect($fixedlocation); $page->set_redirect($fixedlocation);
} }
} }

View File

@ -26,7 +26,7 @@ class DowntimeTheme extends Themelet
$login_link = make_link("user_admin/login"); $login_link = make_link("user_admin/login");
$auth = $user->get_auth_html(); $auth = $user->get_auth_html();
$page->set_mode('data'); $page->set_mode(PageMode::DATA);
$page->set_code(503); $page->set_code(503);
$page->set_data( $page->set_data(
<<<EOD <<<EOD

View File

@ -18,7 +18,7 @@ class EmoticonListTheme extends Themelet
} }
$html .= "</tr></table>"; $html .= "</tr></table>";
$html .= "</body></html>"; $html .= "</body></html>";
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_data($html); $page->set_data($html);
} }
} }

View File

@ -22,8 +22,7 @@ class ExtensionInfo
public $ext_name; public $ext_name;
public $name; public $name;
public $link; public $link;
public $author; public $authors;
public $email;
public $description; public $description;
public $documentation; public $documentation;
public $version; public $version;
@ -39,8 +38,9 @@ class ExtensionInfo
$this->ext_name = $matches[1]; $this->ext_name = $matches[1];
$this->name = $this->ext_name; $this->name = $this->ext_name;
$this->enabled = $this->is_enabled($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]; $line = $lines[$i];
if (preg_match("/Name: (.*)/", $line, $matches)) { if (preg_match("/Name: (.*)/", $line, $matches)) {
$this->name = $matches[1]; $this->name = $matches[1];
@ -53,25 +53,31 @@ class ExtensionInfo
} }
} elseif (preg_match("/Version: (.*)/", $line, $matches)) { } elseif (preg_match("/Version: (.*)/", $line, $matches)) {
$this->version = $matches[1]; $this->version = $matches[1];
} elseif (preg_match("/Author: (.*) [<\(](.*@.*)[>\)]/", $line, $matches)) { } elseif (preg_match("/Authors?: (.*)/", $line, $matches)) {
$this->author = $matches[1]; $author_list = explode(',', $matches[1]);
$this->email = $matches[2]; foreach ($author_list as $author) {
} elseif (preg_match("/Author: (.*)/", $line, $matches)) { if (preg_match("/(.*) [<\(](.*@.*)[>\)]/", $author, $matches)) {
$this->author = $matches[1]; $this->authors[] = new ExtensionAuthor($matches[1], $matches[2]);
} else {
$this->authors[] = new ExtensionAuthor($author, null);
}
}
} elseif (preg_match("/(.*)Description: ?(.*)/", $line, $matches)) { } elseif (preg_match("/(.*)Description: ?(.*)/", $line, $matches)) {
$this->description = $matches[2]; $this->description = $matches[2];
$start = $matches[1]." "; $start = $matches[1] . " ";
$start_len = strlen($start); $start_len = strlen($start);
while (substr($lines[$i+1], 0, $start_len) == $start) { while (substr($lines[$i + 1], 0, $start_len) == $start) {
$this->description .= " ".substr($lines[$i+1], $start_len); $this->description .= " " . substr($lines[$i + 1], $start_len);
$i++; $i++;
} }
} elseif (preg_match("/(.*)Documentation: ?(.*)/", $line, $matches)) { } elseif (preg_match("/(.*)Documentation: ?(.*)/", $line, $matches)) {
$this->documentation = $matches[2]; $this->documentation = $matches[2];
$start = $matches[1]." "; $start = $matches[1] . " ";
$start_len = strlen($start); $start_len = strlen($start);
while (substr($lines[$i+1], 0, $start_len) == $start) { while (substr($lines[$i + 1], 0, $start_len) == $start) {
$this->documentation .= " ".substr($lines[$i+1], $start_len); $this->documentation .= " " . substr($lines[$i + 1], $start_len);
$i++; $i++;
} }
$this->documentation = str_replace('$site', make_http(get_base_href()), $this->documentation); $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 class ExtManager extends Extension
{ {
public function onPageRequest(PageRequestEvent $event) public function onPageRequest(PageRequestEvent $event)
@ -107,7 +125,7 @@ class ExtManager extends Extension
if (is_writable("data/config")) { if (is_writable("data/config")) {
$this->set_things($_POST); $this->set_things($_POST);
log_warning("ext_manager", "Active extensions changed", "Active extensions changed"); 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")); $page->set_redirect(make_link("ext_manager"));
} else { } else {
$this->theme->display_error( $this->theme->display_error(
@ -166,7 +184,7 @@ class ExtManager extends Extension
if ($all) { if ($all) {
$exts = zglob("ext/*/main.php"); $exts = zglob("ext/*/main.php");
} else { } else {
$exts = zglob("ext/{".ENABLED_EXTS."}/main.php"); $exts = zglob("ext/{" . ENABLED_EXTS . "}/main.php");
} }
foreach ($exts as $main) { foreach ($exts as $main) {
$extensions[] = new ExtensionInfo($main); $extensions[] = new ExtensionInfo($main);
@ -200,9 +218,9 @@ class ExtManager extends Extension
{ {
file_put_contents( file_put_contents(
"data/config/extensions.conf.php", "data/config/extensions.conf.php",
'<'.'?php'."\n". '<' . '?php' . "\n" .
'define("EXTRA_EXTS", "'.implode(",", $extras).'");'."\n". 'define("EXTRA_EXTS", "' . implode(",", $extras) . '");' . "\n" .
'?'.">" '?' . ">"
); );
// when the list of active extensions changes, we can be // when the list of active extensions changes, we can be

View File

@ -9,7 +9,7 @@ class ExtManagerTheme extends Themelet
{ {
$h_en = $editable ? "<th>Enabled</th>" : ""; $h_en = $editable ? "<th>Enabled</th>" : "";
$html = " $html = "
".make_form(make_link("ext_manager/set"))." " . make_form(make_link("ext_manager/set")) . "
<table id='extensions' class='zebra sortable'> <table id='extensions' class='zebra sortable'>
<thead> <thead>
<tr> <tr>
@ -26,17 +26,17 @@ class ExtManagerTheme extends Themelet
continue; 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_description = html_escape($extension->description);
$h_link = make_link("ext_doc/".url_escape($extension->ext_name)); $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 = ($extension->enabled === true ? " checked='checked'" : ($extension->enabled === false ? "" : " disabled checked='checked'"));
$h_enabled_box = $editable ? "<td><input type='checkbox' name='ext_".html_escape($extension->ext_name)."' id='ext_".html_escape($extension->ext_name)."'$h_enabled></td>" : ""; $h_enabled_box = $editable ? "<td><input type='checkbox' name='ext_" . html_escape($extension->ext_name) . "' id='ext_" . html_escape($extension->ext_name) . "'$h_enabled></td>" : "";
$h_docs = ($extension->documentation ? "<a href='$h_link'>■</a>" : ""); //TODO: A proper "docs" symbol would be preferred here. $h_docs = ($extension->documentation ? "<a href='$h_link'>■</a>" : ""); //TODO: A proper "docs" symbol would be preferred here.
$html .= " $html .= "
<tr data-ext='{$extension->ext_name}'> <tr data-ext='{$extension->ext_name}'>
{$h_enabled_box} {$h_enabled_box}
<td><label for='ext_".html_escape($extension->ext_name)."'>{$h_name}</label></td> <td><label for='ext_" . html_escape($extension->ext_name) . "'>{$h_name}</label></td>
<td>{$h_docs}</td> <td>{$h_docs}</td>
<td style='text-align: left;'>{$h_description}</td> <td style='text-align: left;'>{$h_description}</td>
</tr>"; </tr>";
@ -116,15 +116,24 @@ class ExtManagerTheme extends Themelet
public function display_doc(Page $page, ExtensionInfo $info) public function display_doc(Page $page, ExtensionInfo $info)
{ {
$author = ""; $author = "";
if ($info->author) { if (count($info->authors) > 0) {
if ($info->email) { $author = "<br /><b>Author";
$author = "<br><b>Author:</b> <a href=\"mailto:".html_escape($info->email)."\">".html_escape($info->author)."</a>"; if (count($info->authors) > 1) {
} else { $author .= "s";
$author = "<br><b>Author:</b> ".html_escape($info->author);
} }
$author .= ":</b>";
foreach ($info->authors as $auth) {
if (!empty($auth->email)) {
$author .= "<a href=\"mailto:" . html_escape($auth->email) . "\">" . html_escape($auth->name) . "</a>";
} else {
$author .= html_escape($auth->name);
}
}
} }
$version = ($info->version) ? "<br><b>Version:</b> ".html_escape($info->version) : "";
$link = ($info->link) ? "<br><b>Home Page:</b> <a href=\"".html_escape($info->link)."\">Link</a>" : ""; $version = ($info->version) ? "<br><b>Version:</b> " . html_escape($info->version) : "";
$link = ($info->link) ? "<br><b>Home Page:</b> <a href=\"" . html_escape($info->link) . "\">Link</a>" : "";
$doc = $info->documentation; $doc = $info->documentation;
$html = " $html = "
<div style='margin: auto; text-align: left; width: 512px;'> <div style='margin: auto; text-align: left; width: 512px;'>
@ -133,10 +142,10 @@ class ExtManagerTheme extends Themelet
$link $link
<p>$doc <p>$doc
<hr> <hr>
<p><a href='".make_link("ext_manager")."'>Back to the list</a> <p><a href='" . make_link("ext_manager") . "'>Back to the list</a>
</div>"; </div>";
$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->set_heading(html_escape($info->name));
$page->add_block(new NavBlock()); $page->add_block(new NavBlock());
$page->add_block(new Block("Documentation", $html)); $page->add_block(new Block("Documentation", $html));

View File

@ -81,7 +81,7 @@ class Favorites extends Extension
log_debug("favourite", "Favourite removed for $image_id", "Favourite removed"); 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")); $page->set_redirect(make_link("post/view/$image_id"));
} }
} }

View File

@ -37,7 +37,7 @@ class Featured extends Extension
if ($id > 0) { if ($id > 0) {
$config->set_int("featured_id", $id); $config->set_int("featured_id", $id);
log_info("featured", "Featured image set to $id", "Featured image set"); 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")); $page->set_redirect(make_link("post/view/$id"));
} }
} }
@ -45,7 +45,7 @@ class Featured extends Extension
if ($event->get_arg(0) == "download") { if ($event->get_arg(0) == "download") {
$image = Image::by_id($config->get_int("featured_id")); $image = Image::by_id($config->get_int("featured_id"));
if (!is_null($image)) { if (!is_null($image)) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type($image->get_mime_type()); $page->set_type($image->get_mime_type());
$page->set_data(file_get_contents($image->get_image_filename())); $page->set_data(file_get_contents($image->get_image_filename()));
} }

View File

@ -139,7 +139,7 @@ class Forum extends Extension
$redirectTo = "forum/view/".$newThreadID."/1"; $redirectTo = "forum/view/".$newThreadID."/1";
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link($redirectTo)); $page->set_redirect(make_link($redirectTo));
break; break;
@ -151,7 +151,7 @@ class Forum extends Extension
$this->delete_post($postID); $this->delete_post($postID);
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/view/".$threadID)); $page->set_redirect(make_link("forum/view/".$threadID));
break; break;
case "nuke": case "nuke":
@ -161,7 +161,7 @@ class Forum extends Extension
$this->delete_thread($threadID); $this->delete_thread($threadID);
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/index")); $page->set_redirect(make_link("forum/index"));
break; break;
case "answer": case "answer":
@ -176,11 +176,11 @@ class Forum extends Extension
} }
$this->save_new_post($threadID, $user); $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)); $page->set_redirect(make_link("forum/view/".$threadID."/".$total_pages));
break; break;
default: default:
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("forum/index")); $page->set_redirect(make_link("forum/index"));
//$this->theme->display_error(400, "Invalid action", "You should check forum/index."); //$this->theme->display_error(400, "Invalid action", "You should check forum/index.");
break; break;

View File

@ -14,7 +14,7 @@ class Handle404 extends Extension
{ {
global $config, $page; global $config, $page;
// hax. // 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)); $h_pagename = html_escape(implode('/', $event->args));
log_debug("handle_404", "Hit 404: $h_pagename"); log_debug("handle_404", "Hit 404: $h_pagename");
$page->set_code(404); $page->set_code(404);

View File

@ -8,12 +8,12 @@
class FlashFileHandler extends DataHandlerExtension class FlashFileHandler extends DataHandlerExtension
{ {
protected function create_thumb(string $hash): bool protected function create_thumb(string $hash, string $type): bool
{ {
global $config; global $config;
if (!create_thumbnail_ffmpeg($hash)) { 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; return true;
} }

View File

@ -5,65 +5,45 @@
* Description: Handle windows icons * 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)) { return in_array(strtolower($ext), self::SUPPORTED_EXTENSIONS);
$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;
}
} }
public function onDisplayingImage(DisplayingImageEvent $event) protected function create_image_from_data(string $filename, array $metadata)
{
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)
{ {
$image = new Image(); $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)); $fp = fopen($filename, "r");
fclose($fp); 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']; $width = $subheader['width'];
$height = $subheader['height']; $height = $subheader['height'];
$image->width = $width == 0 ? 256 : $width; $image->width = $width == 0 ? 256 : $width;
$image->height = $height == 0 ? 256 : $height; $image->height = $height == 0 ? 256 : $height;
$image->filesize = $metadata['size']; $image->filesize = $metadata['size'];
$image->hash = $metadata['hash']; $image->hash = $metadata['hash'];
$image->filename = $metadata['filename']; $image->filename = $metadata['filename'];
$image->ext = $metadata['extension']; $image->ext = $metadata['extension'];
$image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']); $image->tag_array = is_array($metadata['tags']) ? $metadata['tags'] : Tag::explode($metadata['tags']);
$image->source = $metadata['source']; $image->source = $metadata['source'];
return $image; return $image;
} }
private function check_contents(string $file): bool protected function check_contents(string $file): bool
{ {
if (!file_exists($file)) { if (!file_exists($file)) {
return false; return false;
@ -74,27 +54,8 @@ class IcoFileHandler extends Extension
return ($header['null'] == 0 && ($header['type'] == 0 || $header['type'] == 1)); 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; return create_thumbnail_convert($hash, $type);
$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;
} }
} }

View File

@ -7,9 +7,9 @@
class MP3FileHandler extends DataHandlerExtension 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)); copy("ext/handle_mp3/thumb.jpg", warehouse_path(Image::THUMBNAIL_DIR, $hash));
return true; return true;
} }

View File

@ -8,11 +8,12 @@
class PixelFileHandler extends DataHandlerExtension class PixelFileHandler extends DataHandlerExtension
{ {
const SUPPORTED_EXTENSIONS = ["jpg", "jpeg", "gif", "png", "webp"];
protected function supported_ext(string $ext): bool protected function supported_ext(string $ext): bool
{ {
$exts = ["jpg", "jpeg", "gif", "png", "webp"];
$ext = (($pos = strpos($ext, '?')) !== false) ? substr($ext, 0, $pos) : $ext; $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) protected function create_image_from_data(string $filename, array $metadata)
@ -53,12 +54,12 @@ class PixelFileHandler extends DataHandlerExtension
return false; return false;
} }
protected function create_thumb(string $hash): bool protected function create_thumb(string $hash, string $type): bool
{ {
global $config; global $config;
$inname = warehouse_path("images", $hash); $inname = warehouse_path(Image::IMAGE_DIR, $hash);
$outname = warehouse_path("thumbs", $hash); $outname = warehouse_path(Image::THUMBNAIL_DIR, $hash);
$ok = false; $ok = false;
@ -96,7 +97,7 @@ class PixelFileHandler extends DataHandlerExtension
try { try {
$info = getimagesize($inname); $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( $image = image_resize_gd(
$inname, $inname,
$info, $info,

View File

@ -14,7 +14,7 @@ class HandleStatic extends Extension
{ {
global $config, $page; global $config, $page;
// hax. // 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)); $h_pagename = html_escape(implode('/', $event->args));
$f_pagename = preg_replace("/[^a-z_\-\.]+/", "_", $h_pagename); $f_pagename = preg_replace("/[^a-z_\-\.]+/", "_", $h_pagename);
$theme_name = $config->get_string("theme", "default"); $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("Cache-control: public, max-age=600");
$page->add_http_header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 600) . ' GMT'); $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)); $page->set_data(file_get_contents($filename));
if (endsWith($filename, ".ico")) { if (endsWith($filename, ".ico")) {
$page->set_type("image/x-icon"); $page->set_type("image/x-icon");

View File

@ -19,23 +19,24 @@ class SVGFileHandler extends DataHandlerExtension
$sanitizer->removeRemoteReferences(true); $sanitizer->removeRemoteReferences(true);
$dirtySVG = file_get_contents($event->tmpname); $dirtySVG = file_get_contents($event->tmpname);
$cleanSVG = $sanitizer->sanitize($dirtySVG); $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)); 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)) { if (is_null($image)) {
throw new UploadException("SVG handler failed to create image object from data"); throw new UploadException("SVG handler failed to create image object from data");
} }
$iae = new ImageAdditionEvent($image); $iae = new ImageAdditionEvent($image);
send_event($iae); send_event($iae);
$event->image_id = $iae->image->id; $event->image_id = $iae->image->id;
$event->merged = $iae->merged;
} }
} }
protected function create_thumb(string $hash): bool protected function create_thumb(string $hash, string $type): bool
{ {
if (!create_thumbnail_convert($hash)) { 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; return true;
} }
@ -57,11 +58,11 @@ class SVGFileHandler extends DataHandlerExtension
$hash = $image->hash; $hash = $image->hash;
$page->set_type("image/svg+xml"); $page->set_type("image/svg+xml");
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$sanitizer = new Sanitizer(); $sanitizer = new Sanitizer();
$sanitizer->removeRemoteReferences(true); $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); $cleanSVG = $sanitizer->sanitize($dirtySVG);
$page->set_data($cleanSVG); $page->set_data($cleanSVG);
} }

View File

@ -53,7 +53,7 @@ class VideoFileHandler extends DataHandlerExtension
/** /**
* Generate the Thumbnail image for particular file. * 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); return create_thumbnail_ffmpeg($hash);
} }

View File

@ -4,7 +4,7 @@ class HomeTheme extends Themelet
{ {
public function display_page(Page $page, $sitename, $base_href, $theme_name, $body) 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(); $page->add_auto_html_headers();
$hh = $page->get_all_html_headers(); $hh = $page->get_all_html_headers();
$page->set_data( $page->set_data(

View File

@ -43,7 +43,7 @@ class ImageIO extends Extension
$image = Image::by_id($_POST['image_id']); $image = Image::by_id($_POST['image_id']);
if ($image) { if ($image) {
send_event(new ImageDeletionEvent($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')) { if (isset($_SERVER['HTTP_REFERER']) && !strstr($_SERVER['HTTP_REFERER'], 'post/view')) {
$page->set_redirect($_SERVER['HTTP_REFERER']); $page->set_redirect($_SERVER['HTTP_REFERER']);
} else { } else {
@ -56,7 +56,7 @@ class ImageIO extends Extension
if ($user->can("replace_image") && isset($_POST['image_id']) && $user->check_auth_token()) { if ($user->can("replace_image") && isset($_POST['image_id']) && $user->check_auth_token()) {
$image = Image::by_id($_POST['image_id']); $image = Image::by_id($_POST['image_id']);
if ($image) { if ($image) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link('upload/replace/'.$image->id)); $page->set_redirect(make_link('upload/replace/'.$image->id));
} else { } else {
/* Invalid image ID */ /* Invalid image ID */
@ -88,7 +88,7 @@ class ImageIO extends Extension
public function onImageAddition(ImageAdditionEvent $event) public function onImageAddition(ImageAdditionEvent $event)
{ {
try { try {
$this->add_image($event->image); $this->add_image($event);
} catch (ImageAdditionException $e) { } catch (ImageAdditionException $e) {
throw new UploadException($e->error); throw new UploadException($e->error);
} }
@ -141,7 +141,7 @@ class ImageIO extends Extension
$thumb_types = []; $thumb_types = [];
$thumb_types['JPEG'] = "jpg"; $thumb_types['JPEG'] = "jpg";
$thumb_types['WEBP'] = "webp"; $thumb_types['WEBP (Not IE/Safari compatible)'] = "webp";
$sb = new SetupBlock("Thumbnailing"); $sb = new SetupBlock("Thumbnailing");
@ -175,10 +175,12 @@ class ImageIO extends Extension
// add image {{{ // add image {{{
private function add_image(Image $image) private function add_image(ImageAdditionEvent $event)
{ {
global $user, $database, $config; global $user, $database, $config;
$image = $event->image;
/* /*
* Validate things * Validate things
*/ */
@ -201,7 +203,9 @@ class ImageIO extends Extension
if (isset($_GET['source']) && isset($_GET['update'])) { if (isset($_GET['source']) && isset($_GET['update'])) {
send_event(new SourceSetEvent($existing, $_GET['source'])); send_event(new SourceSetEvent($existing, $_GET['source']));
} }
return null; $event->merged = true;
$event->image = Image::by_id($existing->id);
return;
} else { } else {
$error = "Image <a href='".make_link("post/view/{$existing->id}")."'>{$existing->id}</a> ". $error = "Image <a href='".make_link("post/view/{$existing->id}")."'>{$existing->id}</a> ".
"already has hash {$image->hash}:<p>".$this->theme->build_thumb_html($existing); "already has hash {$image->hash}:<p>".$this->theme->build_thumb_html($existing);
@ -251,7 +255,7 @@ class ImageIO extends Extension
global $page; global $page;
if (!is_null($image)) { if (!is_null($image)) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
if ($type == "thumb") { if ($type == "thumb") {
$ext = $config->get_string("thumb_type"); $ext = $config->get_string("thumb_type");
if (array_key_exists($ext, MIME_TYPE_MAP)) { if (array_key_exists($ext, MIME_TYPE_MAP)) {

View File

@ -79,7 +79,7 @@ class ImageBan extends Extension
flash_message("Image deleted"); flash_message("Image deleted");
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect($_SERVER['HTTP_REFERER']); $page->set_redirect($_SERVER['HTTP_REFERER']);
} }
} elseif ($event->get_arg(0) == "remove") { } elseif ($event->get_arg(0) == "remove") {
@ -87,7 +87,7 @@ class ImageBan extends Extension
send_event(new RemoveImageHashBanEvent($_POST['hash'])); send_event(new RemoveImageHashBanEvent($_POST['hash']));
flash_message("Image ban removed"); flash_message("Image ban removed");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect($_SERVER['HTTP_REFERER']); $page->set_redirect($_SERVER['HTTP_REFERER']);
} }
} elseif ($event->get_arg(0) == "list") { } elseif ($event->get_arg(0) == "list") {

View File

@ -239,10 +239,10 @@ class Index extends Extension
// implode(explode()) to resolve aliases and sanitise // implode(explode()) to resolve aliases and sanitise
$search = url_escape(Tag::implode(Tag::explode($_GET['search'], false))); $search = url_escape(Tag::implode(Tag::explode($_GET['search'], false)));
if (empty($search)) { if (empty($search)) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/list/1")); $page->set_redirect(make_link("post/list/1"));
} else { } else {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link('post/list/'.$search.'/1')); $page->set_redirect(make_link('post/list/'.$search.'/1'));
} }
return; return;
@ -278,7 +278,7 @@ class Index extends Extension
$this->theme->display_intro($page); $this->theme->display_intro($page);
send_event(new PostListBuildingEvent($search_terms)); send_event(new PostListBuildingEvent($search_terms));
} elseif ($count_search_terms > 0 && $count_images === 1 && $page_number === 1) { } 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)); $page->set_redirect(make_link('post/view/'.$images[0]->id));
} else { } else {
$plbe = new PostListBuildingEvent($search_terms); $plbe = new PostListBuildingEvent($search_terms);

View File

@ -157,7 +157,7 @@ class IndexTest extends ShimmiePHPUnitTestCase
global $database; global $database;
$db = $database->get_driver_name(); $db = $database->get_driver_name();
if ($db == "pgsql" || $db == "sqlite") { if ($db == DatabaseDriver::PGSQL || $db == DatabaseDriver::SQLITE) {
$this->markTestIncomplete(); $this->markTestIncomplete();
} }

View File

@ -77,7 +77,7 @@ class IPBan extends Extension
send_event(new AddIPBanEvent($_POST['ip'], $_POST['reason'], $end)); send_event(new AddIPBanEvent($_POST['ip'], $_POST['reason'], $end));
flash_message("Ban for {$_POST['ip']} added"); flash_message("Ban for {$_POST['ip']} added");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("ip_ban/list")); $page->set_redirect(make_link("ip_ban/list"));
} }
} elseif ($event->get_arg(0) == "remove" && $user->check_auth_token()) { } elseif ($event->get_arg(0) == "remove" && $user->check_auth_token()) {
@ -85,7 +85,7 @@ class IPBan extends Extension
send_event(new RemoveIPBanEvent($_POST['id'])); send_event(new RemoveIPBanEvent($_POST['id']));
flash_message("Ban removed"); flash_message("Ban removed");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("ip_ban/list")); $page->set_redirect(make_link("ip_ban/list"));
} }
} elseif ($event->get_arg(0) == "list") { } elseif ($event->get_arg(0) == "list") {
@ -235,7 +235,7 @@ class IPBan extends Extension
{ {
global $config, $database; global $config, $database;
$prefix = ($database->get_driver_name() == "sqlite" ? "bans." : ""); $prefix = ($database->get_driver_name() == DatabaseDriver::SQLITE ? "bans." : "");
$bans = $this->get_active_bans(); $bans = $this->get_active_bans();

View File

@ -16,7 +16,7 @@ class IPBanTheme extends Themelet
{ {
global $database, $user; global $database, $user;
$h_bans = ""; $h_bans = "";
$prefix = ($database->get_driver_name() == "sqlite" ? "bans." : ""); $prefix = ($database->get_driver_name() == DatabaseDriver::SQLITE ? "bans." : "");
foreach ($bans as $ban) { foreach ($bans as $ban) {
$end_human = date('Y-m-d', $ban[$prefix.'end_timestamp']); $end_human = date('Y-m-d', $ban[$prefix.'end_timestamp']);
$h_bans .= " $h_bans .= "

View File

@ -68,7 +68,7 @@ class LogDatabase extends Extension
$args["module"] = $_GET["module"]; $args["module"] = $_GET["module"];
} }
if (!empty($_GET["user"])) { if (!empty($_GET["user"])) {
if ($database->get_driver_name() == "pgsql") { if ($database->get_driver_name() == DatabaseDriver::PGSQL) {
if (preg_match("#\d+\.\d+\.\d+\.\d+(/\d+)?#", $_GET["user"])) { if (preg_match("#\d+\.\d+\.\d+\.\d+(/\d+)?#", $_GET["user"])) {
$wheres[] = "(username = :user1 OR text(address) = :user2)"; $wheres[] = "(username = :user1 OR text(address) = :user2)";
$args["user1"] = $_GET["user"]; $args["user1"] = $_GET["user"];

View File

@ -35,7 +35,7 @@ class MailTest extends Extension
{ {
if ($event->page_matches("mail/test")) { if ($event->page_matches("mail/test")) {
global $page; 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 "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:<br>"; echo "Preparing to send message:<br>";

View File

@ -64,7 +64,7 @@ class MassTagger extends Extension
} }
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
if (!isset($_SERVER['HTTP_REFERER'])) { if (!isset($_SERVER['HTTP_REFERER'])) {
$_SERVER['HTTP_REFERER'] = make_link(); $_SERVER['HTTP_REFERER'] = make_link();
} }

View File

@ -81,14 +81,14 @@ class NotATag extends Extension
[$tag, $redirect] [$tag, $redirect]
); );
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect($_SERVER['HTTP_REFERER']); $page->set_redirect($_SERVER['HTTP_REFERER']);
} elseif ($event->get_arg(0) == "remove") { } elseif ($event->get_arg(0) == "remove") {
if (isset($_POST['tag'])) { if (isset($_POST['tag'])) {
$database->Execute("DELETE FROM untags WHERE tag = ?", [$_POST['tag']]); $database->Execute("DELETE FROM untags WHERE tag = ?", [$_POST['tag']]);
flash_message("Image ban removed"); flash_message("Image ban removed");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect($_SERVER['HTTP_REFERER']); $page->set_redirect($_SERVER['HTTP_REFERER']);
} }
} elseif ($event->get_arg(0) == "list") { } elseif ($event->get_arg(0) == "list") {

View File

@ -100,7 +100,7 @@ class Notes extends Extension
$this->revert_history($noteID, $reviewID); $this->revert_history($noteID, $reviewID);
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("note/updated")); $page->set_redirect(make_link("note/updated"));
break; break;
case "add_note": case "add_note":
@ -108,7 +108,7 @@ class Notes extends Extension
$this->add_new_note(); $this->add_new_note();
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$_POST["image_id"])); $page->set_redirect(make_link("post/view/".$_POST["image_id"]));
break; break;
case "add_request": case "add_request":
@ -116,7 +116,7 @@ class Notes extends Extension
$this->add_note_request(); $this->add_note_request();
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$_POST["image_id"])); $page->set_redirect(make_link("post/view/".$_POST["image_id"]));
break; break;
case "nuke_notes": case "nuke_notes":
@ -124,7 +124,7 @@ class Notes extends Extension
$this->nuke_notes(); $this->nuke_notes();
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$_POST["image_id"])); $page->set_redirect(make_link("post/view/".$_POST["image_id"]));
break; break;
case "nuke_requests": case "nuke_requests":
@ -132,25 +132,25 @@ class Notes extends Extension
$this->nuke_requests(); $this->nuke_requests();
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$_POST["image_id"])); $page->set_redirect(make_link("post/view/".$_POST["image_id"]));
break; break;
case "edit_note": case "edit_note":
if (!$user->is_anonymous()) { if (!$user->is_anonymous()) {
$this->update_note(); $this->update_note();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/" . $_POST["image_id"])); $page->set_redirect(make_link("post/view/" . $_POST["image_id"]));
} }
break; break;
case "delete_note": case "delete_note":
if ($user->is_admin()) { if ($user->is_admin()) {
$this->delete_note(); $this->delete_note();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$_POST["image_id"])); $page->set_redirect(make_link("post/view/".$_POST["image_id"]));
} }
break; break;
default: default:
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("note/list")); $page->set_redirect(make_link("note/list"));
break; break;
} }

View File

@ -94,7 +94,7 @@ class NumericScore extends Extension
if (!is_null($score) && $image_id>0) { if (!is_null($score) && $image_id>0) {
send_event(new NumericScoreSetEvent($image_id, $user, $score)); 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")); $page->set_redirect(make_link("post/view/$image_id"));
} }
} elseif ($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) { } 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=?", "UPDATE images SET numeric_score=0 WHERE id=?",
[$image_id] [$image_id]
); );
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$image_id")); $page->set_redirect(make_link("post/view/$image_id"));
} }
} elseif ($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) { } elseif ($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) {
if ($user->can("edit_other_vote")) { if ($user->can("edit_other_vote")) {
$this->delete_votes_by(int_escape($_POST['user_id'])); $this->delete_votes_by(int_escape($_POST['user_id']));
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link()); $page->set_redirect(make_link());
} }
} elseif ($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) { } elseif ($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) {

View File

@ -41,7 +41,7 @@ class Oekaki extends Extension
throw new UploadException("File type not recognised"); throw new UploadException("File type not recognised");
} else { } else {
unlink($tmpname); unlink($tmpname);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$duev->image_id)); $page->set_redirect(make_link("post/view/".$duev->image_id));
} }
} }

View File

@ -404,7 +404,7 @@ class OuroborosAPI extends Extension
} elseif ($this->type == 'xml') { } elseif ($this->type == 'xml') {
$page->set_type('text/xml; charset=utf-8'); $page->set_type('text/xml; charset=utf-8');
} }
$page->set_mode('data'); $page->set_mode(PageMode::DATA);
$this->tryAuth(); $this->tryAuth();
if ($event->page_matches('post')) { if ($event->page_matches('post')) {
@ -464,7 +464,7 @@ class OuroborosAPI extends Extension
} }
} }
} elseif ($event->page_matches('post/show')) { } 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->set_redirect(make_link(str_replace('post/show', 'post/view', implode('/', $event->args))));
$page->display(); $page->display();
die(); die();

View File

@ -149,7 +149,7 @@ class PrivMsg extends Extension
$database->execute("DELETE FROM private_message WHERE id = :id", ["id" => $pm_id]); $database->execute("DELETE FROM private_message WHERE id = :id", ["id" => $pm_id]);
$database->cache->delete("pm-count-{$user->id}"); $database->cache->delete("pm-count-{$user->id}");
log_info("pm", "Deleted PM #$pm_id", "PM deleted"); log_info("pm", "Deleted PM #$pm_id", "PM deleted");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect($_SERVER["HTTP_REFERER"]); $page->set_redirect($_SERVER["HTTP_REFERER"]);
} }
} }
@ -162,7 +162,7 @@ class PrivMsg extends Extension
$message = $_POST["message"]; $message = $_POST["message"];
send_event(new SendPMEvent(new PM($from_id, $_SERVER["REMOTE_ADDR"], $to_id, $subject, $message))); send_event(new SendPMEvent(new PM($from_id, $_SERVER["REMOTE_ADDR"], $to_id, $subject, $message)));
flash_message("PM sent"); flash_message("PM sent");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect($_SERVER["HTTP_REFERER"]); $page->set_redirect($_SERVER["HTTP_REFERER"]);
} }
break; break;

View File

@ -130,7 +130,7 @@ class Pools extends Extension
case "create": // ADD _POST case "create": // ADD _POST
try { try {
$newPoolID = $this->add_pool(); $newPoolID = $this->add_pool();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/".$newPoolID)); $page->set_redirect(make_link("pool/view/".$newPoolID));
} catch (PoolCreationException $e) { } catch (PoolCreationException $e) {
$this->theme->display_error(400, "Error", $e->error); $this->theme->display_error(400, "Error", $e->error);
@ -150,7 +150,7 @@ class Pools extends Extension
if (!$user->is_anonymous()) { if (!$user->is_anonymous()) {
$historyID = int_escape($event->get_arg(1)); $historyID = int_escape($event->get_arg(1));
$this->revert_history($historyID); $this->revert_history($historyID);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/updated")); $page->set_redirect(make_link("pool/updated"));
} }
break; break;
@ -159,7 +159,7 @@ class Pools extends Extension
if ($this->have_permission($user, $pool)) { if ($this->have_permission($user, $pool)) {
$this->theme->edit_pool($page, $this->get_pool($pool_id), $this->edit_posts($pool_id)); $this->theme->edit_pool($page, $this->get_pool($pool_id), $this->edit_posts($pool_id));
} else { } else {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/".$pool_id)); $page->set_redirect(make_link("pool/view/".$pool_id));
} }
break; break;
@ -169,13 +169,13 @@ class Pools extends Extension
if ($this->have_permission($user, $pool)) { if ($this->have_permission($user, $pool)) {
$this->theme->edit_order($page, $this->get_pool($pool_id), $this->edit_order($pool_id)); $this->theme->edit_order($page, $this->get_pool($pool_id), $this->edit_order($pool_id));
} else { } else {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/".$pool_id)); $page->set_redirect(make_link("pool/view/".$pool_id));
} }
} else { } else {
if ($this->have_permission($user, $pool)) { if ($this->have_permission($user, $pool)) {
$this->order_posts(); $this->order_posts();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/".$pool_id)); $page->set_redirect(make_link("pool/view/".$pool_id));
} else { } else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); $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": case "add_posts":
if ($this->have_permission($user, $pool)) { if ($this->have_permission($user, $pool)) {
$this->add_posts(); $this->add_posts();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/".$pool_id)); $page->set_redirect(make_link("pool/view/".$pool_id));
} else { } else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); $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": case "remove_posts":
if ($this->have_permission($user, $pool)) { if ($this->have_permission($user, $pool)) {
$this->remove_posts(); $this->remove_posts();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/".$pool_id)); $page->set_redirect(make_link("pool/view/".$pool_id));
} else { } else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); $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": case "edit_description":
if ($this->have_permission($user, $pool)) { if ($this->have_permission($user, $pool)) {
$this->edit_description(); $this->edit_description();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/".$pool_id)); $page->set_redirect(make_link("pool/view/".$pool_id));
} else { } else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); $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 // -> Only admins and owners may do this
if ($user->is_admin() || $user->id == $pool['user_id']) { if ($user->is_admin() || $user->id == $pool['user_id']) {
$this->nuke_pool($pool_id); $this->nuke_pool($pool_id);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/list")); $page->set_redirect(make_link("pool/list"));
} else { } else {
$this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); $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; break;
default: default:
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/list")); $page->set_redirect(make_link("pool/list"));
break; break;
} }

View File

@ -40,7 +40,7 @@ class RandomImage extends Extension
if ($action === "download") { if ($action === "download") {
if (!is_null($image)) { if (!is_null($image)) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type($image->get_mime_type()); $page->set_type($image->get_mime_type());
$page->set_data(file_get_contents($image->get_image_filename())); $page->set_data(file_get_contents($image->get_image_filename()));
} }
@ -50,7 +50,7 @@ class RandomImage extends Extension
} }
} elseif ($action === "widget") { } elseif ($action === "widget") {
if (!is_null($image)) { if (!is_null($image)) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("text/html"); $page->set_type("text/html");
$page->set_data($this->theme->build_thumb_html($image)); $page->set_data($this->theme->build_thumb_html($image));
} }

View File

@ -21,10 +21,10 @@ class RandomList extends Extension
// implode(explode()) to resolve aliases and sanitise // implode(explode()) to resolve aliases and sanitise
$search = url_escape(Tag::implode(Tag::explode($_GET['search'], false))); $search = url_escape(Tag::implode(Tag::explode($_GET['search'], false)));
if (empty($search)) { if (empty($search)) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("random")); $page->set_redirect(make_link("random"));
} else { } else {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link('random/'.$search)); $page->set_redirect(make_link('random/'.$search));
} }
return; return;

View File

@ -37,7 +37,7 @@ class RatingSetEvent extends Event
class Ratings extends Extension class Ratings extends Extension
{ {
protected $db_support = ['mysql','pgsql']; // ? protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL];
public function get_priority(): int public function get_priority(): int
{ {
@ -91,7 +91,7 @@ class Ratings extends Extension
$user_view_level = Ratings::get_user_privs($user); $user_view_level = Ratings::get_user_privs($user);
$user_view_level = preg_split('//', $user_view_level, -1); $user_view_level = preg_split('//', $user_view_level, -1);
if (!in_array($event->image->rating, $user_view_level)) { 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")); $page->set_redirect(make_link("post/list"));
} }
} }
@ -170,7 +170,7 @@ class Ratings extends Extension
global $user; global $user;
if ($user->is_admin()) { 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"));
} }
} }
@ -228,7 +228,7 @@ class Ratings extends Extension
# select image_id from image_tags join tags # select image_id from image_tags join tags
# on image_tags.tag_id = tags.id where tags.tag = ?); # on image_tags.tag_id = tags.id where tags.tag = ?);
# ", array($_POST["rating"], $_POST["tag"])); # ", array($_POST["rating"], $_POST["tag"]));
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/list")); $page->set_redirect(make_link("post/list"));
} }
} }
@ -331,10 +331,10 @@ class Ratings extends Extension
if ($config->get_int("ext_ratings2_version") < 3) { if ($config->get_int("ext_ratings2_version") < 3) {
$database->Execute("UPDATE images SET rating = 'u' WHERE rating is null"); $database->Execute("UPDATE images SET rating = 'u' WHERE rating is null");
switch ($database->get_driver_name()) { switch ($database->get_driver_name()) {
case "mysql": case DatabaseDriver::MYSQL:
$database->Execute("ALTER TABLE images CHANGE rating rating CHAR(1) NOT NULL DEFAULT 'u'"); $database->Execute("ALTER TABLE images CHANGE rating rating CHAR(1) NOT NULL DEFAULT 'u'");
break; break;
case "pgsql": case DatabaseDriver::PGSQL:
$database->Execute("ALTER TABLE images ALTER COLUMN rating SET DEFAULT 'u'"); $database->Execute("ALTER TABLE images ALTER COLUMN rating SET DEFAULT 'u'");
$database->Execute("ALTER TABLE images ALTER COLUMN rating SET NOT NULL"); $database->Execute("ALTER TABLE images ALTER COLUMN rating SET NOT NULL");
break; break;

View File

@ -43,7 +43,7 @@ class RegenThumb extends Extension
$this->regenerate_thumbnail($image); $this->regenerate_thumbnail($image);
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/list")); $page->set_redirect(make_link("post/list"));
} }
} }
@ -133,7 +133,7 @@ class RegenThumb extends Extension
$i = 0; $i = 0;
foreach ($images as $image) { foreach ($images as $image) {
if (!$force) { if (!$force) {
$path = warehouse_path("thumbs", $image["hash"], false); $path = warehouse_path(Image::THUMBNAIL_DIR, $image["hash"], false);
if (file_exists($path)) { if (file_exists($path)) {
continue; continue;
} }
@ -157,7 +157,7 @@ class RegenThumb extends Extension
$i = 0; $i = 0;
foreach ($images as $image) { foreach ($images as $image) {
$outname = warehouse_path("thumbs", $image["hash"]); $outname = warehouse_path(Image::THUMBNAIL_DIR, $image["hash"]);
if (file_exists($outname)) { if (file_exists($outname)) {
unlink($outname); unlink($outname);
$i++; $i++;

View File

@ -8,7 +8,7 @@
class Relationships extends Extension class Relationships extends Extension
{ {
protected $db_support = ['mysql', 'pgsql']; protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL];
public function onInitExt(InitExtEvent $event) public function onInitExt(InitExtEvent $event)
{ {

View File

@ -67,7 +67,7 @@ class ReportImage extends Extension
if (!empty($_POST['image_id']) && !empty($_POST['reason'])) { if (!empty($_POST['image_id']) && !empty($_POST['reason'])) {
$image_id = int_escape($_POST['image_id']); $image_id = int_escape($_POST['image_id']);
send_event(new AddReportedImageEvent(new ImageReport($image_id, $user->id, $_POST['reason']))); 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")); $page->set_redirect(make_link("post/view/$image_id"));
} else { } else {
$this->theme->display_error(500, "Missing input", "Missing image ID or report reason"); $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 (!empty($_POST['id'])) {
if ($user->can("view_image_report")) { if ($user->can("view_image_report")) {
send_event(new RemoveReportedImageEvent($_POST['id'])); send_event(new RemoveReportedImageEvent($_POST['id']));
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("image_report/list")); $page->set_redirect(make_link("image_report/list"));
} }
} else { } else {
@ -85,7 +85,7 @@ class ReportImage extends Extension
} elseif ($event->get_arg(0) == "remove_reports_by" && $user->check_auth_token()) { } elseif ($event->get_arg(0) == "remove_reports_by" && $user->check_auth_token()) {
if ($user->can("view_image_report")) { if ($user->can("view_image_report")) {
$this->delete_reports_by(int_escape($_POST['user_id'])); $this->delete_reports_by(int_escape($_POST['user_id']));
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link()); $page->set_redirect(make_link());
} }
} elseif ($event->get_arg(0) == "list") { } elseif ($event->get_arg(0) == "list") {

View File

@ -16,6 +16,8 @@
*/ */
class ResizeImage extends Extension class ResizeImage extends Extension
{ {
const SUPPORTED_EXT = ["jpg","jpeg","png","gif","webp"];
/** /**
* Needs to be after the data processing extensions * Needs to be after the data processing extensions
*/ */
@ -37,7 +39,8 @@ class ResizeImage extends Extension
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
{ {
global $user, $config; 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 */ /* Add a link to resize the image */
$event->add_part($this->theme->get_resize_html($event->image)); $event->add_part($this->theme->get_resize_html($event->image));
} }
@ -64,7 +67,8 @@ class ResizeImage extends Extension
$image_obj = Image::by_id($event->image_id); $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; $width = $height = 0;
if ($config->get_int("resize_default_width") !== 0) { if ($config->get_int("resize_default_width") !== 0) {
@ -75,7 +79,7 @@ class ResizeImage extends Extension
} }
$isanigif = 0; $isanigif = 0;
if ($image_obj->ext == "gif") { 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'))) { if (($fh = @fopen($image_filename, 'rb'))) {
//check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473) //check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473)
while (!feof($fh) && $isanigif < 2) { while (!feof($fh) && $isanigif < 2) {
@ -141,7 +145,7 @@ class ResizeImage extends Extension
//$this->theme->display_resize_page($page, $image_id); //$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)); $page->set_redirect(make_link("post/view/".$image_id));
} catch (ImageResizeException $e) { } catch (ImageResizeException $e) {
$this->theme->display_resize_error($page, "Error Resizing", $e->error); $this->theme->display_resize_error($page, "Error Resizing", $e->error);
@ -163,7 +167,7 @@ class ResizeImage extends Extension
} }
$hash = $image_obj->hash; $hash = $image_obj->hash;
$image_filename = warehouse_path("images", $hash); $image_filename = warehouse_path(Image::IMAGE_DIR, $hash);
$info = getimagesize($image_filename); $info = getimagesize($image_filename);
if (($image_obj->width != $info[0]) || ($image_obj->height != $info[1])) { if (($image_obj->width != $info[0]) || ($image_obj->height != $info[1])) {
@ -189,7 +193,7 @@ class ResizeImage extends Extension
$new_image->ext = $image_obj->ext; $new_image->ext = $image_obj->ext;
/* Move the new image into the main storage location */ /* 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)) { if (!@copy($tmp_filename, $target)) {
throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)");
} }

View File

@ -31,6 +31,8 @@ class ImageRotateException extends SCoreException
*/ */
class RotateImage extends Extension class RotateImage extends Extension
{ {
const SUPPORTED_EXT = ["jpg","jpeg","png","gif","webp"];
public function onInitExt(InitExtEvent $event) public function onInitExt(InitExtEvent $event)
{ {
global $config; global $config;
@ -41,7 +43,8 @@ class RotateImage extends Extension
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
{ {
global $user, $config; 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 */ /* Add a link to rotate the image */
$event->add_part($this->theme->get_rotate_html($event->image->id)); $event->add_part($this->theme->get_rotate_html($event->image->id));
} }
@ -93,7 +96,7 @@ class RotateImage extends Extension
//$this->theme->display_rotate_page($page, $image_id); //$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)); $page->set_redirect(make_link("post/view/".$image_id));
} catch (ImageRotateException $e) { } catch (ImageRotateException $e) {
$this->theme->display_rotate_error($page, "Error Rotating", $e->error); $this->theme->display_rotate_error($page, "Error Rotating", $e->error);
@ -120,7 +123,7 @@ class RotateImage extends Extension
throw new ImageRotateException("Image does not have a hash associated with it."); 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) { if (file_exists($image_filename)==false) {
throw new ImageRotateException("$image_filename does not exist."); throw new ImageRotateException("$image_filename does not exist.");
} }
@ -212,7 +215,7 @@ class RotateImage extends Extension
$new_image->ext = $image_obj->ext; $new_image->ext = $image_obj->ext;
/* Move the new image into the main storage location */ /* 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)) { if (!@copy($tmp_filename, $target)) {
throw new ImageRotateException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); throw new ImageRotateException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)");
} }

View File

@ -9,7 +9,7 @@
class RSS_Comments extends Extension class RSS_Comments extends Extension
{ {
protected $db_support = ['mysql', 'sqlite']; // pgsql has no UNIX_TIMESTAMP protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::SQLITE]; // pgsql has no UNIX_TIMESTAMP
public function onPostListBuilding(PostListBuildingEvent $event) public function onPostListBuilding(PostListBuildingEvent $event)
{ {
@ -24,7 +24,7 @@ class RSS_Comments extends Extension
{ {
global $config, $database, $page; global $config, $database, $page;
if ($event->page_matches("rss/comments")) { if ($event->page_matches("rss/comments")) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("application/rss+xml"); $page->set_type("application/rss+xml");
$comments = $database->get_all(" $comments = $database->get_all("

View File

@ -39,7 +39,7 @@ class RSS_Images extends Extension
{ {
global $page; global $page;
global $config; global $config;
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("application/rss+xml"); $page->set_type("application/rss+xml");
$data = ""; $data = "";

View File

@ -19,7 +19,7 @@ if ( // kill these glitched requests immediately
class Rule34 extends Extension class Rule34 extends Extension
{ {
protected $db_support = ['pgsql']; # Only PG has the NOTIFY pubsub system protected $db_support = [DatabaseDriver::PGSQL]; # Only PG has the NOTIFY pubsub system
public function onImageDeletion(ImageDeletionEvent $event) public function onImageDeletion(ImageDeletionEvent $event)
{ {
@ -90,14 +90,14 @@ class Rule34 extends Extension
'UPDATE users SET comic_admin=? WHERE id=?', 'UPDATE users SET comic_admin=? WHERE id=?',
[$input['is_admin'] ? 't' : 'f', $input['user_id']] [$input['is_admin'] ? 't' : 'f', $input['user_id']]
); );
$page->set_mode('redirect'); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(@$_SERVER['HTTP_REFERER']); $page->set_redirect(@$_SERVER['HTTP_REFERER']);
} }
} }
if ($event->page_matches("tnc_agreed")) { if ($event->page_matches("tnc_agreed")) {
setcookie("ui-tnc-agreed", "true", 0, "/"); setcookie("ui-tnc-agreed", "true", 0, "/");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(@$_SERVER['HTTP_REFERER'] ?? "/"); $page->set_redirect(@$_SERVER['HTTP_REFERER'] ?? "/");
} }
@ -116,14 +116,14 @@ class Rule34 extends Extension
continue; continue;
} }
log_info("admin", "Cleaning {$hash}"); log_info("admin", "Cleaning {$hash}");
@unlink(warehouse_path('images', $hash)); @unlink(warehouse_path(Image::IMAGE_DIR, $hash));
@unlink(warehouse_path('thumbs', $hash)); @unlink(warehouse_path(Image::THUMBNAIL_DIR, $hash));
$database->execute("NOTIFY shm_image_bans, '{$hash}';"); $database->execute("NOTIFY shm_image_bans, '{$hash}';");
} }
} }
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin")); $page->set_redirect(make_link("admin"));
} }
} }

View File

@ -19,7 +19,7 @@ class Rule34Theme extends Themelet
{ {
global $database, $user; global $database, $user;
$h_bans = ""; $h_bans = "";
$prefix = ($database->get_driver_name() == "sqlite" ? "bans." : ""); $prefix = ($database->get_driver_name() == DatabaseDriver::SQLITE ? "bans." : "");
foreach ($bans as $ban) { foreach ($bans as $ban) {
$h_bans .= " $h_bans .= "
<tr> <tr>

View File

@ -203,7 +203,7 @@ class Setup extends Extension
global $config, $page, $user; global $config, $page, $user;
if ($event->page_matches("nicetest")) { if ($event->page_matches("nicetest")) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_data("ok"); $page->set_data("ok");
} }
@ -216,7 +216,7 @@ class Setup extends Extension
$config->save(); $config->save();
flash_message("Config saved"); flash_message("Config saved");
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("setup")); $page->set_redirect(make_link("setup"));
} elseif ($event->get_arg(0) == "advanced") { } elseif ($event->get_arg(0) == "advanced") {
$this->theme->display_advanced($page, $config->values); $this->theme->display_advanced($page, $config->values);

View File

@ -53,7 +53,7 @@ class ShimmieApi extends Extension
global $page, $user; global $page, $user;
if ($event->page_matches("api/shimmie")) { if ($event->page_matches("api/shimmie")) {
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("text/plain"); $page->set_type("text/plain");
if ($event->page_matches("api/shimmie/get_tags")) { if ($event->page_matches("api/shimmie/get_tags")) {
@ -100,7 +100,7 @@ class ShimmieApi extends Extension
$all = $this->api_get_user($type, $query); $all = $this->api_get_user($type, $query);
$page->set_data(json_encode($all)); $page->set_data(json_encode($all));
} else { } else {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("ext_doc/shimmie_api")); $page->set_redirect(make_link("ext_doc/shimmie_api"));
} }
} }

View File

@ -152,7 +152,7 @@ class XMLSitemap extends Extension
// Generate new sitemap // Generate new sitemap
file_put_contents($this->sitemap_filepath, $xml); file_put_contents($this->sitemap_filepath, $xml);
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("application/xml"); $page->set_type("application/xml");
$page->set_data($xml); $page->set_data($xml);
} }
@ -188,7 +188,7 @@ class XMLSitemap extends Extension
$xml = file_get_contents($this->sitemap_filepath); $xml = file_get_contents($this->sitemap_filepath);
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("application/xml"); $page->set_type("application/xml");
$page->set_data($xml); $page->set_data($xml);
} }

View File

@ -132,7 +132,7 @@ class Source_History extends Extension
// check for the nothing case // check for the nothing case
if ($revert_id < 1) { if ($revert_id < 1) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link()); $page->set_redirect(make_link());
return; return;
} }
@ -165,7 +165,7 @@ class Source_History extends Extension
send_event(new SourceSetEvent($image, $stored_source)); send_event(new SourceSetEvent($image, $stored_source));
// all should be done now so redirect the user back to the image // 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)); $page->set_redirect(make_link('post/view/'.$stored_image_id));
} }

View File

@ -165,14 +165,14 @@ class TagEdit extends Extension
$search = $_POST['search']; $search = $_POST['search'];
$replace = $_POST['replace']; $replace = $_POST['replace'];
$this->mass_tag_edit($search, $replace); $this->mass_tag_edit($search, $replace);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("admin")); $page->set_redirect(make_link("admin"));
} }
} }
if ($event->get_arg(0) == "mass_source_set") { if ($event->get_arg(0) == "mass_source_set") {
if ($user->can("mass_tag_edit") && isset($_POST['tags']) && isset($_POST['source'])) { if ($user->can("mass_tag_edit") && isset($_POST['tags']) && isset($_POST['source'])) {
$this->mass_source_edit($_POST['tags'], $_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")); $page->set_redirect(make_link("post/list"));
} }
} }

View File

@ -132,7 +132,7 @@ class Tag_History extends Extension
// check for the nothing case // check for the nothing case
if ($revert_id < 1) { if ($revert_id < 1) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link()); $page->set_redirect(make_link());
return; return;
} }
@ -162,7 +162,7 @@ class Tag_History extends Extension
send_event(new TagSetEvent($image, Tag::explode($stored_tags))); send_event(new TagSetEvent($image, Tag::explode($stored_tags)));
// all should be done now so redirect the user back to the image // 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)); $page->set_redirect(make_link('post/view/'.$stored_image_id));
} }

View File

@ -75,7 +75,7 @@ class TagList extends Extension
$database->cache->set($cache_key, $res, 600); $database->cache->set($cache_key, $res, 600);
} }
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("text/plain"); $page->set_type("text/plain");
$page->set_data(implode("\n", $res)); $page->set_data(implode("\n", $res));
} }

View File

@ -59,7 +59,7 @@ class TaggerXML extends Extension
$tags. $tags.
"</tags>"; "</tags>";
$page->set_mode("data"); $page->set_mode(PageMode::DATA);
$page->set_type("text/xml"); $page->set_type("text/xml");
$page->set_data($xml); $page->set_data($xml);
} }

View File

@ -10,7 +10,7 @@
class Tips extends Extension class Tips extends Extension
{ {
protected $db_support = ['mysql', 'sqlite']; // rand() ? protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::SQLITE]; // rand() ?
public function onInitExt(InitExtEvent $event) public function onInitExt(InitExtEvent $event)
{ {
@ -51,7 +51,7 @@ class Tips extends Extension
case "save": case "save":
if ($user->check_auth_token()) { if ($user->check_auth_token()) {
$this->saveTip(); $this->saveTip();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list")); $page->set_redirect(make_link("tips/list"));
} }
break; break;
@ -59,14 +59,14 @@ class Tips extends Extension
// FIXME: HTTP GET CSRF // FIXME: HTTP GET CSRF
$tipID = int_escape($event->get_arg(1)); $tipID = int_escape($event->get_arg(1));
$this->setStatus($tipID); $this->setStatus($tipID);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list")); $page->set_redirect(make_link("tips/list"));
break; break;
case "delete": case "delete":
// FIXME: HTTP GET CSRF // FIXME: HTTP GET CSRF
$tipID = int_escape($event->get_arg(1)); $tipID = int_escape($event->get_arg(1));
$this->deleteTip($tipID); $this->deleteTip($tipID);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("tips/list")); $page->set_redirect(make_link("tips/list"));
break; break;
} }

View File

@ -43,6 +43,7 @@ class TranscodeImage extends Extension
"psd", "psd",
"tiff", "tiff",
"webp", "webp",
"ico",
] ]
]; ];
@ -68,6 +69,7 @@ class TranscodeImage extends Extension
const INPUT_FORMATS = [ const INPUT_FORMATS = [
"BMP" => "bmp", "BMP" => "bmp",
"GIF" => "gif", "GIF" => "gif",
"ICO" => "ico",
"JPG" => "jpg", "JPG" => "jpg",
"PNG" => "png", "PNG" => "png",
"PSD" => "psd", "PSD" => "psd",
@ -197,7 +199,7 @@ class TranscodeImage extends Extension
if (isset($_POST['transcode_format'])) { if (isset($_POST['transcode_format'])) {
try { try {
$this->transcode_and_replace_image($image_obj, $_POST['transcode_format']); $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)); $page->set_redirect(make_link("post/view/".$image_id));
} catch (ImageTranscodeException $e) { } catch (ImageTranscodeException $e) {
$this->theme->display_transcode_error($page, "Error Transcoding", $e->getMessage()); $this->theme->display_transcode_error($page, "Error Transcoding", $e->getMessage());
@ -306,7 +308,7 @@ class TranscodeImage extends Extension
private function transcode_and_replace_image(Image $image_obj, String $target_format) private function transcode_and_replace_image(Image $image_obj, String $target_format)
{ {
$target_format = $this->clean_format($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); $tmp_filename = $this->transcode_image($original_file, $image_obj->ext, $target_format);
@ -319,7 +321,7 @@ class TranscodeImage extends Extension
$new_image->ext = $this->determine_ext($target_format); $new_image->ext = $this->determine_ext($target_format);
/* Move the new image into the main storage location */ /* 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)) { if (!@copy($tmp_filename, $target)) {
throw new ImageTranscodeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); throw new ImageTranscodeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)");
} }
@ -440,15 +442,21 @@ class TranscodeImage extends Extension
} }
$tmp_name = tempnam("/tmp", "shimmie_transcode"); $tmp_name = tempnam("/tmp", "shimmie_transcode");
$format = '"%s" %s -quality %u -background %s "%s" %s:"%s"'; $source_type = "";
$cmd = sprintf($format, $convert, $args, $q, $bg, $source_name, $ext, $tmp_name); 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 $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); exec($cmd, $output, $ret);
log_debug('transcode', "Transcoding with command `$cmd`, returns $ret"); log_debug('transcode', "Transcoding with command `$cmd`, returns $ret");
if ($ret!==0) { 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; return $tmp_name;

View File

@ -38,7 +38,7 @@ class Update extends Extension
if ($event->page_matches("update/download")) { if ($event->page_matches("update/download")) {
$ok = $this->download_shimmie(); $ok = $this->download_shimmie();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
if ($ok) { if ($ok) {
$page->set_redirect(make_link("update/update", "sha=".$_GET['sha'])); $page->set_redirect(make_link("update/update", "sha=".$_GET['sha']));
} else { } else {
@ -47,7 +47,7 @@ class Update extends Extension
} elseif ($event->page_matches("update/update")) { } elseif ($event->page_matches("update/update")) {
$ok = $this->update_shimmie(); $ok = $this->update_shimmie();
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
if ($ok) { if ($ok) {
$page->set_redirect(make_link("admin")); $page->set_redirect(make_link("admin"));
} //TODO: Show success? } //TODO: Show success?

View File

@ -44,7 +44,7 @@ class Upgrade extends Extension
$config->set_bool("in_upgrade", true); $config->set_bool("in_upgrade", true);
$config->set_int("db_version", 9); $config->set_int("db_version", 9);
if ($database->get_driver_name() == 'mysql') { if ($database->get_driver_name() == DatabaseDriver::MYSQL) {
$tables = $database->get_col("SHOW TABLES"); $tables = $database->get_col("SHOW TABLES");
foreach ($tables as $table) { foreach ($tables as $table) {
log_info("upgrade", "converting $table to innodb"); log_info("upgrade", "converting $table to innodb");
@ -84,7 +84,7 @@ class Upgrade extends Extension
$config->set_bool("in_upgrade", true); $config->set_bool("in_upgrade", true);
$config->set_int("db_version", 12); $config->set_int("db_version", 12);
if ($database->get_driver_name() == 'pgsql') { if ($database->get_driver_name() == DatabaseDriver::PGSQL) {
log_info("upgrade", "Changing ext column to VARCHAR"); log_info("upgrade", "Changing ext column to VARCHAR");
$database->execute("ALTER TABLE images ALTER COLUMN ext SET DATA TYPE VARCHAR(4)"); $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); $config->set_int("db_version", 13);
log_info("upgrade", "Changing password column to VARCHAR(250)"); log_info("upgrade", "Changing password column to VARCHAR(250)");
if ($database->get_driver_name() == 'pgsql') { if ($database->get_driver_name() == DatabaseDriver::PGSQL) {
$database->execute("ALTER TABLE users ALTER COLUMN pass SET DATA TYPE VARCHAR(250)"); $database->execute("ALTER TABLE users ALTER COLUMN pass SET DATA TYPE VARCHAR(250)");
} elseif ($database->get_driver_name() == 'mysql') { } elseif ($database->get_driver_name() == DatabaseDriver::MYSQL) {
$database->execute("ALTER TABLE users CHANGE pass pass VARCHAR(250)"); $database->execute("ALTER TABLE users CHANGE pass pass VARCHAR(250)");
} }
@ -116,11 +116,11 @@ class Upgrade extends Extension
$config->set_int("db_version", 14); $config->set_int("db_version", 14);
log_info("upgrade", "Changing tag column to VARCHAR(255)"); log_info("upgrade", "Changing tag column to VARCHAR(255)");
if ($database->get_driver_name() == 'pgsql') { if ($database->get_driver_name() == DatabaseDriver::PGSQL) {
$database->execute('ALTER TABLE tags ALTER COLUMN tag SET DATA TYPE VARCHAR(255)'); $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 oldtag SET DATA TYPE VARCHAR(255)');
$database->execute('ALTER TABLE aliases ALTER COLUMN newtag 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() == DatabaseDriver::MYSQL) {
$database->execute('ALTER TABLE tags MODIFY COLUMN tag VARCHAR(255) NOT NULL'); $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 oldtag VARCHAR(255) NOT NULL');
$database->execute('ALTER TABLE aliases MODIFY COLUMN newtag VARCHAR(255) NOT NULL'); $database->execute('ALTER TABLE aliases MODIFY COLUMN newtag VARCHAR(255) NOT NULL');
@ -129,6 +129,20 @@ class Upgrade extends Extension
log_info("upgrade", "Database at version 14"); log_info("upgrade", "Database at version 14");
$config->set_bool("in_upgrade", false); $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() == 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)))');
}
log_info("upgrade", "Database at version 15");
$config->set_bool("in_upgrade", false);
}
} }
public function get_priority(): int public function get_priority(): int

View File

@ -27,7 +27,6 @@ class DataUploadEvent extends Event
public $merged = false; public $merged = false;
/** /**
* Some data is being uploaded. * Some data is being uploaded.
* This should be caught by a file handler. * This should be caught by a file handler.
@ -49,10 +48,10 @@ class DataUploadEvent extends Event
if ($config->get_bool("upload_use_mime")) { if ($config->get_bool("upload_use_mime")) {
$this->set_type(get_extension_from_mime($tmpname)); $this->set_type(get_extension_from_mime($tmpname));
} else { } else {
if (array_key_exists('extension', $metadata)&&!empty($metadata['extension'])) { if (array_key_exists('extension', $metadata) && !empty($metadata['extension'])) {
$this->type = strtolower($metadata['extension']); $this->type = strtolower($metadata['extension']);
} else { } 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; $sb->position = 10;
// Output the limits from PHP so the user has an idea of what they can set. // 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_int_option("upload_count", "Max uploads: ");
$sb->add_label("<i>PHP Limit = ".ini_get('max_file_uploads')."</i>"); $sb->add_label("<i>PHP Limit = " . ini_get('max_file_uploads') . "</i>");
$sb->add_shorthand_int_option("upload_size", "<br/>Max size per file: "); $sb->add_shorthand_int_option("upload_size", "<br/>Max size per file: ");
$sb->add_label("<i>PHP Limit = ".ini_get('upload_max_filesize')."</i>"); $sb->add_label("<i>PHP Limit = " . ini_get('upload_max_filesize') . "</i>");
$sb->add_choice_option("transload_engine", $tes, "<br/>Transload: "); $sb->add_choice_option("transload_engine", $tes, "<br/>Transload: ");
$sb->add_bool_option("upload_tlsource", "<br/>Use transloaded URL as source if none is provided: "); $sb->add_bool_option("upload_tlsource", "<br/>Use transloaded URL as source if none is provided: ");
$sb->add_bool_option("upload_use_mime", "<br/>Use mime type to determine file types: "); $sb->add_bool_option("upload_use_mime", "<br/>Use mime type to determine file types: ");
@ -314,7 +313,7 @@ class Upload extends Extension
* #param string[] $file * #param string[] $file
* #param string[] $tags * #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; global $page;
@ -348,11 +347,14 @@ class Upload extends Extension
$event = new DataUploadEvent($file['tmp_name'], $metadata); $event = new DataUploadEvent($file['tmp_name'], $metadata);
send_event($event); 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) { } catch (UploadException $ex) {
$this->theme->display_upload_error( $this->theme->display_upload_error(
$page, $page,
"Error with ".html_escape($file['name']), "Error with " . html_escape($file['name']),
$ex->getMessage() $ex->getMessage()
); );
$ok = false; $ok = false;
@ -362,7 +364,7 @@ class Upload extends Extension
return $ok; 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; global $page, $config, $user;
@ -394,8 +396,8 @@ class Upload extends Extension
if (!$headers) { if (!$headers) {
$this->theme->display_upload_error( $this->theme->display_upload_error(
$page, $page,
"Error with ".html_escape($filename), "Error with " . html_escape($filename),
"Error reading from ".html_escape($url) "Error reading from " . html_escape($url)
); );
return false; return false;
} }
@ -403,7 +405,7 @@ class Upload extends Extension
if (filesize($tmp_filename) == 0) { if (filesize($tmp_filename) == 0) {
$this->theme->display_upload_error( $this->theme->display_upload_error(
$page, $page,
"Error with ".html_escape($filename), "Error with " . html_escape($filename),
"No data found -- perhaps the site has hotlink protection?" "No data found -- perhaps the site has hotlink protection?"
); );
$ok = false; $ok = false;
@ -441,10 +443,13 @@ class Upload extends Extension
try { try {
$event = new DataUploadEvent($tmp_filename, $metadata); $event = new DataUploadEvent($tmp_filename, $metadata);
send_event($event); send_event($event);
if ($event->image_id == -1) {
throw new UploadException("File type not supported: " . $metadata['extension']);
}
} catch (UploadException $ex) { } catch (UploadException $ex) {
$this->theme->display_upload_error( $this->theme->display_upload_error(
$page, $page,
"Error with ".html_escape($url), "Error with " . html_escape($url),
$ex->getMessage() $ex->getMessage()
); );
$ok = false; $ok = false;

View File

@ -300,7 +300,7 @@ class UploadTheme extends Themelet
public function display_upload_status(Page $page, bool $ok) public function display_upload_status(Page $page, bool $ok)
{ {
if ($ok) { if ($ok) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link()); $page->set_redirect(make_link());
} else { } else {
$page->set_title("Upload Status"); $page->set_title("Upload Status");

View File

@ -372,7 +372,7 @@ class UserPage extends Extension
if (!is_null($duser)) { if (!is_null($duser)) {
$user = $duser; $user = $duser;
$this->set_login_cookie($duser->name, $pass); $this->set_login_cookie($duser->name, $pass);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
// Try returning to previous page // Try returning to previous page
if ($config->get_int("user_loginshowprofile", 0) == 0 && 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'), "/"); $page->add_cookie("user", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/");
} }
log_info("user", "Logged out"); 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 // Try forwarding to same page on logout unless user comes from registration page
if ($config->get_int("user_loginshowprofile", 0) == 0 && 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']); $uce = new UserCreationEvent($_POST['name'], $_POST['pass1'], $_POST['email']);
send_event($uce); send_event($uce);
$this->set_login_cookie($uce->username, $uce->password); $this->set_login_cookie($uce->username, $uce->password);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user")); $page->set_redirect(make_link("user"));
} catch (UserCreationException $ex) { } catch (UserCreationException $ex) {
$this->theme->display_error(400, "User Creation Error", $ex->getMessage()); $this->theme->display_error(400, "User Creation Error", $ex->getMessage());
@ -532,10 +532,10 @@ class UserPage extends Extension
global $page, $user; global $page, $user;
if ($user->id == $duser->id) { if ($user->id == $duser->id) {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user")); $page->set_redirect(make_link("user"));
} else { } else {
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("user/{$duser->name}")); $page->set_redirect(make_link("user/{$duser->name}"));
} }
} }
@ -698,7 +698,7 @@ class UserPage extends Extension
["id" => $_POST['id']] ["id" => $_POST['id']]
); );
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/list")); $page->set_redirect(make_link("post/list"));
} }
} }

View File

@ -123,7 +123,7 @@ class ViewImage extends Extension
return; return;
} }
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/{$image->id}", $query)); $page->set_redirect(make_link("post/view/{$image->id}", $query));
} elseif ($event->page_matches("post/view")) { } elseif ($event->page_matches("post/view")) {
if (!is_numeric($event->get_arg(0))) { if (!is_numeric($event->get_arg(0))) {
@ -157,7 +157,7 @@ class ViewImage extends Extension
send_event(new ImageInfoSetEvent(Image::by_id($image_id))); 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']))); $page->set_redirect(make_link("post/view/$image_id", url_escape(@$_POST['query'])));
} }
} }

View File

@ -137,7 +137,7 @@ class Wiki extends Extension
send_event(new WikiUpdateEvent($user, $wikipage)); send_event(new WikiUpdateEvent($user, $wikipage));
$u_title = url_escape($title); $u_title = url_escape($title);
$page->set_mode("redirect"); $page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("wiki/$u_title")); $page->set_redirect(make_link("wiki/$u_title"));
} catch (WikiUpdateException $e) { } catch (WikiUpdateException $e) {
$original = $this->get_page($title); $original = $this->get_page($title);
@ -159,7 +159,7 @@ class Wiki extends Extension
["title"=>$_POST["title"], "rev"=>$_POST["revision"]] ["title"=>$_POST["title"], "rev"=>$_POST["revision"]]
); );
$u_title = url_escape($_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")); $page->set_redirect(make_link("wiki/$u_title"));
} }
} elseif ($event->page_matches("wiki_admin/delete_all")) { } elseif ($event->page_matches("wiki_admin/delete_all")) {
@ -170,7 +170,7 @@ class Wiki extends Extension
["title"=>$_POST["title"]] ["title"=>$_POST["title"]]
); );
$u_title = url_escape($_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")); $page->set_redirect(make_link("wiki/$u_title"));
} }
} }
@ -213,7 +213,7 @@ class Wiki extends Extension
return false; return false;
} }
private function get_page(string $title): WikiPage private function get_page(string $title, int $revision=-1): WikiPage
{ {
global $database; global $database;
// first try and get the actual page // first try and get the actual page
@ -222,21 +222,17 @@ class Wiki extends Extension
SELECT * SELECT *
FROM wiki_pages FROM wiki_pages
WHERE SCORE_STRNORM(title) LIKE SCORE_STRNORM(:title) WHERE SCORE_STRNORM(title) LIKE SCORE_STRNORM(:title)
ORDER BY revision DESC ORDER BY revision DESC"),
LIMIT 1
"),
["title"=>$title] ["title"=>$title]
); );
// fall back to wiki:default // fall back to wiki:default
if (empty($row)) { if (empty($row)) {
$row = $database->get_row(" $row = $database->get_row("
SELECT * SELECT *
FROM wiki_pages FROM wiki_pages
WHERE title LIKE :title WHERE title LIKE :title
ORDER BY revision DESC ORDER BY revision DESC", ["title"=>"wiki:default"]);
LIMIT 1
", ["title"=>"wiki:default"]);
// fall further back to manual // fall further back to manual
if (empty($row)) { if (empty($row)) {

View File

@ -52,7 +52,7 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase
$_POST = []; $_POST = [];
$page = class_exists("CustomPage") ? new CustomPage() : new Page(); $page = class_exists("CustomPage") ? new CustomPage() : new Page();
send_event(new PageRequestEvent($page_name)); send_event(new PageRequestEvent($page_name));
if ($page->mode == "redirect") { if ($page->mode == PageMode::REDIRECT) {
$page->code = 302; $page->code = 302;
} }
} }
@ -68,7 +68,7 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase
$_POST = $args; $_POST = $args;
$page = class_exists("CustomPage") ? new CustomPage() : new Page(); $page = class_exists("CustomPage") ? new CustomPage() : new Page();
send_event(new PageRequestEvent($page_name)); send_event(new PageRequestEvent($page_name));
if ($page->mode == "redirect") { if ($page->mode == PageMode::REDIRECT) {
$page->code = 302; $page->code = 302;
} }
} }

View File

@ -4,7 +4,7 @@ class CustomHomeTheme extends HomeTheme
{ {
public function display_page(Page $page, $sitename, $base_href, $theme_name, $body) 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(); $page->add_auto_html_headers();
$hh = $page->get_all_html_headers(); $hh = $page->get_all_html_headers();
$page->set_data( $page->set_data(