diff --git a/.editorconfig b/.editorconfig index 9c622947..15d2c086 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,6 +16,6 @@ insert_final_newline = true [*.{js,css,php}] charset = utf-8 -indent_style = tab +indent_style = space indent_size = 4 diff --git a/.gitignore b/.gitignore index 98c90ae5..e2053c51 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ images thumbs *.phar *.sqlite +.php_cs.cache #Composer composer.phar diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 00000000..9430b4e5 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,18 @@ +exclude('ext/amazon_s3/lib') + ->exclude('vendor') + ->in(__DIR__) +; + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR2' => true, + //'strict_param' => true, + 'array_syntax' => ['syntax' => 'short'], + ]) + ->setFinder($finder) +; + +?> diff --git a/core/_bootstrap.php b/core/_bootstrap.php index 025a4e6a..2611854e 100644 --- a/core/_bootstrap.php +++ b/core/_bootstrap.php @@ -19,14 +19,14 @@ _sanitise_environment(); // load base files $_shm_ctx->log_start("Opening files"); $_shm_files = array_merge( - zglob("core/*.php"), - zglob("core/{".ENABLED_MODS."}/*.php"), - zglob("ext/{".ENABLED_EXTS."}/main.php") + zglob("core/*.php"), + zglob("core/{".ENABLED_MODS."}/*.php"), + zglob("ext/{".ENABLED_EXTS."}/main.php") ); -foreach($_shm_files as $_shm_filename) { - if(basename($_shm_filename)[0] != "_") { - require_once $_shm_filename; - } +foreach ($_shm_files as $_shm_filename) { + if (basename($_shm_filename)[0] != "_") { + require_once $_shm_filename; + } } unset($_shm_files); unset($_shm_filename); @@ -40,8 +40,8 @@ $_shm_ctx->log_endok(); // load the theme parts $_shm_ctx->log_start("Loading themelets"); -foreach(_get_themelet_files(get_theme()) as $themelet) { - require_once $themelet; +foreach (_get_themelet_files(get_theme()) as $themelet) { + require_once $themelet; } unset($themelet); $page = class_exists("CustomPage") ? new CustomPage() : new Page(); diff --git a/core/_install.php b/core/_install.php index 177a1267..527708fa 100644 --- a/core/_install.php +++ b/core/_install.php @@ -7,7 +7,7 @@ * @author Shish [webmaster at shishnet.org], jgen [jeffgenovy at gmail.com] * @link http://code.shishnet.org/shimmie2/ * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 - * + * * Initialise the database, check that folder * permissions are set properly. * @@ -30,7 +30,7 @@ date_default_timezone_set('UTC');
- +- +EOD; - exit(2); - } + exit(2); + } - $db->create_table("aliases", " + $db->create_table("aliases", " oldtag VARCHAR(128) NOT NULL, newtag VARCHAR(128) NOT NULL, PRIMARY KEY (oldtag) "); - $db->execute("CREATE INDEX aliases_newtag_idx ON aliases(newtag)", array()); + $db->execute("CREATE INDEX aliases_newtag_idx ON aliases(newtag)", []); - $db->create_table("config", " + $db->create_table("config", " name VARCHAR(128) NOT NULL, value TEXT, PRIMARY KEY (name) "); - $db->create_table("users", " + $db->create_table("users", " id SCORE_AIPK, name VARCHAR(32) UNIQUE NOT NULL, pass VARCHAR(250), @@ -289,9 +293,9 @@ EOD; class VARCHAR(32) NOT NULL DEFAULT 'user', email VARCHAR(128) "); - $db->execute("CREATE INDEX users_name_idx ON users(name)", array()); + $db->execute("CREATE INDEX users_name_idx ON users(name)", []); - $db->create_table("images", " + $db->create_table("images", " id SCORE_AIPK, owner_id INTEGER NOT NULL, owner_ip SCORE_INET NOT NULL, @@ -306,69 +310,72 @@ EOD; locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N, FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT "); - $db->execute("CREATE INDEX images_owner_id_idx ON images(owner_id)", array()); - $db->execute("CREATE INDEX images_width_idx ON images(width)", array()); - $db->execute("CREATE INDEX images_height_idx ON images(height)", array()); - $db->execute("CREATE INDEX images_hash_idx ON images(hash)", array()); + $db->execute("CREATE INDEX images_owner_id_idx ON images(owner_id)", []); + $db->execute("CREATE INDEX images_width_idx ON images(width)", []); + $db->execute("CREATE INDEX images_height_idx ON images(height)", []); + $db->execute("CREATE INDEX images_hash_idx ON images(hash)", []); - $db->create_table("tags", " + $db->create_table("tags", " id SCORE_AIPK, tag VARCHAR(64) UNIQUE NOT NULL, count INTEGER NOT NULL DEFAULT 0 "); - $db->execute("CREATE INDEX tags_tag_idx ON tags(tag)", array()); + $db->execute("CREATE INDEX tags_tag_idx ON tags(tag)", []); - $db->create_table("image_tags", " + $db->create_table("image_tags", " image_id INTEGER NOT NULL, tag_id INTEGER NOT NULL, UNIQUE(image_id, tag_id), FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE, FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE "); - $db->execute("CREATE INDEX images_tags_image_id_idx ON image_tags(image_id)", array()); - $db->execute("CREATE INDEX images_tags_tag_id_idx ON image_tags(tag_id)", array()); + $db->execute("CREATE INDEX images_tags_image_id_idx ON image_tags(image_id)", []); + $db->execute("CREATE INDEX images_tags_tag_id_idx ON image_tags(tag_id)", []); - $db->execute("INSERT INTO config(name, value) VALUES('db_version', 11)"); - $db->commit(); - } - catch(PDOException $e) { - handle_db_errors(TRUE, "An error occurred while trying to create the database tables necessary for Shimmie.", $e->getMessage(), 3); - } catch (Exception $e) { - handle_db_errors(FALSE, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 4); - } + $db->execute("INSERT INTO config(name, value) VALUES('db_version', 11)"); + $db->commit(); + } catch (PDOException $e) { + handle_db_errors(true, "An error occurred while trying to create the database tables necessary for Shimmie.", $e->getMessage(), 3); + } catch (Exception $e) { + handle_db_errors(false, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 4); + } } // }}} -function insert_defaults() { // {{{ - try { - $db = new Database(); +function insert_defaults() +{ // {{{ + try { + $db = new Database(); - $db->execute("INSERT INTO users(name, pass, joindate, class) VALUES(:name, :pass, now(), :class)", Array("name" => 'Anonymous', "pass" => null, "class" => 'anonymous')); - $db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", Array("name" => 'anon_id', "value" => $db->get_last_insert_id('users_id_seq'))); + $db->execute("INSERT INTO users(name, pass, joindate, class) VALUES(:name, :pass, now(), :class)", ["name" => 'Anonymous', "pass" => null, "class" => 'anonymous']); + $db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", ["name" => 'anon_id', "value" => $db->get_last_insert_id('users_id_seq')]); - if(check_im_version() > 0) { - $db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", Array("name" => 'thumb_engine', "value" => 'convert')); - } - $db->commit(); - } - catch(PDOException $e) { - handle_db_errors(TRUE, "An error occurred while trying to insert data into the database.", $e->getMessage(), 5); - } - catch (Exception $e) { - handle_db_errors(FALSE, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 6); - } + if (check_im_version() > 0) { + $db->execute("INSERT INTO config(name, value) VALUES(:name, :value)", ["name" => 'thumb_engine', "value" => 'convert']); + } + $db->commit(); + } catch (PDOException $e) { + handle_db_errors(true, "An error occurred while trying to insert data into the database.", $e->getMessage(), 5); + } catch (Exception $e) { + handle_db_errors(false, "An unknown error occurred while trying to insert data into the database.", $e->getMessage(), 6); + } } // }}} -function build_dirs() { // {{{ - // *try* and make default dirs. Ignore any errors -- - // if something is amiss, we'll tell the user later - if(!file_exists("data")) @mkdir("data"); - if(!is_writable("data")) @chmod("data", 0755); +function build_dirs() +{ // {{{ + // *try* and make default dirs. Ignore any errors -- + // if something is amiss, we'll tell the user later + if (!file_exists("data")) { + @mkdir("data"); + } + if (!is_writable("data")) { + @chmod("data", 0755); + } - // Clear file status cache before checking again. - clearstatcache(); + // Clear file status cache before checking again. + clearstatcache(); - if(!file_exists("data") || !is_writable("data")) { - print " + if (!file_exists("data") || !is_writable("data")) { + print "Install Error
Warning: Composer vendor folder does not exist!
@@ -65,112 +65,114 @@ require_once "core/cacheengine.php"; require_once "core/dbengine.php"; require_once "core/database.php"; -if(is_readable("data/config/shimmie.conf.php")) die("Shimmie is already installed."); +if (is_readable("data/config/shimmie.conf.php")) { + die("Shimmie is already installed."); +} do_install(); // utilities {{{ - // TODO: Can some of these be pushed into "core/???.inc.php" ? + // TODO: Can some of these be pushed into "core/???.inc.php" ? -function check_gd_version(): int { - $gdversion = 0; +function check_gd_version(): int +{ + $gdversion = 0; - if (function_exists('gd_info')){ - $gd_info = gd_info(); - if (substr_count($gd_info['GD Version'], '2.')) { - $gdversion = 2; - } else if (substr_count($gd_info['GD Version'], '1.')) { - $gdversion = 1; - } - } + if (function_exists('gd_info')) { + $gd_info = gd_info(); + if (substr_count($gd_info['GD Version'], '2.')) { + $gdversion = 2; + } elseif (substr_count($gd_info['GD Version'], '1.')) { + $gdversion = 1; + } + } - return $gdversion; + return $gdversion; } -function check_im_version(): int { - $convert_check = exec("convert"); +function check_im_version(): int +{ + $convert_check = exec("convert"); - return (empty($convert_check) ? 0 : 1); + return (empty($convert_check) ? 0 : 1); } -function eok($name, $value) { - echo "
$name ... "; - if($value) { - echo "ok\n"; - } - else { - echo "failed\n"; - } +function eok($name, $value) +{ + echo "
$name ... "; + if ($value) { + echo "ok\n"; + } else { + echo "failed\n"; + } } // }}} -function do_install() { // {{{ - if(file_exists("data/config/auto_install.conf.php")) { - require_once "data/config/auto_install.conf.php"; - } - else if(@$_POST["database_type"] == "sqlite") { - $id = bin2hex(random_bytes(5)); - define('DATABASE_DSN', "sqlite:data/shimmie.{$id}.sqlite"); - } - else if(isset($_POST['database_type']) && isset($_POST['database_host']) && isset($_POST['database_user']) && isset($_POST['database_name'])) { - define('DATABASE_DSN', "{$_POST['database_type']}:user={$_POST['database_user']};password={$_POST['database_password']};host={$_POST['database_host']};dbname={$_POST['database_name']}"); - } - else { - ask_questions(); - return; - } +function do_install() +{ // {{{ + if (file_exists("data/config/auto_install.conf.php")) { + require_once "data/config/auto_install.conf.php"; + } elseif (@$_POST["database_type"] == "sqlite") { + $id = bin2hex(random_bytes(5)); + define('DATABASE_DSN', "sqlite:data/shimmie.{$id}.sqlite"); + } elseif (isset($_POST['database_type']) && isset($_POST['database_host']) && isset($_POST['database_user']) && isset($_POST['database_name'])) { + define('DATABASE_DSN', "{$_POST['database_type']}:user={$_POST['database_user']};password={$_POST['database_password']};host={$_POST['database_host']};dbname={$_POST['database_name']}"); + } else { + ask_questions(); + return; + } - define("CACHE_DSN", null); - define("DEBUG_SQL", false); - define("DATABASE_KA", true); - install_process(); + define("CACHE_DSN", null); + define("DEBUG_SQL", false); + define("DATABASE_KA", true); + install_process(); } // }}} -function ask_questions() { // {{{ - $warnings = array(); - $errors = array(); +function ask_questions() +{ // {{{ + $warnings = []; + $errors = []; - if(check_gd_version() == 0 && check_im_version() == 0) { - $errors[] = " + if (check_gd_version() == 0 && check_im_version() == 0) { + $errors[] = " No thumbnailers could be found - install the imagemagick tools (or the PHP-GD library, if imagemagick is unavailable). "; - } - else if(check_im_version() == 0) { - $warnings[] = " + } elseif (check_im_version() == 0) { + $warnings[] = " The 'convert' command (from the imagemagick package) could not be found - PHP-GD can be used instead, but the size of thumbnails will be limited. "; - } + } - if(!function_exists('mb_strlen')) { - $errors[] = " + if (!function_exists('mb_strlen')) { + $errors[] = " The mbstring PHP extension is missing - multibyte languages (eg non-english languages) may not work right. "; - } + } - $drivers = PDO::getAvailableDrivers(); - if( - !in_array("mysql", $drivers) && - !in_array("pgsql", $drivers) && - !in_array("sqlite", $drivers) - ) { - $errors[] = " + $drivers = PDO::getAvailableDrivers(); + if ( + !in_array("mysql", $drivers) && + !in_array("pgsql", $drivers) && + !in_array("sqlite", $drivers) + ) { + $errors[] = " No database connection library could be found; shimmie needs PDO with either Postgres, MySQL, or SQLite drivers "; - } + } - $db_m = in_array("mysql", $drivers) ? '' : ""; - $db_p = in_array("pgsql", $drivers) ? '' : ""; - $db_s = in_array("sqlite", $drivers) ? '' : ""; + $db_m = in_array("mysql", $drivers) ? '' : ""; + $db_p = in_array("pgsql", $drivers) ? '' : ""; + $db_s = in_array("sqlite", $drivers) ? '' : ""; - $warn_msg = $warnings ? "Warnings
".implode("\n", $warnings) : ""; - $err_msg = $errors ? "
Errors
".implode("\n", $errors) : ""; + $warn_msg = $warnings ? "
Warnings
".implode("\n", $warnings) : ""; + $err_msg = $errors ? "
Errors
".implode("\n", $errors) : ""; - print <<
Shimmie Installer
@@ -243,19 +245,21 @@ EOD; /** * This is where the install really takes place. */ -function install_process() { // {{{ - build_dirs(); - create_tables(); - insert_defaults(); - write_config(); +function install_process() +{ // {{{ + build_dirs(); + create_tables(); + insert_defaults(); + write_config(); } // }}} -function create_tables() { // {{{ - try { - $db = new Database(); +function create_tables() +{ // {{{ + try { + $db = new Database(); - if ( $db->count_tables() > 0 ) { - print <<count_tables() > 0) { + print << Shimmie Installer
Warning: The Database schema is not empty!
@@ -266,22 +270,22 @@ function create_tables() { // {{{"; - exit(7); - } + exit(7); + } } // }}} -function write_config() { // {{{ - $file_content = '<' . '?php' . "\n" . - "define('DATABASE_DSN', '".DATABASE_DSN."');\n" . - '?' . '>'; +function write_config() +{ // {{{ + $file_content = '<' . '?php' . "\n" . + "define('DATABASE_DSN', '".DATABASE_DSN."');\n" . + '?' . '>'; - if(!file_exists("data/config")) { - mkdir("data/config", 0755, true); - } + if (!file_exists("data/config")) { + mkdir("data/config", 0755, true); + } - if(file_put_contents("data/config/shimmie.conf.php", $file_content, LOCK_EX)) { - header("Location: index.php"); - print <<Shimmie Installer
Directory Permissions Error:
@@ -381,22 +388,23 @@ function build_dirs() { // {{{Shimmie Installer
Things are OK \o/
@@ -405,10 +413,9 @@ function write_config() { // {{{ EOD; - } - else { - $h_file_content = htmlentities($file_content); - print <<Shimmie Installer
File Permissions Error:
@@ -425,13 +432,14 @@ EOD; EOD; - } - echo "\n"; + } + echo "\n"; } // }}} -function handle_db_errors(bool $isPDO, string $errorMessage1, string $errorMessage2, int $exitCode) { - $errorMessage1Extra = ($isPDO ? "Please check and ensure that the database configuration options are all correct." : "Please check the server log files for more information."); - print <<Shimmie Installer
Unknown Error:
@@ -442,7 +450,7 @@ function handle_db_errors(bool $isPDO, string $errorMessage1, string $errorMessa EOD; - exit($exitCode); + exit($exitCode); } ?> diff --git a/core/basethemelet.php b/core/basethemelet.php index 77af37d4..8ff6eab1 100644 --- a/core/basethemelet.php +++ b/core/basethemelet.php @@ -5,117 +5,135 @@ * * A collection of common functions for theme parts */ -class BaseThemelet { +class BaseThemelet +{ - /** - * Generic error message display - */ - public function display_error(int $code, string $title, string $message): void { - global $page; - $page->set_code($code); - $page->set_title($title); - $page->set_heading($title); - $has_nav = false; - foreach($page->blocks as $block) { - if($block->header == "Navigation") { - $has_nav = true; - break; - } - } - if(!$has_nav) { - $page->add_block(new NavBlock()); - } - $page->add_block(new Block("Error", $message)); - } + /** + * Generic error message display + */ + public function display_error(int $code, string $title, string $message): void + { + global $page; + $page->set_code($code); + $page->set_title($title); + $page->set_heading($title); + $has_nav = false; + foreach ($page->blocks as $block) { + if ($block->header == "Navigation") { + $has_nav = true; + break; + } + } + if (!$has_nav) { + $page->add_block(new NavBlock()); + } + $page->add_block(new Block("Error", $message)); + } - /** - * A specific, common error message - */ - public function display_permission_denied(): void { - $this->display_error(403, "Permission Denied", "You do not have permission to access this page"); - } + /** + * A specific, common error message + */ + public function display_permission_denied(): void + { + $this->display_error(403, "Permission Denied", "You do not have permission to access this page"); + } - /** - * Generic thumbnail code; returns HTML rather than adding - * a block since thumbs tend to go inside blocks... - */ - public function build_thumb_html(Image $image): string { - global $config; + /** + * Generic thumbnail code; returns HTML rather than adding + * a block since thumbs tend to go inside blocks... + */ + public function build_thumb_html(Image $image): string + { + global $config; - $i_id = (int) $image->id; - $h_view_link = make_link('post/view/'.$i_id); - $h_thumb_link = $image->get_thumb_link(); - $h_tip = html_escape($image->get_tooltip()); - $h_tags = html_escape(strtolower($image->get_tag_list())); + $i_id = (int) $image->id; + $h_view_link = make_link('post/view/'.$i_id); + $h_thumb_link = $image->get_thumb_link(); + $h_tip = html_escape($image->get_tooltip()); + $h_tags = html_escape(strtolower($image->get_tag_list())); - $extArr = array_flip(array('swf', 'svg', 'mp3')); //List of thumbless filetypes - if(!isset($extArr[$image->ext])){ - $tsize = get_thumbnail_size($image->width, $image->height); - }else{ - //Use max thumbnail size if using thumbless filetype - $tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height')); - } + $extArr = array_flip(['swf', 'svg', 'mp3']); //List of thumbless filetypes + if (!isset($extArr[$image->ext])) { + $tsize = get_thumbnail_size($image->width, $image->height); + } else { + //Use max thumbnail size if using thumbless filetype + $tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height')); + } - $custom_classes = ""; - if(class_exists("Relationships")){ - if(property_exists($image, 'parent_id') && $image->parent_id !== NULL){ $custom_classes .= "shm-thumb-has_parent "; } - if(property_exists($image, 'has_children') && bool_escape($image->has_children)){ $custom_classes .= "shm-thumb-has_child "; } - } + $custom_classes = ""; + if (class_exists("Relationships")) { + if (property_exists($image, 'parent_id') && $image->parent_id !== null) { + $custom_classes .= "shm-thumb-has_parent "; + } + if (property_exists($image, 'has_children') && bool_escape($image->has_children)) { + $custom_classes .= "shm-thumb-has_child "; + } + } - return "". - "". - "\n"; - } + return "". + "". + "\n"; + } - public function display_paginator(Page $page, string $base, string $query=null, int $page_number, int $total_pages, bool $show_random = FALSE) { - if($total_pages == 0) $total_pages = 1; - $body = $this->build_paginator($page_number, $total_pages, $base, $query, $show_random); - $page->add_block(new Block(null, $body, "main", 90, "paginator")); - } + public function display_paginator(Page $page, string $base, string $query=null, int $page_number, int $total_pages, bool $show_random = false) + { + if ($total_pages == 0) { + $total_pages = 1; + } + $body = $this->build_paginator($page_number, $total_pages, $base, $query, $show_random); + $page->add_block(new Block(null, $body, "main", 90, "paginator")); + } - private function gen_page_link(string $base_url, string $query=null, string $page, string $name): string { - $link = make_link($base_url.'/'.$page, $query); - return ''.$name.''; - } + private function gen_page_link(string $base_url, string $query=null, string $page, string $name): string + { + $link = make_link($base_url.'/'.$page, $query); + return ''.$name.''; + } - private function gen_page_link_block(string $base_url, string $query=null, string $page, int $current_page, string $name): string { - $paginator = ""; - if($page == $current_page) $paginator .= ""; - $paginator .= $this->gen_page_link($base_url, $query, $page, $name); - if($page == $current_page) $paginator .= ""; - return $paginator; - } + private function gen_page_link_block(string $base_url, string $query=null, string $page, int $current_page, string $name): string + { + $paginator = ""; + if ($page == $current_page) { + $paginator .= ""; + } + $paginator .= $this->gen_page_link($base_url, $query, $page, $name); + if ($page == $current_page) { + $paginator .= ""; + } + return $paginator; + } - private function build_paginator(int $current_page, int $total_pages, string $base_url, string $query=null, bool $show_random): string { - $next = $current_page + 1; - $prev = $current_page - 1; + private function build_paginator(int $current_page, int $total_pages, string $base_url, string $query=null, bool $show_random): string + { + $next = $current_page + 1; + $prev = $current_page - 1; - $at_start = ($current_page <= 1 || $total_pages <= 1); - $at_end = ($current_page >= $total_pages); + $at_start = ($current_page <= 1 || $total_pages <= 1); + $at_end = ($current_page >= $total_pages); - $first_html = $at_start ? "First" : $this->gen_page_link($base_url, $query, 1, "First"); - $prev_html = $at_start ? "Prev" : $this->gen_page_link($base_url, $query, $prev, "Prev"); + $first_html = $at_start ? "First" : $this->gen_page_link($base_url, $query, 1, "First"); + $prev_html = $at_start ? "Prev" : $this->gen_page_link($base_url, $query, $prev, "Prev"); - $random_html = "-"; - if($show_random) { - $rand = mt_rand(1, $total_pages); - $random_html = $this->gen_page_link($base_url, $query, $rand, "Random"); - } + $random_html = "-"; + if ($show_random) { + $rand = mt_rand(1, $total_pages); + $random_html = $this->gen_page_link($base_url, $query, $rand, "Random"); + } - $next_html = $at_end ? "Next" : $this->gen_page_link($base_url, $query, $next, "Next"); - $last_html = $at_end ? "Last" : $this->gen_page_link($base_url, $query, $total_pages, "Last"); + $next_html = $at_end ? "Next" : $this->gen_page_link($base_url, $query, $next, "Next"); + $last_html = $at_end ? "Last" : $this->gen_page_link($base_url, $query, $total_pages, "Last"); - $start = $current_page-5 > 1 ? $current_page-5 : 1; - $end = $start+10 < $total_pages ? $start+10 : $total_pages; + $start = $current_page-5 > 1 ? $current_page-5 : 1; + $end = $start+10 < $total_pages ? $start+10 : $total_pages; - $pages = array(); - foreach(range($start, $end) as $i) { - $pages[] = $this->gen_page_link_block($base_url, $query, $i, $current_page, $i); - } - $pages_html = implode(" | ", $pages); + $pages = []; + foreach (range($start, $end) as $i) { + $pages[] = $this->gen_page_link_block($base_url, $query, $i, $current_page, $i); + } + $pages_html = implode(" | ", $pages); - return $first_html.' | '.$prev_html.' | '.$random_html.' | '.$next_html.' | '.$last_html - .'
<< '.$pages_html.' >>'; - } + return $first_html.' | '.$prev_html.' | '.$random_html.' | '.$next_html.' | '.$last_html + .'
<< '.$pages_html.' >>'; + } } diff --git a/core/block.php b/core/block.php index 737ca3f8..70c8c690 100644 --- a/core/block.php +++ b/core/block.php @@ -5,79 +5,86 @@ * * A basic chunk of a page. */ -class Block { - /** - * The block's title. - * - * @var string - */ - public $header; +class Block +{ + /** + * The block's title. + * + * @var string + */ + public $header; - /** - * The content of the block. - * - * @var string - */ - public $body; + /** + * The content of the block. + * + * @var string + */ + public $body; - /** - * Where the block should be placed. The default theme supports - * "main" and "left", other themes can add their own areas. - * - * @var string - */ - public $section; + /** + * Where the block should be placed. The default theme supports + * "main" and "left", other themes can add their own areas. + * + * @var string + */ + public $section; - /** - * How far down the section the block should appear, higher - * numbers appear lower. The scale is 0-100 by convention, - * though any number or string will work. - * - * @var int - */ - public $position; + /** + * How far down the section the block should appear, higher + * numbers appear lower. The scale is 0-100 by convention, + * though any number or string will work. + * + * @var int + */ + public $position; - /** - * A unique ID for the block. - * - * @var string - */ - public $id; + /** + * A unique ID for the block. + * + * @var string + */ + public $id; - /** - * Should this block count as content for the sake of - * the 404 handler - * - * @var boolean - */ - public $is_content = true; + /** + * Should this block count as content for the sake of + * the 404 handler + * + * @var boolean + */ + public $is_content = true; - public function __construct(string $header=null, string $body=null, string $section="main", int $position=50, string $id=null) { - $this->header = $header; - $this->body = $body; - $this->section = $section; - $this->position = $position; + public function __construct(string $header=null, string $body=null, string $section="main", int $position=50, string $id=null) + { + $this->header = $header; + $this->body = $body; + $this->section = $section; + $this->position = $position; - if(is_null($id)) { - $id = (empty($header) ? md5($body) : $header) . $section; - } - $this->id = preg_replace('/[^\w]/', '',str_replace(' ', '_', $id)); - } + if (is_null($id)) { + $id = (empty($header) ? md5($body) : $header) . $section; + } + $this->id = preg_replace('/[^\w]/', '', str_replace(' ', '_', $id)); + } - /** - * Get the HTML for this block. - */ - public function get_html(bool $hidable=false): string { - $h = $this->header; - $b = $this->body; - $i = $this->id; - $html = ""; - $h_toggler = $hidable ? " shm-toggler" : ""; - if(!empty($h)) $html .= " \n"; - return $html; - } + /** + * Get the HTML for this block. + */ + public function get_html(bool $hidable=false): string + { + $h = $this->header; + $b = $this->body; + $i = $this->id; + $html = "$h
"; - if(!empty($b)) $html .= "$b"; - $html .= ""; + $h_toggler = $hidable ? " shm-toggler" : ""; + if (!empty($h)) { + $html .= " \n"; + return $html; + } } @@ -89,8 +96,10 @@ class Block { * Used because "new NavBlock()" is easier than "new Block('Navigation', ..." * */ -class NavBlock extends Block { - public function __construct() { - parent::__construct("Navigation", "Index", "left", 0); - } +class NavBlock extends Block +{ + public function __construct() + { + parent::__construct("Navigation", "Index", "left", 0); + } } diff --git a/core/cacheengine.php b/core/cacheengine.php index 40be954e..c1e19e64 100644 --- a/core/cacheengine.php +++ b/core/cacheengine.php @@ -1,196 +1,228 @@ memcache = new Memcache; - @$this->memcache->pconnect($hp[0], $hp[1]); - } + public function __construct(string $args) + { + $hp = explode(":", $args); + $this->memcache = new Memcache; + @$this->memcache->pconnect($hp[0], $hp[1]); + } - public function get(string $key) { - return $this->memcache->get($key); - } + public function get(string $key) + { + return $this->memcache->get($key); + } - public function set(string $key, $val, int $time=0) { - $this->memcache->set($key, $val, false, $time); - } + public function set(string $key, $val, int $time=0) + { + $this->memcache->set($key, $val, false, $time); + } - public function delete(string $key) { - $this->memcache->delete($key); - } + public function delete(string $key) + { + $this->memcache->delete($key); + } } -class MemcachedCache implements CacheEngine { - /** @var \Memcached|null */ - public $memcache=null; +class MemcachedCache implements CacheEngine +{ + /** @var \Memcached|null */ + public $memcache=null; - public function __construct(string $args) { - $hp = explode(":", $args); - $this->memcache = new Memcached; - #$this->memcache->setOption(Memcached::OPT_COMPRESSION, False); - #$this->memcache->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP); - #$this->memcache->setOption(Memcached::OPT_PREFIX_KEY, phpversion()); - $this->memcache->addServer($hp[0], $hp[1]); - } + public function __construct(string $args) + { + $hp = explode(":", $args); + $this->memcache = new Memcached; + #$this->memcache->setOption(Memcached::OPT_COMPRESSION, False); + #$this->memcache->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP); + #$this->memcache->setOption(Memcached::OPT_PREFIX_KEY, phpversion()); + $this->memcache->addServer($hp[0], $hp[1]); + } - public function get(string $key) { - $key = urlencode($key); + public function get(string $key) + { + $key = urlencode($key); - $val = $this->memcache->get($key); - $res = $this->memcache->getResultCode(); + $val = $this->memcache->get($key); + $res = $this->memcache->getResultCode(); - if($res == Memcached::RES_SUCCESS) { - return $val; - } - else if($res == Memcached::RES_NOTFOUND) { - return false; - } - else { - error_log("Memcached error during get($key): $res"); - return false; - } - } + if ($res == Memcached::RES_SUCCESS) { + return $val; + } elseif ($res == Memcached::RES_NOTFOUND) { + return false; + } else { + error_log("Memcached error during get($key): $res"); + return false; + } + } - public function set(string $key, $val, int $time=0) { - $key = urlencode($key); + public function set(string $key, $val, int $time=0) + { + $key = urlencode($key); - $this->memcache->set($key, $val, $time); - $res = $this->memcache->getResultCode(); - if($res != Memcached::RES_SUCCESS) { - error_log("Memcached error during set($key): $res"); - } - } + $this->memcache->set($key, $val, $time); + $res = $this->memcache->getResultCode(); + if ($res != Memcached::RES_SUCCESS) { + error_log("Memcached error during set($key): $res"); + } + } - public function delete(string $key) { - $key = urlencode($key); + public function delete(string $key) + { + $key = urlencode($key); - $this->memcache->delete($key); - $res = $this->memcache->getResultCode(); - if($res != Memcached::RES_SUCCESS && $res != Memcached::RES_NOTFOUND) { - error_log("Memcached error during delete($key): $res"); - } - } + $this->memcache->delete($key); + $res = $this->memcache->getResultCode(); + if ($res != Memcached::RES_SUCCESS && $res != Memcached::RES_NOTFOUND) { + error_log("Memcached error during delete($key): $res"); + } + } } -class APCCache implements CacheEngine { - public function __construct(string $args) { - // $args is not used, but is passed in when APC cache is created. - } +class APCCache implements CacheEngine +{ + public function __construct(string $args) + { + // $args is not used, but is passed in when APC cache is created. + } - public function get(string $key) { - return apc_fetch($key); - } + public function get(string $key) + { + return apc_fetch($key); + } - public function set(string $key, $val, int $time=0) { - apc_store($key, $val, $time); - } + public function set(string $key, $val, int $time=0) + { + apc_store($key, $val, $time); + } - public function delete(string $key) { - apc_delete($key); - } + public function delete(string $key) + { + apc_delete($key); + } } -class RedisCache implements CacheEngine { - private $redis=null; +class RedisCache implements CacheEngine +{ + private $redis=null; - public function __construct(string $args) { - $this->redis = new Redis(); - $hp = explode(":", $args); - $this->redis->pconnect($hp[0], $hp[1]); - $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); - $this->redis->setOption(Redis::OPT_PREFIX, 'shm:'); - } + public function __construct(string $args) + { + $this->redis = new Redis(); + $hp = explode(":", $args); + $this->redis->pconnect($hp[0], $hp[1]); + $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); + $this->redis->setOption(Redis::OPT_PREFIX, 'shm:'); + } - public function get(string $key) { - return $this->redis->get($key); - } + public function get(string $key) + { + return $this->redis->get($key); + } - public function set(string $key, $val, int $time=0) { - if($time > 0) { - $this->redis->setEx($key, $time, $val); - } - else { - $this->redis->set($key, $val); - } - } + public function set(string $key, $val, int $time=0) + { + if ($time > 0) { + $this->redis->setEx($key, $time, $val); + } else { + $this->redis->set($key, $val); + } + } - public function delete(string $key) { - $this->redis->delete($key); - } + public function delete(string $key) + { + $this->redis->delete($key); + } } -class Cache { - public $engine; - public $hits=0, $misses=0; - public $time=0; +class Cache +{ + public $engine; + public $hits=0; + public $misses=0; + public $time=0; - public function __construct(?string $dsn) { - $matches = array(); - if($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches)) { - if($matches[1] == "memcache") { - $c = new MemcacheCache($matches[2]); - } - else if($matches[1] == "memcached") { - $c = new MemcachedCache($matches[2]); - } - else if($matches[1] == "apc") { - $c = new APCCache($matches[2]); - } - else if($matches[1] == "redis") { - $c = new RedisCache($matches[2]); - } - } - else { - $c = new NoCache(); - } - $this->engine = $c; - } + public function __construct(?string $dsn) + { + $matches = []; + if ($dsn && preg_match("#(.*)://(.*)#", $dsn, $matches)) { + if ($matches[1] == "memcache") { + $c = new MemcacheCache($matches[2]); + } elseif ($matches[1] == "memcached") { + $c = new MemcachedCache($matches[2]); + } elseif ($matches[1] == "apc") { + $c = new APCCache($matches[2]); + } elseif ($matches[1] == "redis") { + $c = new RedisCache($matches[2]); + } + } else { + $c = new NoCache(); + } + $this->engine = $c; + } - public function get(string $key) { - $val = $this->engine->get($key); - if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { - $hit = $val === false ? "hit" : "miss"; - file_put_contents("data/cache.log", "Cache $hit: $key\n", FILE_APPEND); - } - if($val !== false) { - $this->hits++; - return $val; - } - else { - $this->misses++; - return false; - } - } + public function get(string $key) + { + $val = $this->engine->get($key); + if ((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { + $hit = $val === false ? "hit" : "miss"; + file_put_contents("data/cache.log", "Cache $hit: $key\n", FILE_APPEND); + } + if ($val !== false) { + $this->hits++; + return $val; + } else { + $this->misses++; + return false; + } + } - public function set(string $key, $val, int $time=0) { - $this->engine->set($key, $val, $time); - if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { - file_put_contents("data/cache.log", "Cache set: $key ($time)\n", FILE_APPEND); - } - } + public function set(string $key, $val, int $time=0) + { + $this->engine->set($key, $val, $time); + if ((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { + file_put_contents("data/cache.log", "Cache set: $key ($time)\n", FILE_APPEND); + } + } - public function delete(string $key) { - $this->engine->delete($key); - if((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { - file_put_contents("data/cache.log", "Cache delete: $key\n", FILE_APPEND); - } - } + public function delete(string $key) + { + $this->engine->delete($key); + if ((DEBUG_CACHE === true) || (is_null(DEBUG_CACHE) && @$_GET['DEBUG_CACHE'])) { + file_put_contents("data/cache.log", "Cache delete: $key\n", FILE_APPEND); + } + } - public function get_hits(): int {return $this->hits;} - public function get_misses(): int {return $this->misses;} + public function get_hits(): int + { + return $this->hits; + } + public function get_misses(): int + { + return $this->misses; + } } - diff --git a/core/captcha.php b/core/captcha.php index 99f5e77d..291192f4 100644 --- a/core/captcha.php +++ b/core/captcha.php @@ -3,53 +3,56 @@ * CAPTCHA abstraction * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -function captcha_get_html(): string { - global $config, $user; +function captcha_get_html(): string +{ + global $config, $user; - if(DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) return ""; + if (DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) { + return ""; + } - $captcha = ""; - if($user->is_anonymous() && $config->get_bool("comment_captcha")) { - $r_publickey = $config->get_string("api_recaptcha_pubkey"); - if(!empty($r_publickey)) { - $captcha = " + $captcha = ""; + if ($user->is_anonymous() && $config->get_bool("comment_captcha")) { + $r_publickey = $config->get_string("api_recaptcha_pubkey"); + if (!empty($r_publickey)) { + $captcha = " "; - } else { - session_start(); - $captcha = Securimage::getCaptchaHtml(['securimage_path' => './vendor/dapphp/securimage/']); - } - } - return $captcha; + } else { + session_start(); + $captcha = Securimage::getCaptchaHtml(['securimage_path' => './vendor/dapphp/securimage/']); + } + } + return $captcha; } -function captcha_check(): bool { - global $config, $user; +function captcha_check(): bool +{ + global $config, $user; - if(DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) return true; + if (DEBUG && ip_in_range($_SERVER['REMOTE_ADDR'], "127.0.0.0/8")) { + return true; + } - if($user->is_anonymous() && $config->get_bool("comment_captcha")) { - $r_privatekey = $config->get_string('api_recaptcha_privkey'); - if(!empty($r_privatekey)) { - $recaptcha = new \ReCaptcha\ReCaptcha($r_privatekey); - $resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); + if ($user->is_anonymous() && $config->get_bool("comment_captcha")) { + $r_privatekey = $config->get_string('api_recaptcha_privkey'); + if (!empty($r_privatekey)) { + $recaptcha = new \ReCaptcha\ReCaptcha($r_privatekey); + $resp = $recaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); - if(!$resp->isSuccess()) { - log_info("core", "Captcha failed (ReCaptcha): " . implode("", $resp->getErrorCodes())); - return false; - } - } - else { - session_start(); - $securimg = new Securimage(); - if($securimg->check($_POST['captcha_code']) === false) { - log_info("core", "Captcha failed (Securimage)"); - return false; - } - } - } + if (!$resp->isSuccess()) { + log_info("core", "Captcha failed (ReCaptcha): " . implode("", $resp->getErrorCodes())); + return false; + } + } else { + session_start(); + $securimg = new Securimage(); + if ($securimg->check($_POST['captcha_code']) === false) { + log_info("core", "Captcha failed (Securimage)"); + return false; + } + } + } - return true; + return true; } - - diff --git a/core/config.php b/core/config.php index 7fee9760..889265c4 100644 --- a/core/config.php +++ b/core/config.php @@ -5,100 +5,101 @@ * * An abstract interface for altering a name:value pair list. */ -interface Config { - /** - * Save the list of name:value pairs to wherever they came from, - * so that the next time a page is loaded it will use the new - * configuration. - */ - public function save(string $name=null): void; +interface Config +{ + /** + * Save the list of name:value pairs to wherever they came from, + * so that the next time a page is loaded it will use the new + * configuration. + */ + public function save(string $name=null): void; - //@{ /*--------------------------------- SET ------------------------------------------------------*/ - /** - * Set a configuration option to a new value, regardless of what the value is at the moment. - */ - public function set_int(string $name, ?int $value): void; + //@{ /*--------------------------------- SET ------------------------------------------------------*/ + /** + * Set a configuration option to a new value, regardless of what the value is at the moment. + */ + public function set_int(string $name, ?int $value): void; - /** - * Set a configuration option to a new value, regardless of what the value is at the moment. - */ - public function set_string(string $name, ?string $value): void; + /** + * Set a configuration option to a new value, regardless of what the value is at the moment. + */ + public function set_string(string $name, ?string $value): void; - /** - * Set a configuration option to a new value, regardless of what the value is at the moment. - * @param null|bool|string $value - */ - public function set_bool(string $name, $value): void; + /** + * Set a configuration option to a new value, regardless of what the value is at the moment. + * @param null|bool|string $value + */ + public function set_bool(string $name, $value): void; - /** - * Set a configuration option to a new value, regardless of what the value is at the moment. - */ - public function set_array(string $name, array $value): void; - //@} /*--------------------------------------------------------------------------------------------*/ + /** + * Set a configuration option to a new value, regardless of what the value is at the moment. + */ + public function set_array(string $name, array $value): void; + //@} /*--------------------------------------------------------------------------------------------*/ - //@{ /*-------------------------------- SET DEFAULT -----------------------------------------------*/ - /** - * Set a configuration option to a new value, if there is no value currently. - * - * Extensions should generally call these from their InitExtEvent handlers. - * This has the advantage that the values will show up in the "advanced" setup - * page where they can be modified, while calling get_* with a "default" - * parameter won't show up. - */ - public function set_default_int(string $name, int $value): void; + //@{ /*-------------------------------- SET DEFAULT -----------------------------------------------*/ + /** + * Set a configuration option to a new value, if there is no value currently. + * + * Extensions should generally call these from their InitExtEvent handlers. + * This has the advantage that the values will show up in the "advanced" setup + * page where they can be modified, while calling get_* with a "default" + * parameter won't show up. + */ + public function set_default_int(string $name, int $value): void; - /** - * Set a configuration option to a new value, if there is no value currently. - * - * Extensions should generally call these from their InitExtEvent handlers. - * This has the advantage that the values will show up in the "advanced" setup - * page where they can be modified, while calling get_* with a "default" - * parameter won't show up. - */ - public function set_default_string(string $name, string $value): void; + /** + * Set a configuration option to a new value, if there is no value currently. + * + * Extensions should generally call these from their InitExtEvent handlers. + * This has the advantage that the values will show up in the "advanced" setup + * page where they can be modified, while calling get_* with a "default" + * parameter won't show up. + */ + public function set_default_string(string $name, string $value): void; - /** - * Set a configuration option to a new value, if there is no value currently. - * - * Extensions should generally call these from their InitExtEvent handlers. - * This has the advantage that the values will show up in the "advanced" setup - * page where they can be modified, while calling get_* with a "default" - * parameter won't show up. - */ - public function set_default_bool(string $name, bool $value): void; + /** + * Set a configuration option to a new value, if there is no value currently. + * + * Extensions should generally call these from their InitExtEvent handlers. + * This has the advantage that the values will show up in the "advanced" setup + * page where they can be modified, while calling get_* with a "default" + * parameter won't show up. + */ + public function set_default_bool(string $name, bool $value): void; - /** - * Set a configuration option to a new value, if there is no value currently. - * - * Extensions should generally call these from their InitExtEvent handlers. - * This has the advantage that the values will show up in the "advanced" setup - * page where they can be modified, while calling get_* with a "default" - * parameter won't show up. - */ - public function set_default_array(string $name, array $value): void; - //@} /*--------------------------------------------------------------------------------------------*/ + /** + * Set a configuration option to a new value, if there is no value currently. + * + * Extensions should generally call these from their InitExtEvent handlers. + * This has the advantage that the values will show up in the "advanced" setup + * page where they can be modified, while calling get_* with a "default" + * parameter won't show up. + */ + public function set_default_array(string $name, array $value): void; + //@} /*--------------------------------------------------------------------------------------------*/ - //@{ /*--------------------------------- GET ------------------------------------------------------*/ - /** - * Pick a value out of the table by name, cast to the appropriate data type. - */ - public function get_int(string $name, ?int $default=null): ?int; + //@{ /*--------------------------------- GET ------------------------------------------------------*/ + /** + * Pick a value out of the table by name, cast to the appropriate data type. + */ + public function get_int(string $name, ?int $default=null): ?int; - /** - * Pick a value out of the table by name, cast to the appropriate data type. - */ - public function get_string(string $name, ?string $default=null): ?string; + /** + * Pick a value out of the table by name, cast to the appropriate data type. + */ + public function get_string(string $name, ?string $default=null): ?string; - /** - * Pick a value out of the table by name, cast to the appropriate data type. - */ - public function get_bool(string $name, ?bool $default=null): ?bool; + /** + * Pick a value out of the table by name, cast to the appropriate data type. + */ + public function get_bool(string $name, ?bool $default=null): ?bool; - /** - * Pick a value out of the table by name, cast to the appropriate data type. - */ - public function get_array(string $name, ?array $default=array()): ?array; - //@} /*--------------------------------------------------------------------------------------------*/ + /** + * Pick a value out of the table by name, cast to the appropriate data type. + */ + public function get_array(string $name, ?array $default=[]): ?array; + //@} /*--------------------------------------------------------------------------------------------*/ } @@ -108,77 +109,90 @@ interface Config { * Common methods for manipulating the list, loading and saving is * left to the concrete implementation */ -abstract class BaseConfig implements Config { - public $values = array(); +abstract class BaseConfig implements Config +{ + public $values = []; - public function set_int(string $name, $value) { - $this->values[$name] = parse_shorthand_int($value); - $this->save($name); - } + public function set_int(string $name, $value) + { + $this->values[$name] = parse_shorthand_int($value); + $this->save($name); + } - public function set_string(string $name, $value) { - $this->values[$name] = $value; - $this->save($name); - } + public function set_string(string $name, $value) + { + $this->values[$name] = $value; + $this->save($name); + } - public function set_bool(string $name, $value) { - $this->values[$name] = bool_escape($value) ? 'Y' : 'N'; - $this->save($name); - } + public function set_bool(string $name, $value) + { + $this->values[$name] = bool_escape($value) ? 'Y' : 'N'; + $this->save($name); + } - public function set_array(string $name, array $value) { - $this->values[$name] = implode(",", $value); - $this->save($name); - } + public function set_array(string $name, array $value) + { + $this->values[$name] = implode(",", $value); + $this->save($name); + } - public function set_default_int(string $name, int $value) { - if(is_null($this->get($name))) { - $this->values[$name] = $value; - } - } + public function set_default_int(string $name, int $value) + { + if (is_null($this->get($name))) { + $this->values[$name] = $value; + } + } - public function set_default_string(string $name, string $value) { - if(is_null($this->get($name))) { - $this->values[$name] = $value; - } - } + public function set_default_string(string $name, string $value) + { + if (is_null($this->get($name))) { + $this->values[$name] = $value; + } + } - public function set_default_bool(string $name, bool $value) { - if(is_null($this->get($name))) { - $this->values[$name] = $value ? 'Y' : 'N'; - } - } + public function set_default_bool(string $name, bool $value) + { + if (is_null($this->get($name))) { + $this->values[$name] = $value ? 'Y' : 'N'; + } + } - public function set_default_array(string $name, array $value) { - if(is_null($this->get($name))) { - $this->values[$name] = implode(",", $value); - } - } + public function set_default_array(string $name, array $value) + { + if (is_null($this->get($name))) { + $this->values[$name] = implode(",", $value); + } + } - public function get_int(string $name, $default=null) { - return (int)($this->get($name, $default)); - } + public function get_int(string $name, $default=null) + { + return (int)($this->get($name, $default)); + } - public function get_string(string $name, $default=null) { - return $this->get($name, $default); - } + public function get_string(string $name, $default=null) + { + return $this->get($name, $default); + } - public function get_bool(string $name, $default=null) { - return bool_escape($this->get($name, $default)); - } + public function get_bool(string $name, $default=null) + { + return bool_escape($this->get($name, $default)); + } - public function get_array(string $name, array $default=array()): array { - return explode(",", $this->get($name, "")); - } + public function get_array(string $name, array $default=[]): array + { + return explode(",", $this->get($name, "")); + } - private function get(string $name, $default=null) { - if(isset($this->values[$name])) { - return $this->values[$name]; - } - else { - return $default; - } - } + private function get(string $name, $default=null) + { + if (isset($this->values[$name])) { + return $this->values[$name]; + } else { + return $default; + } + } } @@ -187,14 +201,17 @@ abstract class BaseConfig implements Config { * * For testing, mostly. */ -class HardcodeConfig extends BaseConfig { - public function __construct(array $dict) { - $this->values = $dict; - } +class HardcodeConfig extends BaseConfig +{ + public function __construct(array $dict) + { + $this->values = $dict; + } - public function save(string $name=null) { - // static config is static - } + public function save(string $name=null) + { + // static config is static + } } @@ -208,26 +225,27 @@ class HardcodeConfig extends BaseConfig { * $config['baz'] = "qux"; * ?> */ -class StaticConfig extends BaseConfig { - public function __construct(string $filename) { - if(file_exists($filename)) { - $config = array(); - require_once $filename; - if(!empty($config)) { - $this->values = $config; - } - else { - throw new Exception("Config file '$filename' doesn't contain any config"); - } - } - else { - throw new Exception("Config file '$filename' missing"); - } - } +class StaticConfig extends BaseConfig +{ + public function __construct(string $filename) + { + if (file_exists($filename)) { + $config = []; + require_once $filename; + if (!empty($config)) { + $this->values = $config; + } else { + throw new Exception("Config file '$filename' doesn't contain any config"); + } + } else { + throw new Exception("Config file '$filename' missing"); + } + } - public function save(string $name=null) { - // static config is static - } + public function save(string $name=null) + { + // static config is static + } } @@ -244,51 +262,53 @@ class StaticConfig extends BaseConfig { * ); * \endcode */ -class DatabaseConfig extends BaseConfig { - /** @var Database */ - private $database = null; +class DatabaseConfig extends BaseConfig +{ + /** @var Database */ + private $database = null; - public function __construct(Database $database) { - $this->database = $database; + public function __construct(Database $database) + { + $this->database = $database; - $cached = $this->database->cache->get("config"); - if($cached) { - $this->values = $cached; - } - else { - $this->values = array(); - foreach($this->database->get_all("SELECT name, value FROM config") as $row) { - $this->values[$row["name"]] = $row["value"]; - } - $this->database->cache->set("config", $this->values); - } - } + $cached = $this->database->cache->get("config"); + if ($cached) { + $this->values = $cached; + } else { + $this->values = []; + foreach ($this->database->get_all("SELECT name, value FROM config") as $row) { + $this->values[$row["name"]] = $row["value"]; + } + $this->database->cache->set("config", $this->values); + } + } - public function save(string $name=null) { - if(is_null($name)) { - reset($this->values); // rewind the array to the first element - foreach($this->values as $name => $value) { - $this->save($name); - } - } - else { - $this->database->Execute("DELETE FROM config WHERE name = :name", array("name"=>$name)); - $this->database->Execute("INSERT INTO config VALUES (:name, :value)", array("name"=>$name, "value"=>$this->values[$name])); - } - // rather than deleting and having some other request(s) do a thundering - // herd of race-conditioned updates, just save the updated version once here - $this->database->cache->set("config", $this->values); - } + public function save(string $name=null) + { + if (is_null($name)) { + reset($this->values); // rewind the array to the first element + foreach ($this->values as $name => $value) { + $this->save($name); + } + } else { + $this->database->Execute("DELETE FROM config WHERE name = :name", ["name"=>$name]); + $this->database->Execute("INSERT INTO config VALUES (:name, :value)", ["name"=>$name, "value"=>$this->values[$name]]); + } + // rather than deleting and having some other request(s) do a thundering + // herd of race-conditioned updates, just save the updated version once here + $this->database->cache->set("config", $this->values); + } } /** * Class MockConfig */ -class MockConfig extends HardcodeConfig { - public function __construct(array $config=array()) { - $config["db_version"] = "999"; - $config["anon_id"] = "0"; - parent::__construct($config); - } +class MockConfig extends HardcodeConfig +{ + public function __construct(array $config=[]) + { + $config["db_version"] = "999"; + $config["anon_id"] = "0"; + parent::__construct($config); + } } - diff --git a/core/database.php b/core/database.php index 57720293..9dd63b9e 100644 --- a/core/database.php +++ b/core/database.php @@ -2,353 +2,418 @@ /** * A class for controlled database access */ -class Database { - /** - * The PDO database connection object, for anyone who wants direct access. - * @var null|PDO - */ - private $db = null; - - /** - * @var float - */ - public $dbtime = 0.0; +class Database +{ + /** + * The PDO database connection object, for anyone who wants direct access. + * @var null|PDO + */ + private $db = null; + + /** + * @var float + */ + public $dbtime = 0.0; - /** - * Meta info about the database engine. - * @var DBEngine|null - */ - private $engine = null; + /** + * Meta info about the database engine. + * @var DBEngine|null + */ + private $engine = null; - /** - * The currently active cache engine. - * @var Cache|null - */ - public $cache = null; + /** + * The currently active cache engine. + * @var Cache|null + */ + public $cache = null; - /** - * A boolean flag to track if we already have an active transaction. - * (ie: True if beginTransaction() already called) - * - * @var bool - */ - public $transaction = false; + /** + * A boolean flag to track if we already have an active transaction. + * (ie: True if beginTransaction() already called) + * + * @var bool + */ + public $transaction = false; - /** - * How many queries this DB object has run - */ - public $query_count = 0; + /** + * How many queries this DB object has run + */ + public $query_count = 0; - /** - * For now, only connect to the cache, as we will pretty much certainly - * need it. There are some pages where all the data is in cache, so the - * DB connection is on-demand. - */ - public function __construct() { - $this->cache = new Cache(CACHE_DSN); - } + /** + * For now, only connect to the cache, as we will pretty much certainly + * need it. There are some pages where all the data is in cache, so the + * DB connection is on-demand. + */ + public function __construct() + { + $this->cache = new Cache(CACHE_DSN); + } - private function connect_db() { - # FIXME: detect ADODB URI, automatically translate PDO DSN + private function connect_db() + { + # FIXME: detect ADODB URI, automatically translate PDO DSN - /* - * Why does the abstraction layer act differently depending on the - * back-end? Because PHP is deliberately retarded. - * - * http://stackoverflow.com/questions/237367 - */ - $matches = array(); $db_user=null; $db_pass=null; - if(preg_match("/user=([^;]*)/", DATABASE_DSN, $matches)) $db_user=$matches[1]; - if(preg_match("/password=([^;]*)/", DATABASE_DSN, $matches)) $db_pass=$matches[1]; + /* + * Why does the abstraction layer act differently depending on the + * back-end? Because PHP is deliberately retarded. + * + * http://stackoverflow.com/questions/237367 + */ + $matches = []; + $db_user=null; + $db_pass=null; + if (preg_match("/user=([^;]*)/", DATABASE_DSN, $matches)) { + $db_user=$matches[1]; + } + if (preg_match("/password=([^;]*)/", DATABASE_DSN, $matches)) { + $db_pass=$matches[1]; + } - // https://bugs.php.net/bug.php?id=70221 - $ka = DATABASE_KA; - if(version_compare(PHP_VERSION, "6.9.9") == 1 && $this->get_driver_name() == "sqlite") { - $ka = false; - } + // https://bugs.php.net/bug.php?id=70221 + $ka = DATABASE_KA; + if (version_compare(PHP_VERSION, "6.9.9") == 1 && $this->get_driver_name() == "sqlite") { + $ka = false; + } - $db_params = array( - PDO::ATTR_PERSISTENT => $ka, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION - ); - $this->db = new PDO(DATABASE_DSN, $db_user, $db_pass, $db_params); + $db_params = [ + PDO::ATTR_PERSISTENT => $ka, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION + ]; + $this->db = new PDO(DATABASE_DSN, $db_user, $db_pass, $db_params); - $this->connect_engine(); - $this->engine->init($this->db); + $this->connect_engine(); + $this->engine->init($this->db); - $this->beginTransaction(); - } + $this->beginTransaction(); + } - private function connect_engine() { - if(preg_match("/^([^:]*)/", DATABASE_DSN, $matches)) $db_proto=$matches[1]; - else throw new SCoreException("Can't figure out database engine"); + private function connect_engine() + { + if (preg_match("/^([^:]*)/", DATABASE_DSN, $matches)) { + $db_proto=$matches[1]; + } else { + throw new SCoreException("Can't figure out database engine"); + } - if($db_proto === "mysql") { - $this->engine = new MySQL(); - } - else if($db_proto === "pgsql") { - $this->engine = new PostgreSQL(); - } - else if($db_proto === "sqlite") { - $this->engine = new SQLite(); - } - else { - die('Unknown PDO driver: '.$db_proto); - } - } + if ($db_proto === "mysql") { + $this->engine = new MySQL(); + } elseif ($db_proto === "pgsql") { + $this->engine = new PostgreSQL(); + } elseif ($db_proto === "sqlite") { + $this->engine = new SQLite(); + } else { + die('Unknown PDO driver: '.$db_proto); + } + } - public function beginTransaction() { - if ($this->transaction === false) { - $this->db->beginTransaction(); - $this->transaction = true; - } - } + public function beginTransaction() + { + if ($this->transaction === false) { + $this->db->beginTransaction(); + $this->transaction = true; + } + } - public function commit(): bool { - if(!is_null($this->db)) { - if ($this->transaction === true) { - $this->transaction = false; - return $this->db->commit(); - } - else { - throw new SCoreException("$h
"; + } + if (!empty($b)) { + $html .= "$b"; + } + $html .= "Database Transaction Error: Unable to call commit() as there is no transaction currently open."); - } - } - else { - throw new SCoreException("
Database Transaction Error: Unable to call commit() as there is no connection currently open."); - } - } + public function commit(): bool + { + if (!is_null($this->db)) { + if ($this->transaction === true) { + $this->transaction = false; + return $this->db->commit(); + } else { + throw new SCoreException("
Database Transaction Error: Unable to call commit() as there is no transaction currently open."); + } + } else { + throw new SCoreException("
Database Transaction Error: Unable to call commit() as there is no connection currently open."); + } + } - public function rollback(): bool { - if(!is_null($this->db)) { - if ($this->transaction === true) { - $this->transaction = false; - return $this->db->rollback(); - } - else { - throw new SCoreException("
Database Transaction Error: Unable to call rollback() as there is no transaction currently open."); - } - } - else { - throw new SCoreException("
Database Transaction Error: Unable to call rollback() as there is no connection currently open."); - } - } + public function rollback(): bool + { + if (!is_null($this->db)) { + if ($this->transaction === true) { + $this->transaction = false; + return $this->db->rollback(); + } else { + throw new SCoreException("
Database Transaction Error: Unable to call rollback() as there is no transaction currently open."); + } + } else { + throw new SCoreException("
Database Transaction Error: Unable to call rollback() as there is no connection currently open."); + } + } - public function escape(string $input): string { - if(is_null($this->db)) $this->connect_db(); - return $this->db->Quote($input); - } + public function escape(string $input): string + { + if (is_null($this->db)) { + $this->connect_db(); + } + return $this->db->Quote($input); + } - public function scoreql_to_sql(string $input): string { - if(is_null($this->engine)) $this->connect_engine(); - return $this->engine->scoreql_to_sql($input); - } + public function scoreql_to_sql(string $input): string + { + if (is_null($this->engine)) { + $this->connect_engine(); + } + return $this->engine->scoreql_to_sql($input); + } - public function get_driver_name(): string { - if(is_null($this->engine)) $this->connect_engine(); - return $this->engine->name; - } + public function get_driver_name(): string + { + if (is_null($this->engine)) { + $this->connect_engine(); + } + return $this->engine->name; + } - private function count_execs(string $sql, array $inputarray) { - if((DEBUG_SQL === true) || (is_null(DEBUG_SQL) && @$_GET['DEBUG_SQL'])) { - $sql = trim(preg_replace('/\s+/msi', ' ', $sql)); - if(isset($inputarray) && is_array($inputarray) && !empty($inputarray)) { - $text = $sql." -- ".join(", ", $inputarray)."\n"; - } - else { - $text = $sql."\n"; - } - file_put_contents("data/sql.log", $text, FILE_APPEND); - } - if(!is_array($inputarray)) $this->query_count++; - # handle 2-dimensional input arrays - else if(is_array(reset($inputarray))) $this->query_count += sizeof($inputarray); - else $this->query_count++; - } + private function count_execs(string $sql, array $inputarray) + { + if ((DEBUG_SQL === true) || (is_null(DEBUG_SQL) && @$_GET['DEBUG_SQL'])) { + $sql = trim(preg_replace('/\s+/msi', ' ', $sql)); + if (isset($inputarray) && is_array($inputarray) && !empty($inputarray)) { + $text = $sql." -- ".join(", ", $inputarray)."\n"; + } else { + $text = $sql."\n"; + } + file_put_contents("data/sql.log", $text, FILE_APPEND); + } + if (!is_array($inputarray)) { + $this->query_count++; + } + # handle 2-dimensional input arrays + elseif (is_array(reset($inputarray))) { + $this->query_count += sizeof($inputarray); + } else { + $this->query_count++; + } + } - private function count_time(string $method, float $start) { - if((DEBUG_SQL === true) || (is_null(DEBUG_SQL) && @$_GET['DEBUG_SQL'])) { - $text = $method.":".(microtime(true) - $start)."\n"; - file_put_contents("data/sql.log", $text, FILE_APPEND); - } - $this->dbtime += microtime(true) - $start; - } + private function count_time(string $method, float $start) + { + if ((DEBUG_SQL === true) || (is_null(DEBUG_SQL) && @$_GET['DEBUG_SQL'])) { + $text = $method.":".(microtime(true) - $start)."\n"; + file_put_contents("data/sql.log", $text, FILE_APPEND); + } + $this->dbtime += microtime(true) - $start; + } - public function execute(string $query, array $args=array()): PDOStatement { - try { - if(is_null($this->db)) $this->connect_db(); - $this->count_execs($query, $args); - $stmt = $this->db->prepare( - "-- " . str_replace("%2F", "/", urlencode(@$_GET['q'])). "\n" . - $query - ); - // $stmt = $this->db->prepare($query); - if (!array_key_exists(0, $args)) { - foreach($args as $name=>$value) { - if(is_numeric($value)) { - $stmt->bindValue(':'.$name, $value, PDO::PARAM_INT); - } - else { - $stmt->bindValue(':'.$name, $value, PDO::PARAM_STR); - } - } - $stmt->execute(); - } - else { - $stmt->execute($args); - } - return $stmt; - } - catch(PDOException $pdoe) { - throw new SCoreException($pdoe->getMessage()."
Query: ".$query); - } - } + public function execute(string $query, array $args=[]): PDOStatement + { + try { + if (is_null($this->db)) { + $this->connect_db(); + } + $this->count_execs($query, $args); + $stmt = $this->db->prepare( + "-- " . str_replace("%2F", "/", urlencode(@$_GET['q'])). "\n" . + $query + ); + // $stmt = $this->db->prepare($query); + if (!array_key_exists(0, $args)) { + foreach ($args as $name=>$value) { + if (is_numeric($value)) { + $stmt->bindValue(':'.$name, $value, PDO::PARAM_INT); + } else { + $stmt->bindValue(':'.$name, $value, PDO::PARAM_STR); + } + } + $stmt->execute(); + } else { + $stmt->execute($args); + } + return $stmt; + } catch (PDOException $pdoe) { + throw new SCoreException($pdoe->getMessage()."
Query: ".$query); + } + } - /** - * Execute an SQL query and return a 2D array. - */ - public function get_all(string $query, array $args=array()): array { - $_start = microtime(true); - $data = $this->execute($query, $args)->fetchAll(); - $this->count_time("get_all", $_start); - return $data; - } + /** + * Execute an SQL query and return a 2D array. + */ + public function get_all(string $query, array $args=[]): array + { + $_start = microtime(true); + $data = $this->execute($query, $args)->fetchAll(); + $this->count_time("get_all", $_start); + return $data; + } - /** - * Execute an SQL query and return a single row. - */ - public function get_row(string $query, array $args=array()) { - $_start = microtime(true); - $row = $this->execute($query, $args)->fetch(); - $this->count_time("get_row", $_start); - return $row ? $row : null; - } + /** + * Execute an SQL query and return a single row. + */ + public function get_row(string $query, array $args=[]) + { + $_start = microtime(true); + $row = $this->execute($query, $args)->fetch(); + $this->count_time("get_row", $_start); + return $row ? $row : null; + } - /** - * Execute an SQL query and return the first column of each row. - */ - public function get_col(string $query, array $args=array()): array { - $_start = microtime(true); - $stmt = $this->execute($query, $args); - $res = array(); - foreach($stmt as $row) { - $res[] = $row[0]; - } - $this->count_time("get_col", $_start); - return $res; - } + /** + * Execute an SQL query and return the first column of each row. + */ + public function get_col(string $query, array $args=[]): array + { + $_start = microtime(true); + $stmt = $this->execute($query, $args); + $res = []; + foreach ($stmt as $row) { + $res[] = $row[0]; + } + $this->count_time("get_col", $_start); + return $res; + } - /** - * Execute an SQL query and return the the first row => the second row. - */ - public function get_pairs(string $query, array $args=array()): array { - $_start = microtime(true); - $stmt = $this->execute($query, $args); - $res = array(); - foreach($stmt as $row) { - $res[$row[0]] = $row[1]; - } - $this->count_time("get_pairs", $_start); - return $res; - } + /** + * Execute an SQL query and return the the first row => the second row. + */ + public function get_pairs(string $query, array $args=[]): array + { + $_start = microtime(true); + $stmt = $this->execute($query, $args); + $res = []; + foreach ($stmt as $row) { + $res[$row[0]] = $row[1]; + } + $this->count_time("get_pairs", $_start); + return $res; + } - /** - * Execute an SQL query and return a single value. - */ - public function get_one(string $query, array $args=array()) { - $_start = microtime(true); - $row = $this->execute($query, $args)->fetch(); - $this->count_time("get_one", $_start); - return $row[0]; - } + /** + * Execute an SQL query and return a single value. + */ + public function get_one(string $query, array $args=[]) + { + $_start = microtime(true); + $row = $this->execute($query, $args)->fetch(); + $this->count_time("get_one", $_start); + return $row[0]; + } - /** - * Get the ID of the last inserted row. - */ - public function get_last_insert_id(string $seq): int { - if($this->engine->name == "pgsql") { - return $this->db->lastInsertId($seq); - } - else { - return $this->db->lastInsertId(); - } - } + /** + * Get the ID of the last inserted row. + */ + public function get_last_insert_id(string $seq): int + { + if ($this->engine->name == "pgsql") { + return $this->db->lastInsertId($seq); + } else { + return $this->db->lastInsertId(); + } + } - /** - * Create a table from pseudo-SQL. - */ - public function create_table(string $name, string $data): void { - if(is_null($this->engine)) { $this->connect_engine(); } - $data = trim($data, ", \t\n\r\0\x0B"); // mysql doesn't like trailing commas - $this->execute($this->engine->create_table_sql($name, $data)); - } + /** + * Create a table from pseudo-SQL. + */ + public function create_table(string $name, string $data): void + { + if (is_null($this->engine)) { + $this->connect_engine(); + } + $data = trim($data, ", \t\n\r\0\x0B"); // mysql doesn't like trailing commas + $this->execute($this->engine->create_table_sql($name, $data)); + } - /** - * Returns the number of tables present in the current database. - * - * @throws SCoreException - */ - public function count_tables(): int { - if(is_null($this->db) || is_null($this->engine)) $this->connect_db(); + /** + * Returns the number of tables present in the current database. + * + * @throws SCoreException + */ + public function count_tables(): int + { + if (is_null($this->db) || is_null($this->engine)) { + $this->connect_db(); + } - if($this->engine->name === "mysql") { - return count( - $this->get_all("SHOW TABLES") - ); - } else if ($this->engine->name === "pgsql") { - return count( - $this->get_all("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'") - ); - } else if ($this->engine->name === "sqlite") { - return count( - $this->get_all("SELECT name FROM sqlite_master WHERE type = 'table'") - ); - } else { - throw new SCoreException("Can't count tables for database type {$this->engine->name}"); - } - } + if ($this->engine->name === "mysql") { + return count( + $this->get_all("SHOW TABLES") + ); + } elseif ($this->engine->name === "pgsql") { + return count( + $this->get_all("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'") + ); + } elseif ($this->engine->name === "sqlite") { + return count( + $this->get_all("SELECT name FROM sqlite_master WHERE type = 'table'") + ); + } else { + throw new SCoreException("Can't count tables for database type {$this->engine->name}"); + } + } } -class MockDatabase extends Database { - /** @var int */ - private $query_id = 0; - /** @var array */ - private $responses = array(); - /** @var \NoCache|null */ - public $cache = null; +class MockDatabase extends Database +{ + /** @var int */ + private $query_id = 0; + /** @var array */ + private $responses = []; + /** @var \NoCache|null */ + public $cache = null; - public function __construct(array $responses = array()) { - $this->cache = new NoCache(); - $this->responses = $responses; - } + public function __construct(array $responses = []) + { + $this->cache = new NoCache(); + $this->responses = $responses; + } - public function execute(string $query, array $params=array()): PDOStatement { - log_debug("mock-database", - "QUERY: " . $query . - "\nARGS: " . var_export($params, true) . - "\nRETURN: " . var_export($this->responses[$this->query_id], true) - ); - return $this->responses[$this->query_id++]; - } - public function _execute(string $query, array $params=array()) { - log_debug("mock-database", - "QUERY: " . $query . - "\nARGS: " . var_export($params, true) . - "\nRETURN: " . var_export($this->responses[$this->query_id], true) - ); - return $this->responses[$this->query_id++]; - } + public function execute(string $query, array $params=[]): PDOStatement + { + log_debug( + "mock-database", + "QUERY: " . $query . + "\nARGS: " . var_export($params, true) . + "\nRETURN: " . var_export($this->responses[$this->query_id], true) + ); + return $this->responses[$this->query_id++]; + } + public function _execute(string $query, array $params=[]) + { + log_debug( + "mock-database", + "QUERY: " . $query . + "\nARGS: " . var_export($params, true) . + "\nRETURN: " . var_export($this->responses[$this->query_id], true) + ); + return $this->responses[$this->query_id++]; + } - public function get_all(string $query, array $args=array()): array {return $this->_execute($query, $args);} - public function get_row(string $query, array $args=array()) {return $this->_execute($query, $args);} - public function get_col(string $query, array $args=array()): array {return $this->_execute($query, $args);} - public function get_pairs(string $query, array $args=array()): array {return $this->_execute($query, $args);} - public function get_one(string $query, array $args=array()) {return $this->_execute($query, $args);} + public function get_all(string $query, array $args=[]): array + { + return $this->_execute($query, $args); + } + public function get_row(string $query, array $args=[]) + { + return $this->_execute($query, $args); + } + public function get_col(string $query, array $args=[]): array + { + return $this->_execute($query, $args); + } + public function get_pairs(string $query, array $args=[]): array + { + return $this->_execute($query, $args); + } + public function get_one(string $query, array $args=[]) + { + return $this->_execute($query, $args); + } - public function get_last_insert_id(string $seq): int {return $this->query_id;} + public function get_last_insert_id(string $seq): int + { + return $this->query_id; + } - public function scoreql_to_sql(string $sql): string {return $sql;} - public function create_table(string $name, string $def) {} - public function connect_engine() {} + public function scoreql_to_sql(string $sql): string + { + return $sql; + } + public function create_table(string $name, string $def) + { + } + public function connect_engine() + { + } } - diff --git a/core/dbengine.php b/core/dbengine.php index 18b6f512..bb7c674b 100644 --- a/core/dbengine.php +++ b/core/dbengine.php @@ -1,142 +1,188 @@ exec("SET NAMES utf8;"); - } + public function init(PDO $db) + { + $db->exec("SET NAMES utf8;"); + } - public function scoreql_to_sql(string $data): string { - $data = str_replace("SCORE_AIPK", "INTEGER PRIMARY KEY auto_increment", $data); - $data = str_replace("SCORE_INET", "VARCHAR(45)", $data); - $data = str_replace("SCORE_BOOL_Y", "'Y'", $data); - $data = str_replace("SCORE_BOOL_N", "'N'", $data); - $data = str_replace("SCORE_BOOL", "ENUM('Y', 'N')", $data); - $data = str_replace("SCORE_DATETIME", "DATETIME", $data); - $data = str_replace("SCORE_NOW", "\"1970-01-01\"", $data); - $data = str_replace("SCORE_STRNORM", "", $data); - $data = str_replace("SCORE_ILIKE", "LIKE", $data); - return $data; - } + public function scoreql_to_sql(string $data): string + { + $data = str_replace("SCORE_AIPK", "INTEGER PRIMARY KEY auto_increment", $data); + $data = str_replace("SCORE_INET", "VARCHAR(45)", $data); + $data = str_replace("SCORE_BOOL_Y", "'Y'", $data); + $data = str_replace("SCORE_BOOL_N", "'N'", $data); + $data = str_replace("SCORE_BOOL", "ENUM('Y', 'N')", $data); + $data = str_replace("SCORE_DATETIME", "DATETIME", $data); + $data = str_replace("SCORE_NOW", "\"1970-01-01\"", $data); + $data = str_replace("SCORE_STRNORM", "", $data); + $data = str_replace("SCORE_ILIKE", "LIKE", $data); + return $data; + } - public function create_table_sql(string $name, string $data): string { - $data = $this->scoreql_to_sql($data); - $ctes = "ENGINE=InnoDB DEFAULT CHARSET='utf8'"; - return 'CREATE TABLE '.$name.' ('.$data.') '.$ctes; - } + public function create_table_sql(string $name, string $data): string + { + $data = $this->scoreql_to_sql($data); + $ctes = "ENGINE=InnoDB DEFAULT CHARSET='utf8'"; + return 'CREATE TABLE '.$name.' ('.$data.') '.$ctes; + } } -class PostgreSQL extends DBEngine { - /** @var string */ - public $name = "pgsql"; +class PostgreSQL extends DBEngine +{ + /** @var string */ + public $name = "pgsql"; - public function init(PDO $db) { - if(array_key_exists('REMOTE_ADDR', $_SERVER)) { - $db->exec("SET application_name TO 'shimmie [{$_SERVER['REMOTE_ADDR']}]';"); - } - else { - $db->exec("SET application_name TO 'shimmie [local]';"); - } - $db->exec("SET statement_timeout TO 10000;"); - } + public function init(PDO $db) + { + if (array_key_exists('REMOTE_ADDR', $_SERVER)) { + $db->exec("SET application_name TO 'shimmie [{$_SERVER['REMOTE_ADDR']}]';"); + } else { + $db->exec("SET application_name TO 'shimmie [local]';"); + } + $db->exec("SET statement_timeout TO 10000;"); + } - public function scoreql_to_sql(string $data): string { - $data = str_replace("SCORE_AIPK", "SERIAL PRIMARY KEY", $data); - $data = str_replace("SCORE_INET", "INET", $data); - $data = str_replace("SCORE_BOOL_Y", "'t'", $data); - $data = str_replace("SCORE_BOOL_N", "'f'", $data); - $data = str_replace("SCORE_BOOL", "BOOL", $data); - $data = str_replace("SCORE_DATETIME", "TIMESTAMP", $data); - $data = str_replace("SCORE_NOW", "current_timestamp", $data); - $data = str_replace("SCORE_STRNORM", "lower", $data); - $data = str_replace("SCORE_ILIKE", "ILIKE", $data); - return $data; - } + public function scoreql_to_sql(string $data): string + { + $data = str_replace("SCORE_AIPK", "SERIAL PRIMARY KEY", $data); + $data = str_replace("SCORE_INET", "INET", $data); + $data = str_replace("SCORE_BOOL_Y", "'t'", $data); + $data = str_replace("SCORE_BOOL_N", "'f'", $data); + $data = str_replace("SCORE_BOOL", "BOOL", $data); + $data = str_replace("SCORE_DATETIME", "TIMESTAMP", $data); + $data = str_replace("SCORE_NOW", "current_timestamp", $data); + $data = str_replace("SCORE_STRNORM", "lower", $data); + $data = str_replace("SCORE_ILIKE", "ILIKE", $data); + return $data; + } - public function create_table_sql(string $name, string $data): string { - $data = $this->scoreql_to_sql($data); - return "CREATE TABLE $name ($data)"; - } + public function create_table_sql(string $name, string $data): string + { + $data = $this->scoreql_to_sql($data); + return "CREATE TABLE $name ($data)"; + } } // shimmie functions for export to sqlite -function _unix_timestamp($date) { return strtotime($date); } -function _now() { return date("Y-m-d h:i:s"); } -function _floor($a) { return floor($a); } -function _log($a, $b=null) { - if(is_null($b)) return log($a); - else return log($a, $b); +function _unix_timestamp($date) +{ + return strtotime($date); } -function _isnull($a) { return is_null($a); } -function _md5($a) { return md5($a); } -function _concat($a, $b) { return $a . $b; } -function _lower($a) { return strtolower($a); } -function _rand() { return rand(); } -function _ln($n) { return log($n); } - -class SQLite extends DBEngine { - /** @var string */ - public $name = "sqlite"; - - public function init(PDO $db) { - ini_set('sqlite.assoc_case', 0); - $db->exec("PRAGMA foreign_keys = ON;"); - $db->sqliteCreateFunction('UNIX_TIMESTAMP', '_unix_timestamp', 1); - $db->sqliteCreateFunction('now', '_now', 0); - $db->sqliteCreateFunction('floor', '_floor', 1); - $db->sqliteCreateFunction('log', '_log'); - $db->sqliteCreateFunction('isnull', '_isnull', 1); - $db->sqliteCreateFunction('md5', '_md5', 1); - $db->sqliteCreateFunction('concat', '_concat', 2); - $db->sqliteCreateFunction('lower', '_lower', 1); - $db->sqliteCreateFunction('rand', '_rand', 0); - $db->sqliteCreateFunction('ln', '_ln', 1); - } - - public function scoreql_to_sql(string $data): string { - $data = str_replace("SCORE_AIPK", "INTEGER PRIMARY KEY", $data); - $data = str_replace("SCORE_INET", "VARCHAR(45)", $data); - $data = str_replace("SCORE_BOOL_Y", "'Y'", $data); - $data = str_replace("SCORE_BOOL_N", "'N'", $data); - $data = str_replace("SCORE_BOOL", "CHAR(1)", $data); - $data = str_replace("SCORE_NOW", "\"1970-01-01\"", $data); - $data = str_replace("SCORE_STRNORM", "lower", $data); - $data = str_replace("SCORE_ILIKE", "LIKE", $data); - return $data; - } - - public function create_table_sql(string $name, string $data): string { - $data = $this->scoreql_to_sql($data); - $cols = array(); - $extras = ""; - foreach(explode(",", $data) as $bit) { - $matches = array(); - if(preg_match("/(UNIQUE)? ?INDEX\s*\((.*)\)/", $bit, $matches)) { - $uni = $matches[1]; - $col = $matches[2]; - $extras .= "CREATE $uni INDEX {$name}_{$col} ON {$name}({$col});"; - } - else { - $cols[] = $bit; - } - } - $cols_redone = implode(", ", $cols); - return "CREATE TABLE $name ($cols_redone); $extras"; - } +function _now() +{ + return date("Y-m-d h:i:s"); +} +function _floor($a) +{ + return floor($a); +} +function _log($a, $b=null) +{ + if (is_null($b)) { + return log($a); + } else { + return log($a, $b); + } +} +function _isnull($a) +{ + return is_null($a); +} +function _md5($a) +{ + return md5($a); +} +function _concat($a, $b) +{ + return $a . $b; +} +function _lower($a) +{ + return strtolower($a); +} +function _rand() +{ + return rand(); +} +function _ln($n) +{ + return log($n); +} + +class SQLite extends DBEngine +{ + /** @var string */ + public $name = "sqlite"; + + public function init(PDO $db) + { + ini_set('sqlite.assoc_case', 0); + $db->exec("PRAGMA foreign_keys = ON;"); + $db->sqliteCreateFunction('UNIX_TIMESTAMP', '_unix_timestamp', 1); + $db->sqliteCreateFunction('now', '_now', 0); + $db->sqliteCreateFunction('floor', '_floor', 1); + $db->sqliteCreateFunction('log', '_log'); + $db->sqliteCreateFunction('isnull', '_isnull', 1); + $db->sqliteCreateFunction('md5', '_md5', 1); + $db->sqliteCreateFunction('concat', '_concat', 2); + $db->sqliteCreateFunction('lower', '_lower', 1); + $db->sqliteCreateFunction('rand', '_rand', 0); + $db->sqliteCreateFunction('ln', '_ln', 1); + } + + public function scoreql_to_sql(string $data): string + { + $data = str_replace("SCORE_AIPK", "INTEGER PRIMARY KEY", $data); + $data = str_replace("SCORE_INET", "VARCHAR(45)", $data); + $data = str_replace("SCORE_BOOL_Y", "'Y'", $data); + $data = str_replace("SCORE_BOOL_N", "'N'", $data); + $data = str_replace("SCORE_BOOL", "CHAR(1)", $data); + $data = str_replace("SCORE_NOW", "\"1970-01-01\"", $data); + $data = str_replace("SCORE_STRNORM", "lower", $data); + $data = str_replace("SCORE_ILIKE", "LIKE", $data); + return $data; + } + + public function create_table_sql(string $name, string $data): string + { + $data = $this->scoreql_to_sql($data); + $cols = []; + $extras = ""; + foreach (explode(",", $data) as $bit) { + $matches = []; + if (preg_match("/(UNIQUE)? ?INDEX\s*\((.*)\)/", $bit, $matches)) { + $uni = $matches[1]; + $col = $matches[2]; + $extras .= "CREATE $uni INDEX {$name}_{$col} ON {$name}({$col});"; + } else { + $cols[] = $bit; + } + } + $cols_redone = implode(", ", $cols); + return "CREATE TABLE $name ($cols_redone); $extras"; + } } diff --git a/core/email.php b/core/email.php index eff609f2..c7982212 100644 --- a/core/email.php +++ b/core/email.php @@ -5,64 +5,66 @@ * * A generic email. */ -class Email { - /** @var string */ - public $to; - /** @var string */ - public $subject; - /** @var string */ - public $header; - /** @var null|string */ - public $style; - /** @var null|string */ - public $header_img; - /** @var null|string */ - public $sitename; - /** @var null|string */ - public $sitedomain; - /** @var null|string */ - public $siteemail; - /** @var string */ - public $date; - /** @var string */ - public $body; - /** @var null|string */ - public $footer; +class Email +{ + /** @var string */ + public $to; + /** @var string */ + public $subject; + /** @var string */ + public $header; + /** @var null|string */ + public $style; + /** @var null|string */ + public $header_img; + /** @var null|string */ + public $sitename; + /** @var null|string */ + public $sitedomain; + /** @var null|string */ + public $siteemail; + /** @var string */ + public $date; + /** @var string */ + public $body; + /** @var null|string */ + public $footer; - public function __construct(string $to, string $subject, string $header, string $body) { - global $config; - $this->to = $to; - - $sub_prefix = $config->get_string("mail_sub"); - - if(!isset($sub_prefix)){ - $this->subject = $subject; - } - else{ - $this->subject = $sub_prefix." ".$subject; - } - - $this->style = $config->get_string("mail_style"); - - $this->header = html_escape($header); - $this->header_img = $config->get_string("mail_img"); - $this->sitename = $config->get_string("site_title"); - $this->sitedomain = make_http(make_link("")); - $this->siteemail = $config->get_string("site_email"); - $this->date = date("F j, Y"); - $this->body = $body; - $this->footer = $config->get_string("mail_fot"); - } - - public function send(): bool { - $headers = "From: ".$this->sitename." <".$this->siteemail.">\r\n"; - $headers .= "Reply-To: ".$this->siteemail."\r\n"; - $headers .= "X-Mailer: PHP/" . phpversion(). "\r\n"; - $headers .= "errors-to: ".$this->siteemail."\r\n"; - $headers .= "Date: " . date(DATE_RFC2822); - $headers .= 'MIME-Version: 1.0' . "\r\n"; - $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n"; - $message = ' + public function __construct(string $to, string $subject, string $header, string $body) + { + global $config; + $this->to = $to; + + $sub_prefix = $config->get_string("mail_sub"); + + if (!isset($sub_prefix)) { + $this->subject = $subject; + } else { + $this->subject = $sub_prefix." ".$subject; + } + + $this->style = $config->get_string("mail_style"); + + $this->header = html_escape($header); + $this->header_img = $config->get_string("mail_img"); + $this->sitename = $config->get_string("site_title"); + $this->sitedomain = make_http(make_link("")); + $this->siteemail = $config->get_string("site_email"); + $this->date = date("F j, Y"); + $this->body = $body; + $this->footer = $config->get_string("mail_fot"); + } + + public function send(): bool + { + $headers = "From: ".$this->sitename." <".$this->siteemail.">\r\n"; + $headers .= "Reply-To: ".$this->siteemail."\r\n"; + $headers .= "X-Mailer: PHP/" . phpversion(). "\r\n"; + $headers .= "errors-to: ".$this->siteemail."\r\n"; + $headers .= "Date: " . date(DATE_RFC2822); + $headers .= 'MIME-Version: 1.0' . "\r\n"; + $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n"; + $message = '
@@ -118,15 +120,13 @@ Copyright (C) '.$this->sitename.'
'; - $sent = mail($this->to, $this->subject, $message, $headers); - if($sent){ - log_info("mail", "Sent message '$this->subject' to '$this->to'"); - } - else{ - log_info("mail", "Error sending message '$this->subject' to '$this->to'"); - } - - return $sent; - } + $sent = mail($this->to, $this->subject, $message, $headers); + if ($sent) { + log_info("mail", "Sent message '$this->subject' to '$this->to'"); + } else { + log_info("mail", "Error sending message '$this->subject' to '$this->to'"); + } + + return $sent; + } } - diff --git a/core/event.php b/core/event.php index 3010da6f..292da5bf 100644 --- a/core/event.php +++ b/core/event.php @@ -4,8 +4,11 @@ * * An event is anything that can be passed around via send_event($blah) */ -abstract class Event { - public function __construct() {} +abstract class Event +{ + public function __construct() + { + } } @@ -16,7 +19,9 @@ abstract class Event { * * This event is sent before $user is set to anything */ -class InitExtEvent extends Event {} +class InitExtEvent extends Event +{ +} /** @@ -27,188 +32,197 @@ class InitExtEvent extends Event {} * true and ignores the matched part, such that $event->count_args() = 1 and * $event->get_arg(0) = "42" */ -class PageRequestEvent extends Event { - /** - * @var array - */ - public $args; +class PageRequestEvent extends Event +{ + /** + * @var array + */ + public $args; - /** - * @var int - */ - public $arg_count; + /** + * @var int + */ + public $arg_count; - /** - * @var int - */ - public $part_count; + /** + * @var int + */ + public $part_count; - public function __construct(string $path) { - global $config; + public function __construct(string $path) + { + global $config; - // trim starting slashes - $path = ltrim($path, "/"); + // trim starting slashes + $path = ltrim($path, "/"); - // if path is not specified, use the default front page - if(empty($path)) { /* empty is faster than strlen */ - $path = $config->get_string('front_page'); - } + // if path is not specified, use the default front page + if (empty($path)) { /* empty is faster than strlen */ + $path = $config->get_string('front_page'); + } - // break the path into parts - $args = explode('/', $path); + // break the path into parts + $args = explode('/', $path); - // voodoo so that an arg can contain a slash; is - // this still needed? - if(strpos($path, "^") !== FALSE) { - $unescaped = array(); - foreach($args as $part) { - $unescaped[] = _decaret($part); - } - $args = $unescaped; - } + // voodoo so that an arg can contain a slash; is + // this still needed? + if (strpos($path, "^") !== false) { + $unescaped = []; + foreach ($args as $part) { + $unescaped[] = _decaret($part); + } + $args = $unescaped; + } - $this->args = $args; - $this->arg_count = count($args); - } + $this->args = $args; + $this->arg_count = count($args); + } - /** - * Test if the requested path matches a given pattern. - * - * If it matches, store the remaining path elements in $args - */ - public function page_matches(string $name): bool { - $parts = explode("/", $name); - $this->part_count = count($parts); + /** + * Test if the requested path matches a given pattern. + * + * If it matches, store the remaining path elements in $args + */ + public function page_matches(string $name): bool + { + $parts = explode("/", $name); + $this->part_count = count($parts); - if($this->part_count > $this->arg_count) { - return false; - } + if ($this->part_count > $this->arg_count) { + return false; + } - for($i=0; $i<$this->part_count; $i++) { - if($parts[$i] != $this->args[$i]) { - return false; - } - } + for ($i=0; $i<$this->part_count; $i++) { + if ($parts[$i] != $this->args[$i]) { + return false; + } + } - return true; - } + return true; + } - /** - * Get the n th argument of the page request (if it exists.) - */ - public function get_arg(int $n): ?string { - $offset = $this->part_count + $n; - if($offset >= 0 && $offset < $this->arg_count) { - return $this->args[$offset]; - } - else { - return null; - } - } + /** + * Get the n th argument of the page request (if it exists.) + */ + public function get_arg(int $n): ?string + { + $offset = $this->part_count + $n; + if ($offset >= 0 && $offset < $this->arg_count) { + return $this->args[$offset]; + } else { + return null; + } + } - /** - * Returns the number of arguments the page request has. - */ - public function count_args(): int { - return int_escape($this->arg_count - $this->part_count); - } + /** + * Returns the number of arguments the page request has. + */ + public function count_args(): int + { + return int_escape($this->arg_count - $this->part_count); + } - /* - * Many things use these functions - */ + /* + * Many things use these functions + */ - public function get_search_terms(): array { - $search_terms = array(); - if($this->count_args() === 2) { - $search_terms = Tag::explode($this->get_arg(0)); - } - return $search_terms; - } + public function get_search_terms(): array + { + $search_terms = []; + if ($this->count_args() === 2) { + $search_terms = Tag::explode($this->get_arg(0)); + } + return $search_terms; + } - public function get_page_number(): int { - $page_number = 1; - if($this->count_args() === 1) { - $page_number = int_escape($this->get_arg(0)); - } - else if($this->count_args() === 2) { - $page_number = int_escape($this->get_arg(1)); - } - if($page_number === 0) $page_number = 1; // invalid -> 0 - return $page_number; - } + public function get_page_number(): int + { + $page_number = 1; + if ($this->count_args() === 1) { + $page_number = int_escape($this->get_arg(0)); + } elseif ($this->count_args() === 2) { + $page_number = int_escape($this->get_arg(1)); + } + if ($page_number === 0) { + $page_number = 1; + } // invalid -> 0 + return $page_number; + } - public function get_page_size(): int { - global $config; - return $config->get_int('index_images'); - } + public function get_page_size(): int + { + global $config; + return $config->get_int('index_images'); + } } /** * Sent when index.php is called from the command line */ -class CommandEvent extends Event { - /** - * @var string - */ - public $cmd = "help"; +class CommandEvent extends Event +{ + /** + * @var string + */ + public $cmd = "help"; - /** - * @var array - */ - public $args = array(); + /** + * @var array + */ + public $args = []; - /** - * #param string[] $args - */ - public function __construct(array $args) { - global $user; + /** + * #param string[] $args + */ + public function __construct(array $args) + { + global $user; - $opts = array(); - $log_level = SCORE_LOG_WARNING; + $opts = []; + $log_level = SCORE_LOG_WARNING; $arg_count = count($args); - for($i=1; $i<$arg_count; $i++) { - switch($args[$i]) { - case '-u': - $user = User::by_name($args[++$i]); - if(is_null($user)) { - die("Unknown user"); - } - break; - case '-q': - $log_level += 10; - break; - case '-v': - $log_level -= 10; - break; - default: - $opts[] = $args[$i]; - break; - } - } + for ($i=1; $i<$arg_count; $i++) { + switch ($args[$i]) { + case '-u': + $user = User::by_name($args[++$i]); + if (is_null($user)) { + die("Unknown user"); + } + break; + case '-q': + $log_level += 10; + break; + case '-v': + $log_level -= 10; + break; + default: + $opts[] = $args[$i]; + break; + } + } - define("CLI_LOG_LEVEL", $log_level); + define("CLI_LOG_LEVEL", $log_level); - if(count($opts) > 0) { - $this->cmd = $opts[0]; - $this->args = array_slice($opts, 1); - } - else { - print "\n"; - print "Usage: php {$args[0]} [flags] [command]\n"; - print "\n"; - print "Flags:\n"; - print " -u [username]\n"; - print " Log in as the specified user\n"; - print " -q / -v\n"; - print " Be quieter / more verbose\n"; - print " Scale is debug - info - warning - error - critical\n"; - print " Default is to show warnings and above\n"; - print " \n"; - print "Currently known commands:\n"; - } - } + if (count($opts) > 0) { + $this->cmd = $opts[0]; + $this->args = array_slice($opts, 1); + } else { + print "\n"; + print "Usage: php {$args[0]} [flags] [command]\n"; + print "\n"; + print "Flags:\n"; + print " -u [username]\n"; + print " Log in as the specified user\n"; + print " -q / -v\n"; + print " Be quieter / more verbose\n"; + print " Scale is debug - info - warning - error - critical\n"; + print " Default is to show warnings and above\n"; + print " \n"; + print "Currently known commands:\n"; + } + } } @@ -216,82 +230,85 @@ class CommandEvent extends Event { * A signal that some text needs formatting, the event carries * both the text and the result */ -class TextFormattingEvent extends Event { - /** - * For reference - * - * @var string - */ - public $original; +class TextFormattingEvent extends Event +{ + /** + * For reference + * + * @var string + */ + public $original; - /** - * with formatting applied - * - * @var string - */ - public $formatted; + /** + * with formatting applied + * + * @var string + */ + public $formatted; - /** - * with formatting removed - * - * @var string - */ - public $stripped; + /** + * with formatting removed + * + * @var string + */ + public $stripped; - public function __construct(string $text) { - $h_text = html_escape(trim($text)); - $this->original = $h_text; - $this->formatted = $h_text; - $this->stripped = $h_text; - } + public function __construct(string $text) + { + $h_text = html_escape(trim($text)); + $this->original = $h_text; + $this->formatted = $h_text; + $this->stripped = $h_text; + } } /** * A signal that something needs logging */ -class LogEvent extends Event { - /** - * a category, normally the extension name - * - * @var string - */ - public $section; +class LogEvent extends Event +{ + /** + * a category, normally the extension name + * + * @var string + */ + public $section; - /** - * See python... - * - * @var int - */ - public $priority = 0; + /** + * See python... + * + * @var int + */ + public $priority = 0; - /** - * Free text to be logged - * - * @var string - */ - public $message; + /** + * Free text to be logged + * + * @var string + */ + public $message; - /** - * The time that the event was created - * - * @var int - */ - public $time; + /** + * The time that the event was created + * + * @var int + */ + public $time; - /** - * Extra data to be held separate - * - * @var array - */ - public $args; + /** + * Extra data to be held separate + * + * @var array + */ + public $args; - public function __construct(string $section, int $priority, string $message, array $args) { - $this->section = $section; - $this->priority = $priority; - $this->message = $message; - $this->args = $args; - $this->time = time(); - } + public function __construct(string $section, int $priority, string $message, array $args) + { + $this->section = $section; + $this->priority = $priority; + $this->message = $message; + $this->args = $args; + $this->time = time(); + } } - diff --git a/core/exceptions.php b/core/exceptions.php index d2400893..a201eba4 100644 --- a/core/exceptions.php +++ b/core/exceptions.php @@ -5,14 +5,18 @@ * * A base exception to be caught by the upper levels. */ -class SCoreException extends Exception {} +class SCoreException extends Exception +{ +} /** * Class PermissionDeniedException * * A fairly common, generic exception. */ -class PermissionDeniedException extends SCoreException {} +class PermissionDeniedException extends SCoreException +{ +} /** * Class ImageDoesNotExist @@ -21,9 +25,13 @@ class PermissionDeniedException extends SCoreException {} * * Example: Image::by_id(-1) returns null */ -class ImageDoesNotExist extends SCoreException {} +class ImageDoesNotExist extends SCoreException +{ +} /* * For validate_input() */ -class InvalidInput extends SCoreException {} +class InvalidInput extends SCoreException +{ +} diff --git a/core/extension.php b/core/extension.php index 5aaf3975..0b6134f2 100644 --- a/core/extension.php +++ b/core/extension.php @@ -81,50 +81,53 @@ * Then re-implemented by Shish after he broke the forum and couldn't * find the thread where the original was posted >_< */ -abstract class Extension { - /** @var array which DBs this ext supports (blank for 'all') */ - protected $db_support = []; +abstract class Extension +{ + /** @var array which DBs this ext supports (blank for 'all') */ + protected $db_support = []; - /** @var Themelet this theme's Themelet object */ - public $theme; + /** @var Themelet this theme's Themelet object */ + public $theme; - public function __construct() { - $this->theme = $this->get_theme_object(get_called_class()); - } + public function __construct() + { + $this->theme = $this->get_theme_object(get_called_class()); + } - public function is_live(): bool { - global $database; - return ( - empty($this->db_support) || - in_array($database->get_driver_name(), $this->db_support) - ); - } + public function is_live(): bool + { + global $database; + return ( + empty($this->db_support) || + in_array($database->get_driver_name(), $this->db_support) + ); + } - /** - * Find the theme object for a given extension. - */ - private function get_theme_object(string $base): ?Themelet { - $custom = 'Custom'.$base.'Theme'; - $normal = $base.'Theme'; + /** + * Find the theme object for a given extension. + */ + private function get_theme_object(string $base): ?Themelet + { + $custom = 'Custom'.$base.'Theme'; + $normal = $base.'Theme'; - if(class_exists($custom)) { - return new $custom(); - } - elseif(class_exists($normal)) { - return new $normal(); - } - else { - return null; - } - } + if (class_exists($custom)) { + return new $custom(); + } elseif (class_exists($normal)) { + return new $normal(); + } else { + return null; + } + } - /** - * Override this to change the priority of the extension, - * lower numbered ones will receive events first. - */ - public function get_priority(): int { - return 50; - } + /** + * Override this to change the priority of the extension, + * lower numbered ones will receive events first. + */ + public function get_priority(): int + { + return 50; + } } /** @@ -132,14 +135,16 @@ abstract class Extension { * * Several extensions have this in common, make a common API. */ -abstract class FormatterExtension extends Extension { - public function onTextFormatting(TextFormattingEvent $event) { - $event->formatted = $this->format($event->formatted); - $event->stripped = $this->strip($event->stripped); - } +abstract class FormatterExtension extends Extension +{ + public function onTextFormatting(TextFormattingEvent $event) + { + $event->formatted = $this->format($event->formatted); + $event->stripped = $this->strip($event->stripped); + } - abstract public function format(string $text): string; - abstract public function strip(string $text): string; + abstract public function format(string $text): string; + abstract public function strip(string $text): string; } /** @@ -148,100 +153,100 @@ abstract class FormatterExtension extends Extension { * This too is a common class of extension with many methods in common, * so we have a base class to extend from. */ -abstract class DataHandlerExtension extends Extension { - public function onDataUpload(DataUploadEvent $event) { - $supported_ext = $this->supported_ext($event->type); - $check_contents = $this->check_contents($event->tmpname); - if($supported_ext && $check_contents) { - move_upload_to_archive($event); - send_event(new ThumbnailGenerationEvent($event->hash, $event->type)); +abstract class DataHandlerExtension extends Extension +{ + public function onDataUpload(DataUploadEvent $event) + { + $supported_ext = $this->supported_ext($event->type); + $check_contents = $this->check_contents($event->tmpname); + if ($supported_ext && $check_contents) { + move_upload_to_archive($event); + send_event(new ThumbnailGenerationEvent($event->hash, $event->type)); - /* Check if we are replacing an image */ - if(array_key_exists('replace', $event->metadata) && isset($event->metadata['replace'])) { - /* hax: This seems like such a dirty way to do this.. */ + /* Check if we are replacing an image */ + if (array_key_exists('replace', $event->metadata) && isset($event->metadata['replace'])) { + /* hax: This seems like such a dirty way to do this.. */ - /* Validate things */ - $image_id = int_escape($event->metadata['replace']); + /* Validate things */ + $image_id = int_escape($event->metadata['replace']); - /* Check to make sure the image exists. */ - $existing = Image::by_id($image_id); + /* Check to make sure the image exists. */ + $existing = Image::by_id($image_id); - if(is_null($existing)) { - throw new UploadException("Image to replace does not exist!"); - } - if ($existing->hash === $event->metadata['hash']) { - throw new UploadException("The uploaded image is the same as the one to replace."); - } + if (is_null($existing)) { + throw new UploadException("Image to replace does not exist!"); + } + if ($existing->hash === $event->metadata['hash']) { + throw new UploadException("The uploaded image is the same as the one to replace."); + } - // even more hax.. - $event->metadata['tags'] = $existing->get_tag_list(); - $image = $this->create_image_from_data(warehouse_path("images", $event->metadata['hash']), $event->metadata); + // even more hax.. + $event->metadata['tags'] = $existing->get_tag_list(); + $image = $this->create_image_from_data(warehouse_path("images", $event->metadata['hash']), $event->metadata); - if(is_null($image)) { - throw new UploadException("Data handler failed to create image object from data"); - } + if (is_null($image)) { + throw new UploadException("Data handler failed to create image object from data"); + } - $ire = new ImageReplaceEvent($image_id, $image); - send_event($ire); - $event->image_id = $image_id; - } - else { - $image = $this->create_image_from_data(warehouse_path("images", $event->hash), $event->metadata); - if(is_null($image)) { - throw new UploadException("Data handler failed to create image object from data"); - } - $iae = new ImageAdditionEvent($image); - send_event($iae); - $event->image_id = $iae->image->id; + $ire = new ImageReplaceEvent($image_id, $image); + send_event($ire); + $event->image_id = $image_id; + } else { + $image = $this->create_image_from_data(warehouse_path("images", $event->hash), $event->metadata); + if (is_null($image)) { + throw new UploadException("Data handler failed to create image object from data"); + } + $iae = new ImageAdditionEvent($image); + send_event($iae); + $event->image_id = $iae->image->id; - // Rating Stuff. - if(!empty($event->metadata['rating'])){ - $rating = $event->metadata['rating']; - send_event(new RatingSetEvent($image, $rating)); - } + // Rating Stuff. + if (!empty($event->metadata['rating'])) { + $rating = $event->metadata['rating']; + send_event(new RatingSetEvent($image, $rating)); + } - // Locked Stuff. - if(!empty($event->metadata['locked'])){ - $locked = $event->metadata['locked']; - send_event(new LockSetEvent($image, !empty($locked))); - } - } - } - elseif($supported_ext && !$check_contents){ - throw new UploadException("Invalid or corrupted file"); - } - } + // Locked Stuff. + if (!empty($event->metadata['locked'])) { + $locked = $event->metadata['locked']; + send_event(new LockSetEvent($image, !empty($locked))); + } + } + } elseif ($supported_ext && !$check_contents) { + throw new UploadException("Invalid or corrupted file"); + } + } - public function onThumbnailGeneration(ThumbnailGenerationEvent $event) { - if($this->supported_ext($event->type)) { - if (method_exists($this, 'create_thumb_force') && $event->force == true) { - $this->create_thumb_force($event->hash); - } - else { - $this->create_thumb($event->hash); - } - } - } + public function onThumbnailGeneration(ThumbnailGenerationEvent $event) + { + if ($this->supported_ext($event->type)) { + if (method_exists($this, 'create_thumb_force') && $event->force == true) { + $this->create_thumb_force($event->hash); + } else { + $this->create_thumb($event->hash); + } + } + } - public function onDisplayingImage(DisplayingImageEvent $event) { - global $page; - if($this->supported_ext($event->image->ext)) { - $this->theme->display_image($page, $event->image); - } - } + public function onDisplayingImage(DisplayingImageEvent $event) + { + global $page; + if ($this->supported_ext($event->image->ext)) { + $this->theme->display_image($page, $event->image); + } + } - /* - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = $this->setup(); - if($sb) $event->panel->add_block($sb); - } + /* + public function onSetupBuilding(SetupBuildingEvent $event) { + $sb = $this->setup(); + if($sb) $event->panel->add_block($sb); + } - protected function setup() {} - */ + protected function setup() {} + */ - abstract protected function supported_ext(string $ext): bool; - abstract protected function check_contents(string $tmpname): bool; - abstract protected function create_image_from_data(string $filename, array $metadata); - abstract protected function create_thumb(string $hash): bool; + abstract protected function supported_ext(string $ext): bool; + abstract protected function check_contents(string $tmpname): bool; + abstract protected function create_image_from_data(string $filename, array $metadata); + abstract protected function create_thumb(string $hash): bool; } - diff --git a/core/imageboard/event.php b/core/imageboard/event.php index ff7def1c..9f09655a 100644 --- a/core/imageboard/event.php +++ b/core/imageboard/event.php @@ -3,99 +3,111 @@ /** * An image is being added to the database. */ -class ImageAdditionEvent extends Event { - /** @var User */ - public $user; +class ImageAdditionEvent extends Event +{ + /** @var User */ + public $user; - /** @var Image */ - public $image; + /** @var Image */ + public $image; - /** - * Inserts a new image into the database with its associated - * information. Also calls TagSetEvent to set the tags for - * this new image. - */ - public function __construct(Image $image) { - $this->image = $image; - } + /** + * Inserts a new image into the database with its associated + * information. Also calls TagSetEvent to set the tags for + * this new image. + */ + public function __construct(Image $image) + { + $this->image = $image; + } } -class ImageAdditionException extends SCoreException { - public $error; +class ImageAdditionException extends SCoreException +{ + public $error; - public function __construct(string $error) { - $this->error = $error; - } + public function __construct(string $error) + { + $this->error = $error; + } } /** * An image is being deleted. */ -class ImageDeletionEvent extends Event { - /** @var \Image */ - public $image; +class ImageDeletionEvent extends Event +{ + /** @var \Image */ + public $image; - /** - * Deletes an image. - * - * Used by things like tags and comments handlers to - * clean out related rows in their tables. - */ - public function __construct(Image $image) { - $this->image = $image; - } + /** + * Deletes an image. + * + * Used by things like tags and comments handlers to + * clean out related rows in their tables. + */ + public function __construct(Image $image) + { + $this->image = $image; + } } /** * An image is being replaced. */ -class ImageReplaceEvent extends Event { - /** @var int */ - public $id; - /** @var \Image */ - public $image; +class ImageReplaceEvent extends Event +{ + /** @var int */ + public $id; + /** @var \Image */ + public $image; - /** - * Replaces an image. - * - * Updates an existing ID in the database to use a new image - * file, leaving the tags and such unchanged. Also removes - * the old image file and thumbnail from the disk. - */ - public function __construct(int $id, Image $image) { - $this->id = $id; - $this->image = $image; - } + /** + * Replaces an image. + * + * Updates an existing ID in the database to use a new image + * file, leaving the tags and such unchanged. Also removes + * the old image file and thumbnail from the disk. + */ + public function __construct(int $id, Image $image) + { + $this->id = $id; + $this->image = $image; + } } -class ImageReplaceException extends SCoreException { - /** @var string */ - public $error; +class ImageReplaceException extends SCoreException +{ + /** @var string */ + public $error; - public function __construct(string $error) { - $this->error = $error; - } + public function __construct(string $error) + { + $this->error = $error; + } } /** * Request a thumbnail be made for an image object. */ -class ThumbnailGenerationEvent extends Event { - /** @var string */ - public $hash; - /** @var string */ - public $type; - /** @var bool */ - public $force; +class ThumbnailGenerationEvent extends Event +{ + /** @var string */ + public $hash; + /** @var string */ + public $type; + /** @var bool */ + public $force; - /** - * Request a thumbnail be made for an image object - */ - public function __construct(string $hash, string $type, bool $force=false) { - $this->hash = $hash; - $this->type = $type; - $this->force = $force; - } + /** + * Request a thumbnail be made for an image object + */ + public function __construct(string $hash, string $type, bool $force=false) + { + $this->hash = $hash; + $this->type = $type; + $this->force = $force; + } } @@ -105,21 +117,24 @@ class ThumbnailGenerationEvent extends Event { * $original -- the formatting string, for reference * $image -- the image who's link is being parsed */ -class ParseLinkTemplateEvent extends Event { - /** @var string */ - public $link; - /** @var string */ - public $original; - /** @var \Image */ - public $image; +class ParseLinkTemplateEvent extends Event +{ + /** @var string */ + public $link; + /** @var string */ + public $original; + /** @var \Image */ + public $image; - public function __construct(string $link, Image $image) { - $this->link = $link; - $this->original = $link; - $this->image = $image; - } + public function __construct(string $link, Image $image) + { + $this->link = $link; + $this->original = $link; + $this->image = $image; + } - public function replace(string $needle, string $replace): void { - $this->link = str_replace($needle, $replace, $this->link); - } + public function replace(string $needle, string $replace): void + { + $this->link = str_replace($needle, $replace, $this->link); + } } diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 7fa9d2e5..8c9e32c0 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -8,497 +8,545 @@ * image per se, but could be a video, sound file, or any * other supported upload type. */ -class Image { - private static $tag_n = 0; // temp hack - public static $order_sql = null; // this feels ugly +class Image +{ + private static $tag_n = 0; // temp hack + public static $order_sql = null; // this feels ugly - /** @var null|int */ - public $id = null; + /** @var null|int */ + public $id = null; - /** @var int */ - public $height; + /** @var int */ + public $height; - /** @var int */ - public $width; + /** @var int */ + public $width; - /** @var string */ - public $hash; + /** @var string */ + public $hash; - public $filesize; + public $filesize; - /** @var string */ - public $filename; + /** @var string */ + public $filename; - /** @var string */ - public $ext; + /** @var string */ + public $ext; - /** @var string[]|null */ - public $tag_array; + /** @var string[]|null */ + public $tag_array; - /** @var int */ - public $owner_id; - - /** @var string */ - public $owner_ip; - - /** @var string */ - public $posted; - - /** @var string */ - public $source; + /** @var int */ + public $owner_id; - /** @var boolean */ - public $locked = false; + /** @var string */ + public $owner_ip; + + /** @var string */ + public $posted; + + /** @var string */ + public $source; + + /** @var boolean */ + public $locked = false; - /** - * One will very rarely construct an image directly, more common - * would be to use Image::by_id, Image::by_hash, etc. - */ - public function __construct(?array $row=null) { - if(!is_null($row)) { - foreach($row as $name => $value) { - // some databases use table.name rather than name - $name = str_replace("images.", "", $name); - $this->$name = $value; // hax, this is likely the cause of much scrutinizer-ci complaints. - } - $this->locked = bool_escape($this->locked); + /** + * One will very rarely construct an image directly, more common + * would be to use Image::by_id, Image::by_hash, etc. + */ + public function __construct(?array $row=null) + { + if (!is_null($row)) { + foreach ($row as $name => $value) { + // some databases use table.name rather than name + $name = str_replace("images.", "", $name); + $this->$name = $value; // hax, this is likely the cause of much scrutinizer-ci complaints. + } + $this->locked = bool_escape($this->locked); - assert(is_numeric($this->id)); - assert(is_numeric($this->height)); - assert(is_numeric($this->width)); - } - } + assert(is_numeric($this->id)); + assert(is_numeric($this->height)); + assert(is_numeric($this->width)); + } + } - public static function by_id(int $id) { - global $database; - $row = $database->get_row("SELECT * FROM images WHERE images.id=:id", array("id"=>$id)); - return ($row ? new Image($row) : null); - } + public static function by_id(int $id) + { + global $database; + $row = $database->get_row("SELECT * FROM images WHERE images.id=:id", ["id"=>$id]); + return ($row ? new Image($row) : null); + } - public static function by_hash(string $hash) { - global $database; - $row = $database->get_row("SELECT images.* FROM images WHERE hash=:hash", array("hash"=>$hash)); - return ($row ? new Image($row) : null); - } + public static function by_hash(string $hash) + { + global $database; + $row = $database->get_row("SELECT images.* FROM images WHERE hash=:hash", ["hash"=>$hash]); + return ($row ? new Image($row) : null); + } - public static function by_random(array $tags=array()) { - $max = Image::count_images($tags); - if ($max < 1) return null; // From Issue #22 - opened by HungryFeline on May 30, 2011. - $rand = mt_rand(0, $max-1); - $set = Image::find_images($rand, 1, $tags); - if(count($set) > 0) return $set[0]; - else return null; - } + public static function by_random(array $tags=[]) + { + $max = Image::count_images($tags); + if ($max < 1) { + return null; + } // From Issue #22 - opened by HungryFeline on May 30, 2011. + $rand = mt_rand(0, $max-1); + $set = Image::find_images($rand, 1, $tags); + if (count($set) > 0) { + return $set[0]; + } else { + return null; + } + } - /** - * Search for an array of images - * - * #param string[] $tags - * #return Image[] - */ - public static function find_images(int $start, int $limit, array $tags=array()): array { - global $database, $user, $config; + /** + * Search for an array of images + * + * #param string[] $tags + * #return Image[] + */ + public static function find_images(int $start, int $limit, array $tags=[]): array + { + global $database, $user, $config; - $images = array(); + $images = []; - if($start < 0) $start = 0; - if($limit < 1) $limit = 1; + if ($start < 0) { + $start = 0; + } + if ($limit < 1) { + $limit = 1; + } - if(SPEED_HAX) { - if(!$user->can("big_search") and count($tags) > 3) { - throw new SCoreException("Anonymous users may only search for up to 3 tags at a time"); - } - } + if (SPEED_HAX) { + if (!$user->can("big_search") and count($tags) > 3) { + throw new SCoreException("Anonymous users may only search for up to 3 tags at a time"); + } + } - $result = null; - if(SEARCH_ACCEL) { - $result = Image::get_accelerated_result($tags, $start, $limit); - } + $result = null; + if (SEARCH_ACCEL) { + $result = Image::get_accelerated_result($tags, $start, $limit); + } - if(!$result) { - $querylet = Image::build_search_querylet($tags); - $querylet->append(new Querylet(" ORDER BY ".(Image::$order_sql ?: "images.".$config->get_string("index_order")))); - $querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", array("limit"=>$limit, "offset"=>$start))); - #var_dump($querylet->sql); var_dump($querylet->variables); - $result = $database->execute($querylet->sql, $querylet->variables); - } + if (!$result) { + $querylet = Image::build_search_querylet($tags); + $querylet->append(new Querylet(" ORDER BY ".(Image::$order_sql ?: "images.".$config->get_string("index_order")))); + $querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", ["limit"=>$limit, "offset"=>$start])); + #var_dump($querylet->sql); var_dump($querylet->variables); + $result = $database->execute($querylet->sql, $querylet->variables); + } - while($row = $result->fetch()) { - $images[] = new Image($row); - } - Image::$order_sql = null; - return $images; - } + while ($row = $result->fetch()) { + $images[] = new Image($row); + } + Image::$order_sql = null; + return $images; + } - /* - * Accelerator stuff - */ - public static function get_acceleratable(array $tags) { - $ret = array( - "yays" => array(), - "nays" => array(), - ); - $yays = 0; - $nays = 0; - foreach($tags as $tag) { - if(!preg_match("/^-?[a-zA-Z0-9_-]+$/", $tag)) { - return false; - } - if($tag[0] == "-") {$nays++; $ret["nays"][] = substr($tag, 1);} - else {$yays++; $ret["yays"][] = $tag;} - } - if($yays > 1 || $nays > 0) { - return $ret; - } - return false; - } + /* + * Accelerator stuff + */ + public static function get_acceleratable(array $tags) + { + $ret = [ + "yays" => [], + "nays" => [], + ]; + $yays = 0; + $nays = 0; + foreach ($tags as $tag) { + if (!preg_match("/^-?[a-zA-Z0-9_-]+$/", $tag)) { + return false; + } + if ($tag[0] == "-") { + $nays++; + $ret["nays"][] = substr($tag, 1); + } else { + $yays++; + $ret["yays"][] = $tag; + } + } + if ($yays > 1 || $nays > 0) { + return $ret; + } + return false; + } - public static function get_accelerated_result(array $tags, int $offset, int $limit) { - global $database; + public static function get_accelerated_result(array $tags, int $offset, int $limit) + { + global $database; - $req = Image::get_acceleratable($tags); - if(!$req) {return null;} - $req["offset"] = $offset; - $req["limit"] = $limit; + $req = Image::get_acceleratable($tags); + if (!$req) { + return null; + } + $req["offset"] = $offset; + $req["limit"] = $limit; - $response = Image::query_accelerator($req); - $list = implode(",", $response); - if($list) { - $result = $database->execute("SELECT * FROM images WHERE id IN ($list) ORDER BY images.id DESC"); - } - else { - $result = $database->execute("SELECT * FROM images WHERE 1=0 ORDER BY images.id DESC"); - } - return $result; - } + $response = Image::query_accelerator($req); + $list = implode(",", $response); + if ($list) { + $result = $database->execute("SELECT * FROM images WHERE id IN ($list) ORDER BY images.id DESC"); + } else { + $result = $database->execute("SELECT * FROM images WHERE 1=0 ORDER BY images.id DESC"); + } + return $result; + } - public static function get_accelerated_count(array $tags) { - $req = Image::get_acceleratable($tags); - if(!$req) {return null;} - $req["count"] = true; + public static function get_accelerated_count(array $tags) + { + $req = Image::get_acceleratable($tags); + if (!$req) { + return null; + } + $req["count"] = true; - return Image::query_accelerator($req); - } + return Image::query_accelerator($req); + } - public static function query_accelerator($req) { - $fp = @fsockopen("127.0.0.1", 21212); - if (!$fp) { - return null; - } - fwrite($fp, json_encode($req)); - $data = ""; - while (($buffer = fgets($fp, 4096)) !== false) { - $data .= $buffer; - } - if (!feof($fp)) { - die("Error: unexpected fgets() fail in query_accelerator($req)\n"); - } - fclose($fp); - return json_decode($data); - } + public static function query_accelerator($req) + { + $fp = @fsockopen("127.0.0.1", 21212); + if (!$fp) { + return null; + } + fwrite($fp, json_encode($req)); + $data = ""; + while (($buffer = fgets($fp, 4096)) !== false) { + $data .= $buffer; + } + if (!feof($fp)) { + die("Error: unexpected fgets() fail in query_accelerator($req)\n"); + } + fclose($fp); + return json_decode($data); + } - /* - * Image-related utility functions - */ + /* + * Image-related utility functions + */ - /** - * Count the number of image results for a given search - * - * #param string[] $tags - */ - public static function count_images(array $tags=array()): int { - global $database; - $tag_count = count($tags); + /** + * Count the number of image results for a given search + * + * #param string[] $tags + */ + public static function count_images(array $tags=[]): int + { + global $database; + $tag_count = count($tags); - if($tag_count === 0) { - $total = $database->cache->get("image-count"); - if(!$total) { - $total = $database->get_one("SELECT COUNT(*) FROM images"); - $database->cache->set("image-count", $total, 600); - } - } - else if($tag_count === 1 && !preg_match("/[:=><\*\?]/", $tags[0])) { - $total = $database->get_one( - $database->scoreql_to_sql("SELECT count FROM tags WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)"), - array("tag"=>$tags[0])); - } - else { - $total = Image::get_accelerated_count($tags); - if(is_null($total)) { - $querylet = Image::build_search_querylet($tags); - $total = $database->get_one("SELECT COUNT(*) AS cnt FROM ($querylet->sql) AS tbl", $querylet->variables); - } - } - if(is_null($total)) return 0; - return $total; - } + if ($tag_count === 0) { + $total = $database->cache->get("image-count"); + if (!$total) { + $total = $database->get_one("SELECT COUNT(*) FROM images"); + $database->cache->set("image-count", $total, 600); + } + } elseif ($tag_count === 1 && !preg_match("/[:=><\*\?]/", $tags[0])) { + $total = $database->get_one( + $database->scoreql_to_sql("SELECT count FROM tags WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)"), + ["tag"=>$tags[0]] + ); + } else { + $total = Image::get_accelerated_count($tags); + if (is_null($total)) { + $querylet = Image::build_search_querylet($tags); + $total = $database->get_one("SELECT COUNT(*) AS cnt FROM ($querylet->sql) AS tbl", $querylet->variables); + } + } + if (is_null($total)) { + return 0; + } + return $total; + } - /** - * Count the number of pages for a given search - * - * #param string[] $tags - */ - public static function count_pages(array $tags=array()): float { - global $config; - return ceil(Image::count_images($tags) / $config->get_int('index_images')); - } + /** + * Count the number of pages for a given search + * + * #param string[] $tags + */ + public static function count_pages(array $tags=[]): float + { + global $config; + return ceil(Image::count_images($tags) / $config->get_int('index_images')); + } - /* - * Accessors & mutators - */ + /* + * Accessors & mutators + */ - /** - * Find the next image in the sequence. - * - * Rather than simply $this_id + 1, one must take into account - * deleted images and search queries - * - * #param string[] $tags - */ - public function get_next(array $tags=array(), bool $next=true): ?Image { - global $database; + /** + * Find the next image in the sequence. + * + * Rather than simply $this_id + 1, one must take into account + * deleted images and search queries + * + * #param string[] $tags + */ + public function get_next(array $tags=[], bool $next=true): ?Image + { + global $database; - if($next) { - $gtlt = "<"; - $dir = "DESC"; - } - else { - $gtlt = ">"; - $dir = "ASC"; - } + if ($next) { + $gtlt = "<"; + $dir = "DESC"; + } else { + $gtlt = ">"; + $dir = "ASC"; + } - if(count($tags) === 0) { - $row = $database->get_row(' + if (count($tags) === 0) { + $row = $database->get_row(' SELECT images.* FROM images WHERE images.id '.$gtlt.' '.$this->id.' ORDER BY images.id '.$dir.' LIMIT 1 '); - } - else { - $tags[] = 'id'. $gtlt . $this->id; - $querylet = Image::build_search_querylet($tags); - $querylet->append_sql(' ORDER BY images.id '.$dir.' LIMIT 1'); - $row = $database->get_row($querylet->sql, $querylet->variables); - } + } else { + $tags[] = 'id'. $gtlt . $this->id; + $querylet = Image::build_search_querylet($tags); + $querylet->append_sql(' ORDER BY images.id '.$dir.' LIMIT 1'); + $row = $database->get_row($querylet->sql, $querylet->variables); + } - return ($row ? new Image($row) : null); - } + return ($row ? new Image($row) : null); + } - /** - * The reverse of get_next - * - * #param string[] $tags - */ - public function get_prev(array $tags=array()): ?Image { - return $this->get_next($tags, false); - } + /** + * The reverse of get_next + * + * #param string[] $tags + */ + public function get_prev(array $tags=[]): ?Image + { + return $this->get_next($tags, false); + } - /** - * Find the User who owns this Image - */ - public function get_owner(): User { - return User::by_id($this->owner_id); - } + /** + * Find the User who owns this Image + */ + public function get_owner(): User + { + return User::by_id($this->owner_id); + } - /** - * Set the image's owner. - */ - public function set_owner(User $owner) { - global $database; - if($owner->id != $this->owner_id) { - $database->execute(" + /** + * Set the image's owner. + */ + public function set_owner(User $owner) + { + global $database; + if ($owner->id != $this->owner_id) { + $database->execute(" UPDATE images SET owner_id=:owner_id WHERE id=:id - ", array("owner_id"=>$owner->id, "id"=>$this->id)); - log_info("core_image", "Owner for Image #{$this->id} set to {$owner->name}", null, array("image_id" => $this->id)); - } - } + ", ["owner_id"=>$owner->id, "id"=>$this->id]); + log_info("core_image", "Owner for Image #{$this->id} set to {$owner->name}", null, ["image_id" => $this->id]); + } + } - /** - * Get this image's tags as an array. - * - * #return string[] - */ - public function get_tag_array(): array { - global $database; - if(!isset($this->tag_array)) { - $this->tag_array = $database->get_col(" + /** + * Get this image's tags as an array. + * + * #return string[] + */ + public function get_tag_array(): array + { + global $database; + if (!isset($this->tag_array)) { + $this->tag_array = $database->get_col(" SELECT tag FROM image_tags JOIN tags ON image_tags.tag_id = tags.id WHERE image_id=:id ORDER BY tag - ", array("id"=>$this->id)); - } - return $this->tag_array; - } + ", ["id"=>$this->id]); + } + return $this->tag_array; + } - /** - * Get this image's tags as a string. - */ - public function get_tag_list(): string { - return Tag::implode($this->get_tag_array()); - } + /** + * Get this image's tags as a string. + */ + public function get_tag_list(): string + { + return Tag::implode($this->get_tag_array()); + } - /** - * Get the URL for the full size image - */ - public function get_image_link(): string { - return $this->get_link('image_ilink', '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext'); - } + /** + * Get the URL for the full size image + */ + public function get_image_link(): string + { + return $this->get_link('image_ilink', '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext'); + } - /** - * Get the URL for the thumbnail - */ - public function get_thumb_link(): string { - return $this->get_link('image_tlink', '_thumbs/$hash/thumb.jpg', 'thumb/$id.jpg'); - } + /** + * Get the URL for the thumbnail + */ + public function get_thumb_link(): string + { + return $this->get_link('image_tlink', '_thumbs/$hash/thumb.jpg', 'thumb/$id.jpg'); + } - /** - * Check configured template for a link, then try nice URL, then plain URL - */ - private function get_link(string $template, string $nice, string $plain): string { - global $config; + /** + * Check configured template for a link, then try nice URL, then plain URL + */ + private function get_link(string $template, string $nice, string $plain): string + { + global $config; - $image_link = $config->get_string($template); + $image_link = $config->get_string($template); - if(!empty($image_link)) { - if(!(strpos($image_link, "://") > 0) && !startsWith($image_link, "/")) { - $image_link = make_link($image_link); - } - return $this->parse_link_template($image_link); - } - else if($config->get_bool('nice_urls', false)) { - return $this->parse_link_template(make_link($nice)); - } - else { - return $this->parse_link_template(make_link($plain)); - } - } + if (!empty($image_link)) { + if (!(strpos($image_link, "://") > 0) && !startsWith($image_link, "/")) { + $image_link = make_link($image_link); + } + return $this->parse_link_template($image_link); + } elseif ($config->get_bool('nice_urls', false)) { + return $this->parse_link_template(make_link($nice)); + } else { + return $this->parse_link_template(make_link($plain)); + } + } - /** - * Get the tooltip for this image, formatted according to the - * configured template. - */ - public function get_tooltip(): string { - global $config; - $tt = $this->parse_link_template($config->get_string('image_tip'), "no_escape"); + /** + * Get the tooltip for this image, formatted according to the + * configured template. + */ + public function get_tooltip(): string + { + global $config; + $tt = $this->parse_link_template($config->get_string('image_tip'), "no_escape"); - // Removes the size tag if the file is an mp3 - if($this->ext === 'mp3'){ - $iitip = $tt; - $mp3tip = array("0x0"); - $h_tip = str_replace($mp3tip, " ", $iitip); + // Removes the size tag if the file is an mp3 + if ($this->ext === 'mp3') { + $iitip = $tt; + $mp3tip = ["0x0"]; + $h_tip = str_replace($mp3tip, " ", $iitip); - // Makes it work with a variation of the default tooltips (I.E $tags // $filesize // $size) - $justincase = array(" //", "// ", " //", "// ", " "); - if(strstr($h_tip, " ")) { - $h_tip = html_escape(str_replace($justincase, "", $h_tip)); - }else{ - $h_tip = html_escape($h_tip); - } - return $h_tip; - } - else { - return $tt; - } - } + // Makes it work with a variation of the default tooltips (I.E $tags // $filesize // $size) + $justincase = [" //", "// ", " //", "// ", " "]; + if (strstr($h_tip, " ")) { + $h_tip = html_escape(str_replace($justincase, "", $h_tip)); + } else { + $h_tip = html_escape($h_tip); + } + return $h_tip; + } else { + return $tt; + } + } - /** - * Figure out where the full size image is on disk. - */ - public function get_image_filename(): string { - return warehouse_path("images", $this->hash); - } + /** + * Figure out where the full size image is on disk. + */ + public function get_image_filename(): string + { + return warehouse_path("images", $this->hash); + } - /** - * Figure out where the thumbnail is on disk. - */ - public function get_thumb_filename(): string { - return warehouse_path("thumbs", $this->hash); - } + /** + * Figure out where the thumbnail is on disk. + */ + public function get_thumb_filename(): string + { + return warehouse_path("thumbs", $this->hash); + } - /** - * Get the original filename. - */ - public function get_filename(): string { - return $this->filename; - } + /** + * Get the original filename. + */ + public function get_filename(): string + { + return $this->filename; + } - /** - * Get the image's mime type. - */ - public function get_mime_type(): string { - return getMimeType($this->get_image_filename(), $this->get_ext()); - } + /** + * Get the image's mime type. + */ + public function get_mime_type(): string + { + return getMimeType($this->get_image_filename(), $this->get_ext()); + } - /** - * Get the image's filename extension - */ - public function get_ext(): string { - return $this->ext; - } + /** + * Get the image's filename extension + */ + public function get_ext(): string + { + return $this->ext; + } - /** - * Get the image's source URL - */ - public function get_source(): string { - return $this->source; - } + /** + * Get the image's source URL + */ + public function get_source(): string + { + return $this->source; + } - /** - * Set the image's source URL - */ - public function set_source(string $new_source): void { - global $database; - $old_source = $this->source; - if(empty($new_source)) $new_source = null; - if($new_source != $old_source) { - $database->execute("UPDATE images SET source=:source WHERE id=:id", array("source"=>$new_source, "id"=>$this->id)); - log_info("core_image", "Source for Image #{$this->id} set to: $new_source (was $old_source)", null, array("image_id" => $this->id)); - } - } + /** + * Set the image's source URL + */ + public function set_source(string $new_source): void + { + global $database; + $old_source = $this->source; + if (empty($new_source)) { + $new_source = null; + } + if ($new_source != $old_source) { + $database->execute("UPDATE images SET source=:source WHERE id=:id", ["source"=>$new_source, "id"=>$this->id]); + log_info("core_image", "Source for Image #{$this->id} set to: $new_source (was $old_source)", null, ["image_id" => $this->id]); + } + } - /** - * Check if the image is locked. - */ - public function is_locked(): bool { - return $this->locked; - } + /** + * Check if the image is locked. + */ + public function is_locked(): bool + { + return $this->locked; + } - public function set_locked(bool $tf) { - global $database; - $ln = $tf ? "Y" : "N"; - $sln = $database->scoreql_to_sql('SCORE_BOOL_'.$ln); - $sln = str_replace("'", "", $sln); - $sln = str_replace('"', "", $sln); - if(bool_escape($sln) !== $this->locked) { - $database->execute("UPDATE images SET locked=:yn WHERE id=:id", array("yn"=>$sln, "id"=>$this->id)); - log_info("core_image", "Setting Image #{$this->id} lock to: $ln", null, array("image_id" => $this->id)); - } - } + public function set_locked(bool $tf) + { + global $database; + $ln = $tf ? "Y" : "N"; + $sln = $database->scoreql_to_sql('SCORE_BOOL_'.$ln); + $sln = str_replace("'", "", $sln); + $sln = str_replace('"', "", $sln); + if (bool_escape($sln) !== $this->locked) { + $database->execute("UPDATE images SET locked=:yn WHERE id=:id", ["yn"=>$sln, "id"=>$this->id]); + log_info("core_image", "Setting Image #{$this->id} lock to: $ln", null, ["image_id" => $this->id]); + } + } - /** - * Delete all tags from this image. - * - * Normally in preparation to set them to a new set. - */ - public function delete_tags_from_image(): void { - global $database; - if($database->get_driver_name() == "mysql") { - //mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this - $database->execute(" + /** + * Delete all tags from this image. + * + * Normally in preparation to set them to a new set. + */ + public function delete_tags_from_image(): void + { + global $database; + if ($database->get_driver_name() == "mysql") { + //mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this + $database->execute( + " UPDATE tags t INNER JOIN image_tags it ON t.id = it.tag_id SET count = count - 1 WHERE it.image_id = :id", - array("id"=>$this->id) - ); - } else { - $database->execute(" + ["id"=>$this->id] + ); + } else { + $database->execute(" UPDATE tags SET count = count - 1 WHERE id IN ( @@ -506,270 +554,278 @@ class Image { FROM image_tags WHERE image_id = :id ) - ", array("id"=>$this->id)); - } - $database->execute(" + ", ["id"=>$this->id]); + } + $database->execute(" DELETE FROM image_tags WHERE image_id=:id - ", array("id"=>$this->id)); - } + ", ["id"=>$this->id]); + } - /** - * Set the tags for this image. - */ - public function set_tags(array $unfiltered_tags) { - global $database; + /** + * Set the tags for this image. + */ + public function set_tags(array $unfiltered_tags) + { + global $database; - $tags = []; - foreach ($unfiltered_tags as $tag) { - if(mb_strlen($tag, 'UTF-8') > 255){ - flash_message("Can't set a tag longer than 255 characters"); - continue; - } - if(startsWith($tag, "-")) { - flash_message("Can't set a tag which starts with a minus"); - continue; - } + $tags = []; + foreach ($unfiltered_tags as $tag) { + if (mb_strlen($tag, 'UTF-8') > 255) { + flash_message("Can't set a tag longer than 255 characters"); + continue; + } + if (startsWith($tag, "-")) { + flash_message("Can't set a tag which starts with a minus"); + continue; + } - $tags[] = $tag; - } + $tags[] = $tag; + } - if(count($tags) <= 0) { - throw new SCoreException('Tried to set zero tags'); - } + if (count($tags) <= 0) { + throw new SCoreException('Tried to set zero tags'); + } - if(Tag::implode($tags) != $this->get_tag_list()) { - // delete old - $this->delete_tags_from_image(); - // insert each new tags - foreach($tags as $tag) { - $id = $database->get_one( - $database->scoreql_to_sql(" + if (Tag::implode($tags) != $this->get_tag_list()) { + // delete old + $this->delete_tags_from_image(); + // insert each new tags + foreach ($tags as $tag) { + $id = $database->get_one( + $database->scoreql_to_sql(" SELECT id FROM tags WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag) "), - array("tag"=>$tag) - ); - if(empty($id)) { - // a new tag - $database->execute( - "INSERT INTO tags(tag) VALUES (:tag)", - array("tag"=>$tag)); - $database->execute( - "INSERT INTO image_tags(image_id, tag_id) + ["tag"=>$tag] + ); + if (empty($id)) { + // a new tag + $database->execute( + "INSERT INTO tags(tag) VALUES (:tag)", + ["tag"=>$tag] + ); + $database->execute( + "INSERT INTO image_tags(image_id, tag_id) VALUES(:id, (SELECT id FROM tags WHERE tag = :tag))", - array("id"=>$this->id, "tag"=>$tag)); - } - else { - // user of an existing tag - $database->execute(" + ["id"=>$this->id, "tag"=>$tag] + ); + } else { + // user of an existing tag + $database->execute(" INSERT INTO image_tags(image_id, tag_id) VALUES(:iid, :tid) - ", array("iid"=>$this->id, "tid"=>$id)); - } - $database->execute( - $database->scoreql_to_sql(" + ", ["iid"=>$this->id, "tid"=>$id]); + } + $database->execute( + $database->scoreql_to_sql(" UPDATE tags SET count = count + 1 WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag) "), - array("tag"=>$tag) - ); - } + ["tag"=>$tag] + ); + } - log_info("core_image", "Tags for Image #{$this->id} set to: ".Tag::implode($tags), null, array("image_id" => $this->id)); - $database->cache->delete("image-{$this->id}-tags"); - } - } + log_info("core_image", "Tags for Image #{$this->id} set to: ".Tag::implode($tags), null, ["image_id" => $this->id]); + $database->cache->delete("image-{$this->id}-tags"); + } + } - /** - * Send list of metatags to be parsed. - * - * #param string[] $metatags - */ - public function parse_metatags(array $metatags, int $image_id): void { - foreach($metatags as $tag) { - $ttpe = new TagTermParseEvent($tag, $image_id, TRUE); - send_event($ttpe); - } - } + /** + * Send list of metatags to be parsed. + * + * #param string[] $metatags + */ + public function parse_metatags(array $metatags, int $image_id): void + { + foreach ($metatags as $tag) { + $ttpe = new TagTermParseEvent($tag, $image_id, true); + send_event($ttpe); + } + } - /** - * Delete this image from the database and disk - */ - public function delete(): void { - global $database; - $this->delete_tags_from_image(); - $database->execute("DELETE FROM images WHERE id=:id", array("id"=>$this->id)); - log_info("core_image", 'Deleted Image #'.$this->id.' ('.$this->hash.')', null, array("image_id" => $this->id)); + /** + * Delete this image from the database and disk + */ + public function delete(): void + { + global $database; + $this->delete_tags_from_image(); + $database->execute("DELETE FROM images WHERE id=:id", ["id"=>$this->id]); + log_info("core_image", 'Deleted Image #'.$this->id.' ('.$this->hash.')', null, ["image_id" => $this->id]); - unlink($this->get_image_filename()); - unlink($this->get_thumb_filename()); - } + unlink($this->get_image_filename()); + unlink($this->get_thumb_filename()); + } - /** - * This function removes an image (and thumbnail) from the DISK ONLY. - * It DOES NOT remove anything from the database. - */ - public function remove_image_only(): void { - log_info("core_image", 'Removed Image File ('.$this->hash.')', null, array("image_id" => $this->id)); - @unlink($this->get_image_filename()); - @unlink($this->get_thumb_filename()); - } + /** + * This function removes an image (and thumbnail) from the DISK ONLY. + * It DOES NOT remove anything from the database. + */ + public function remove_image_only(): void + { + log_info("core_image", 'Removed Image File ('.$this->hash.')', null, ["image_id" => $this->id]); + @unlink($this->get_image_filename()); + @unlink($this->get_thumb_filename()); + } - public function parse_link_template(string $tmpl, string $_escape="url_escape", int $n=0): string { - global $config; + public function parse_link_template(string $tmpl, string $_escape="url_escape", int $n=0): string + { + global $config; - // don't bother hitting the database if it won't be used... - $tags = ""; - if(strpos($tmpl, '$tags') !== false) { // * stabs dynamically typed languages with a rusty spoon * - $tags = $this->get_tag_list(); - $tags = str_replace("/", "", $tags); - $tags = preg_replace("/^\.+/", "", $tags); - } + // don't bother hitting the database if it won't be used... + $tags = ""; + if (strpos($tmpl, '$tags') !== false) { // * stabs dynamically typed languages with a rusty spoon * + $tags = $this->get_tag_list(); + $tags = str_replace("/", "", $tags); + $tags = preg_replace("/^\.+/", "", $tags); + } - $base_href = $config->get_string('base_href'); - $fname = $this->get_filename(); - $base_fname = strpos($fname, '.') ? substr($fname, 0, strrpos($fname, '.')) : $fname; + $base_href = $config->get_string('base_href'); + $fname = $this->get_filename(); + $base_fname = strpos($fname, '.') ? substr($fname, 0, strrpos($fname, '.')) : $fname; - $tmpl = str_replace('$id', $this->id, $tmpl); - $tmpl = str_replace('$hash_ab', substr($this->hash, 0, 2), $tmpl); - $tmpl = str_replace('$hash_cd', substr($this->hash, 2, 2), $tmpl); - $tmpl = str_replace('$hash', $this->hash, $tmpl); - $tmpl = str_replace('$tags', $_escape($tags), $tmpl); - $tmpl = str_replace('$base', $base_href, $tmpl); - $tmpl = str_replace('$ext', $this->ext, $tmpl); - $tmpl = str_replace('$size', "{$this->width}x{$this->height}", $tmpl); - $tmpl = str_replace('$filesize', to_shorthand_int($this->filesize), $tmpl); - $tmpl = str_replace('$filename', $_escape($base_fname), $tmpl); - $tmpl = str_replace('$title', $_escape($config->get_string("title")), $tmpl); - $tmpl = str_replace('$date', $_escape(autodate($this->posted, false)), $tmpl); + $tmpl = str_replace('$id', $this->id, $tmpl); + $tmpl = str_replace('$hash_ab', substr($this->hash, 0, 2), $tmpl); + $tmpl = str_replace('$hash_cd', substr($this->hash, 2, 2), $tmpl); + $tmpl = str_replace('$hash', $this->hash, $tmpl); + $tmpl = str_replace('$tags', $_escape($tags), $tmpl); + $tmpl = str_replace('$base', $base_href, $tmpl); + $tmpl = str_replace('$ext', $this->ext, $tmpl); + $tmpl = str_replace('$size', "{$this->width}x{$this->height}", $tmpl); + $tmpl = str_replace('$filesize', to_shorthand_int($this->filesize), $tmpl); + $tmpl = str_replace('$filename', $_escape($base_fname), $tmpl); + $tmpl = str_replace('$title', $_escape($config->get_string("title")), $tmpl); + $tmpl = str_replace('$date', $_escape(autodate($this->posted, false)), $tmpl); - // nothing seems to use this, sending the event out to 50 exts is a lot of overhead - if(!SPEED_HAX) { - $plte = new ParseLinkTemplateEvent($tmpl, $this); - send_event($plte); - $tmpl = $plte->link; - } + // nothing seems to use this, sending the event out to 50 exts is a lot of overhead + if (!SPEED_HAX) { + $plte = new ParseLinkTemplateEvent($tmpl, $this); + send_event($plte); + $tmpl = $plte->link; + } - static $flexihash = null; - static $fh_last_opts = null; - $matches = array(); - if(preg_match("/(.*){(.*)}(.*)/", $tmpl, $matches)) { - $pre = $matches[1]; - $opts = $matches[2]; - $post = $matches[3]; + static $flexihash = null; + static $fh_last_opts = null; + $matches = []; + if (preg_match("/(.*){(.*)}(.*)/", $tmpl, $matches)) { + $pre = $matches[1]; + $opts = $matches[2]; + $post = $matches[3]; - if($opts != $fh_last_opts) { - $fh_last_opts = $opts; - $flexihash = new Flexihash\Flexihash(); - foreach(explode(",", $opts) as $opt) { - $parts = explode("=", $opt); - $parts_count = count($parts); - $opt_val = ""; - $opt_weight = 0; - if($parts_count === 2) { - $opt_val = $parts[0]; - $opt_weight = $parts[1]; - } - elseif($parts_count === 1) { - $opt_val = $parts[0]; - $opt_weight = 1; - } - $flexihash->addTarget($opt_val, $opt_weight); - } - } + if ($opts != $fh_last_opts) { + $fh_last_opts = $opts; + $flexihash = new Flexihash\Flexihash(); + foreach (explode(",", $opts) as $opt) { + $parts = explode("=", $opt); + $parts_count = count($parts); + $opt_val = ""; + $opt_weight = 0; + if ($parts_count === 2) { + $opt_val = $parts[0]; + $opt_weight = $parts[1]; + } elseif ($parts_count === 1) { + $opt_val = $parts[0]; + $opt_weight = 1; + } + $flexihash->addTarget($opt_val, $opt_weight); + } + } - // $choice = $flexihash->lookup($pre.$post); - $choices = $flexihash->lookupList($this->hash, $n+1); // hash doesn't change - $choice = $choices[$n]; - $tmpl = $pre.$choice.$post; - } + // $choice = $flexihash->lookup($pre.$post); + $choices = $flexihash->lookupList($this->hash, $n+1); // hash doesn't change + $choice = $choices[$n]; + $tmpl = $pre.$choice.$post; + } - return $tmpl; - } + return $tmpl; + } - /** - * #param string[] $terms - */ - private static function build_search_querylet(array $terms): Querylet { - global $database; + /** + * #param string[] $terms + */ + private static function build_search_querylet(array $terms): Querylet + { + global $database; - $tag_querylets = array(); - $img_querylets = array(); - $positive_tag_count = 0; - $negative_tag_count = 0; + $tag_querylets = []; + $img_querylets = []; + $positive_tag_count = 0; + $negative_tag_count = 0; - /* - * Turn a bunch of strings into a bunch of TagQuerylet - * and ImgQuerylet objects - */ - $stpe = new SearchTermParseEvent(null, $terms); - send_event($stpe); - if ($stpe->is_querylet_set()) { - foreach ($stpe->get_querylets() as $querylet) { - $img_querylets[] = new ImgQuerylet($querylet, true); - } - } + /* + * Turn a bunch of strings into a bunch of TagQuerylet + * and ImgQuerylet objects + */ + $stpe = new SearchTermParseEvent(null, $terms); + send_event($stpe); + if ($stpe->is_querylet_set()) { + foreach ($stpe->get_querylets() as $querylet) { + $img_querylets[] = new ImgQuerylet($querylet, true); + } + } - foreach ($terms as $term) { - $positive = true; - if (is_string($term) && !empty($term) && ($term[0] == '-')) { - $positive = false; - $term = substr($term, 1); - } - if (strlen($term) === 0) { - continue; - } + foreach ($terms as $term) { + $positive = true; + if (is_string($term) && !empty($term) && ($term[0] == '-')) { + $positive = false; + $term = substr($term, 1); + } + if (strlen($term) === 0) { + continue; + } - $stpe = new SearchTermParseEvent($term, $terms); - send_event($stpe); - if ($stpe->is_querylet_set()) { - foreach ($stpe->get_querylets() as $querylet) { - $img_querylets[] = new ImgQuerylet($querylet, $positive); - } - } - else { - // if the whole match is wild, skip this; - // if not, translate into SQL - if(str_replace("*", "", $term) != "") { - $term = str_replace('_', '\_', $term); - $term = str_replace('%', '\%', $term); - $term = str_replace('*', '%', $term); - $tag_querylets[] = new TagQuerylet($term, $positive); - if ($positive) $positive_tag_count++; - else $negative_tag_count++; - } - } - } + $stpe = new SearchTermParseEvent($term, $terms); + send_event($stpe); + if ($stpe->is_querylet_set()) { + foreach ($stpe->get_querylets() as $querylet) { + $img_querylets[] = new ImgQuerylet($querylet, $positive); + } + } else { + // if the whole match is wild, skip this; + // if not, translate into SQL + if (str_replace("*", "", $term) != "") { + $term = str_replace('_', '\_', $term); + $term = str_replace('%', '\%', $term); + $term = str_replace('*', '%', $term); + $tag_querylets[] = new TagQuerylet($term, $positive); + if ($positive) { + $positive_tag_count++; + } else { + $negative_tag_count++; + } + } + } + } - /* - * Turn a bunch of Querylet objects into a base query - * - * Must follow the format - * - * SELECT images.* - * FROM (...) AS images - * WHERE (...) - * - * ie, return a set of images.* columns, and end with a WHERE - */ + /* + * Turn a bunch of Querylet objects into a base query + * + * Must follow the format + * + * SELECT images.* + * FROM (...) AS images + * WHERE (...) + * + * ie, return a set of images.* columns, and end with a WHERE + */ - // no tags, do a simple search - if($positive_tag_count === 0 && $negative_tag_count === 0) { - $query = new Querylet(" + // no tags, do a simple search + if ($positive_tag_count === 0 && $negative_tag_count === 0) { + $query = new Querylet(" SELECT images.* FROM images WHERE 1=1 "); - } + } - // one positive tag (a common case), do an optimised search - else if($positive_tag_count === 1 && $negative_tag_count === 0) { - # "LIKE" to account for wildcards - $query = new Querylet($database->scoreql_to_sql(" + // one positive tag (a common case), do an optimised search + elseif ($positive_tag_count === 1 && $negative_tag_count === 0) { + # "LIKE" to account for wildcards + $query = new Querylet($database->scoreql_to_sql(" SELECT * FROM ( SELECT images.* @@ -780,104 +836,110 @@ class Image { GROUP BY images.id ) AS images WHERE 1=1 - "), array("tag"=>$tag_querylets[0]->tag)); - } + "), ["tag"=>$tag_querylets[0]->tag]); + } - // more than one positive tag, or more than zero negative tags - else { - if($database->get_driver_name() === "mysql") - $query = Image::build_ugly_search_querylet($tag_querylets); - else - $query = Image::build_accurate_search_querylet($tag_querylets); - } + // more than one positive tag, or more than zero negative tags + else { + if ($database->get_driver_name() === "mysql") { + $query = Image::build_ugly_search_querylet($tag_querylets); + } else { + $query = Image::build_accurate_search_querylet($tag_querylets); + } + } - /* - * Merge all the image metadata searches into one generic querylet - * and append to the base querylet with "AND blah" - */ - if(!empty($img_querylets)) { - $n = 0; - $img_sql = ""; - $img_vars = array(); - foreach ($img_querylets as $iq) { - if ($n++ > 0) $img_sql .= " AND"; - if (!$iq->positive) $img_sql .= " NOT"; - $img_sql .= " (" . $iq->qlet->sql . ")"; - $img_vars = array_merge($img_vars, $iq->qlet->variables); - } - $query->append_sql(" AND "); - $query->append(new Querylet($img_sql, $img_vars)); - } + /* + * Merge all the image metadata searches into one generic querylet + * and append to the base querylet with "AND blah" + */ + if (!empty($img_querylets)) { + $n = 0; + $img_sql = ""; + $img_vars = []; + foreach ($img_querylets as $iq) { + if ($n++ > 0) { + $img_sql .= " AND"; + } + if (!$iq->positive) { + $img_sql .= " NOT"; + } + $img_sql .= " (" . $iq->qlet->sql . ")"; + $img_vars = array_merge($img_vars, $iq->qlet->variables); + } + $query->append_sql(" AND "); + $query->append(new Querylet($img_sql, $img_vars)); + } - return $query; - } + return $query; + } - /** - * WARNING: this description is no longer accurate, though it does get across - * the general idea - the actual method has a few extra optimisations - * - * "foo bar -baz user=foo" becomes - * - * SELECT * FROM images WHERE - * images.id IN (SELECT image_id FROM image_tags WHERE tag='foo') - * AND images.id IN (SELECT image_id FROM image_tags WHERE tag='bar') - * AND NOT images.id IN (SELECT image_id FROM image_tags WHERE tag='baz') - * AND images.id IN (SELECT id FROM images WHERE owner_name='foo') - * - * This is: - * A) Incredibly simple: - * Each search term maps to a list of image IDs - * B) Runs really fast on a good database: - * These lists are calculated once, and the set intersection taken - * C) Runs really slow on bad databases: - * All the subqueries are executed every time for every row in the - * images table. Yes, MySQL does suck this much. - * - * #param TagQuerylet[] $tag_querylets - */ - private static function build_accurate_search_querylet(array $tag_querylets): Querylet { - global $database; + /** + * WARNING: this description is no longer accurate, though it does get across + * the general idea - the actual method has a few extra optimisations + * + * "foo bar -baz user=foo" becomes + * + * SELECT * FROM images WHERE + * images.id IN (SELECT image_id FROM image_tags WHERE tag='foo') + * AND images.id IN (SELECT image_id FROM image_tags WHERE tag='bar') + * AND NOT images.id IN (SELECT image_id FROM image_tags WHERE tag='baz') + * AND images.id IN (SELECT id FROM images WHERE owner_name='foo') + * + * This is: + * A) Incredibly simple: + * Each search term maps to a list of image IDs + * B) Runs really fast on a good database: + * These lists are calculated once, and the set intersection taken + * C) Runs really slow on bad databases: + * All the subqueries are executed every time for every row in the + * images table. Yes, MySQL does suck this much. + * + * #param TagQuerylet[] $tag_querylets + */ + private static function build_accurate_search_querylet(array $tag_querylets): Querylet + { + global $database; - $positive_tag_id_array = array(); - $negative_tag_id_array = array(); + $positive_tag_id_array = []; + $negative_tag_id_array = []; - foreach ($tag_querylets as $tq) { - $tag_ids = $database->get_col( - $database->scoreql_to_sql(" + foreach ($tag_querylets as $tq) { + $tag_ids = $database->get_col( + $database->scoreql_to_sql(" SELECT id FROM tags WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(:tag) "), - array("tag" => $tq->tag) - ); - if ($tq->positive) { - $positive_tag_id_array = array_merge($positive_tag_id_array, $tag_ids); - if (count($tag_ids) == 0) { - # one of the positive tags had zero results, therefor there - # can be no results; "where 1=0" should shortcut things - return new Querylet(" + ["tag" => $tq->tag] + ); + if ($tq->positive) { + $positive_tag_id_array = array_merge($positive_tag_id_array, $tag_ids); + if (count($tag_ids) == 0) { + # one of the positive tags had zero results, therefor there + # can be no results; "where 1=0" should shortcut things + return new Querylet(" SELECT images.* FROM images WHERE 1=0 "); - } - } else { - $negative_tag_id_array = array_merge($negative_tag_id_array, $tag_ids); - } - } + } + } else { + $negative_tag_id_array = array_merge($negative_tag_id_array, $tag_ids); + } + } - assert($positive_tag_id_array || $negative_tag_id_array, @$_GET['q']); - $wheres = array(); - if (!empty($positive_tag_id_array)) { - $positive_tag_id_list = join(', ', $positive_tag_id_array); - $wheres[] = "tag_id IN ($positive_tag_id_list)"; - } - if (!empty($negative_tag_id_array)) { - $negative_tag_id_list = join(', ', $negative_tag_id_array); - $wheres[] = "tag_id NOT IN ($negative_tag_id_list)"; - } - $wheres_str = join(" AND ", $wheres); - return new Querylet(" + assert($positive_tag_id_array || $negative_tag_id_array, @$_GET['q']); + $wheres = []; + if (!empty($positive_tag_id_array)) { + $positive_tag_id_list = join(', ', $positive_tag_id_array); + $wheres[] = "tag_id IN ($positive_tag_id_list)"; + } + if (!empty($negative_tag_id_array)) { + $negative_tag_id_list = join(', ', $negative_tag_id_array); + $wheres[] = "tag_id NOT IN ($negative_tag_id_list)"; + } + $wheres_str = join(" AND ", $wheres); + return new Querylet(" SELECT images.* FROM images WHERE images.id IN ( @@ -887,71 +949,74 @@ class Image { GROUP BY image_id HAVING COUNT(image_id) >= :search_score ) - ", array("search_score"=>count($positive_tag_id_array))); - } + ", ["search_score"=>count($positive_tag_id_array)]); + } - /** - * this function exists because mysql is a turd, see the docs for - * build_accurate_search_querylet() for a full explanation - * - * #param TagQuerylet[] $tag_querylets - */ - private static function build_ugly_search_querylet(array $tag_querylets): Querylet { - global $database; + /** + * this function exists because mysql is a turd, see the docs for + * build_accurate_search_querylet() for a full explanation + * + * #param TagQuerylet[] $tag_querylets + */ + private static function build_ugly_search_querylet(array $tag_querylets): Querylet + { + global $database; - $positive_tag_count = 0; - foreach($tag_querylets as $tq) { - if($tq->positive) $positive_tag_count++; - } + $positive_tag_count = 0; + foreach ($tag_querylets as $tq) { + if ($tq->positive) { + $positive_tag_count++; + } + } - // only negative tags - shortcut to fail - if($positive_tag_count == 0) { - // TODO: This isn't currently implemented. - // SEE: https://github.com/shish/shimmie2/issues/66 - return new Querylet(" + // only negative tags - shortcut to fail + if ($positive_tag_count == 0) { + // TODO: This isn't currently implemented. + // SEE: https://github.com/shish/shimmie2/issues/66 + return new Querylet(" SELECT images.* FROM images WHERE 1=0 "); - } + } - // merge all the tag querylets into one generic one - $sql = "0"; - $terms = array(); - foreach($tag_querylets as $tq) { - $sign = $tq->positive ? "+" : "-"; - $sql .= ' '.$sign.' IF(SUM(tag LIKE :tag'.Image::$tag_n.'), 1, 0)'; - $terms['tag'.Image::$tag_n] = $tq->tag; - Image::$tag_n++; - } - $tag_search = new Querylet($sql, $terms); + // merge all the tag querylets into one generic one + $sql = "0"; + $terms = []; + foreach ($tag_querylets as $tq) { + $sign = $tq->positive ? "+" : "-"; + $sql .= ' '.$sign.' IF(SUM(tag LIKE :tag'.Image::$tag_n.'), 1, 0)'; + $terms['tag'.Image::$tag_n] = $tq->tag; + Image::$tag_n++; + } + $tag_search = new Querylet($sql, $terms); - $tag_id_array = array(); + $tag_id_array = []; - foreach($tag_querylets as $tq) { - $tag_ids = $database->get_col( - $database->scoreql_to_sql(" + foreach ($tag_querylets as $tq) { + $tag_ids = $database->get_col( + $database->scoreql_to_sql(" SELECT id FROM tags WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(:tag) "), - array("tag" => $tq->tag) - ); - $tag_id_array = array_merge($tag_id_array, $tag_ids); + ["tag" => $tq->tag] + ); + $tag_id_array = array_merge($tag_id_array, $tag_ids); - if($tq->positive && count($tag_ids) == 0) { - # one of the positive tags had zero results, therefor there - # can be no results; "where 1=0" should shortcut things - return new Querylet(" + if ($tq->positive && count($tag_ids) == 0) { + # one of the positive tags had zero results, therefor there + # can be no results; "where 1=0" should shortcut things + return new Querylet(" SELECT images.* FROM images WHERE 1=0 "); - } - } + } + } - Image::$tag_n = 0; - return new Querylet(' + Image::$tag_n = 0; + return new Querylet(' SELECT * FROM ( SELECT images.*, ('.$tag_search->sql.') AS score @@ -964,9 +1029,8 @@ class Image { ) AS images WHERE 1=1 ', array_merge( - $tag_search->variables, - array("score"=>$positive_tag_count) - )); - } + $tag_search->variables, + ["score"=>$positive_tag_count] + )); + } } - diff --git a/core/imageboard/misc.php b/core/imageboard/misc.php index 3f7fc599..cde0d981 100644 --- a/core/imageboard/misc.php +++ b/core/imageboard/misc.php @@ -9,15 +9,16 @@ * * @throws UploadException */ -function move_upload_to_archive(DataUploadEvent $event) { - $target = warehouse_path("images", $event->hash); - if(!@copy($event->tmpname, $target)) { - $errors = error_get_last(); - throw new UploadException( - "Failed to copy file from uploads ({$event->tmpname}) to archive ($target): ". - "{$errors['type']} / {$errors['message']}" - ); - } +function move_upload_to_archive(DataUploadEvent $event) +{ + $target = warehouse_path("images", $event->hash); + if (!@copy($event->tmpname, $target)) { + $errors = error_get_last(); + throw new UploadException( + "Failed to copy file from uploads ({$event->tmpname}) to archive ($target): ". + "{$errors['type']} / {$errors['message']}" + ); + } } /** @@ -25,45 +26,46 @@ function move_upload_to_archive(DataUploadEvent $event) { * * #return string[] */ -function add_dir(string $base): array { - $results = array(); +function add_dir(string $base): array +{ + $results = []; - foreach(list_files($base) as $full_path) { - $short_path = str_replace($base, "", $full_path); - $filename = basename($full_path); + foreach (list_files($base) as $full_path) { + $short_path = str_replace($base, "", $full_path); + $filename = basename($full_path); - $tags = path_to_tags($short_path); - $result = "$short_path (".str_replace(" ", ", ", $tags).")... "; - try { - add_image($full_path, $filename, $tags); - $result .= "ok"; - } - catch(UploadException $ex) { - $result .= "failed: ".$ex->getMessage(); - } - $results[] = $result; - } + $tags = path_to_tags($short_path); + $result = "$short_path (".str_replace(" ", ", ", $tags).")... "; + try { + add_image($full_path, $filename, $tags); + $result .= "ok"; + } catch (UploadException $ex) { + $result .= "failed: ".$ex->getMessage(); + } + $results[] = $result; + } - return $results; + return $results; } -function add_image(string $tmpname, string $filename, string $tags): void { - assert(file_exists($tmpname)); +function add_image(string $tmpname, string $filename, string $tags): void +{ + assert(file_exists($tmpname)); - $pathinfo = pathinfo($filename); - if(!array_key_exists('extension', $pathinfo)) { - throw new UploadException("File has no extension"); - } - $metadata = array(); - $metadata['filename'] = $pathinfo['basename']; - $metadata['extension'] = $pathinfo['extension']; - $metadata['tags'] = Tag::explode($tags); - $metadata['source'] = null; - $event = new DataUploadEvent($tmpname, $metadata); - send_event($event); - if($event->image_id == -1) { - throw new UploadException("File type not recognised"); - } + $pathinfo = pathinfo($filename); + if (!array_key_exists('extension', $pathinfo)) { + throw new UploadException("File has no extension"); + } + $metadata = []; + $metadata['filename'] = $pathinfo['basename']; + $metadata['extension'] = $pathinfo['extension']; + $metadata['tags'] = Tag::explode($tags); + $metadata['source'] = null; + $event = new DataUploadEvent($tmpname, $metadata); + send_event($event); + if ($event->image_id == -1) { + throw new UploadException("File type not recognised"); + } } /** @@ -72,26 +74,34 @@ function add_image(string $tmpname, string $filename, string $tags): void { * * #return int[] */ -function get_thumbnail_size(int $orig_width, int $orig_height): array { - global $config; +function get_thumbnail_size(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 === 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; + if ($orig_width > $orig_height * 5) { + $orig_width = $orig_height * 5; + } + if ($orig_height > $orig_width * 5) { + $orig_height = $orig_width * 5; + } - $max_width = $config->get_int('thumb_width'); - $max_height = $config->get_int('thumb_height'); + $max_width = $config->get_int('thumb_width'); + $max_height = $config->get_int('thumb_height'); - $xscale = ($max_height / $orig_height); - $yscale = ($max_width / $orig_width); - $scale = ($xscale < $yscale) ? $xscale : $yscale; + $xscale = ($max_height / $orig_height); + $yscale = ($max_width / $orig_width); + $scale = ($xscale < $yscale) ? $xscale : $yscale; - if($scale > 1 && $config->get_bool('thumb_upscale')) { - return array((int)$orig_width, (int)$orig_height); - } - else { - return array((int)($orig_width*$scale), (int)($orig_height*$scale)); - } + 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)]; + } } diff --git a/core/imageboard/search.php b/core/imageboard/search.php index 8c1e4079..dd1712f7 100644 --- a/core/imageboard/search.php +++ b/core/imageboard/search.php @@ -1,49 +1,58 @@ sql = $sql; - $this->variables = $variables; - } + public function __construct(string $sql, array $variables=[]) + { + $this->sql = $sql; + $this->variables = $variables; + } - public function append(Querylet $querylet) { - $this->sql .= $querylet->sql; - $this->variables = array_merge($this->variables, $querylet->variables); - } + public function append(Querylet $querylet) + { + $this->sql .= $querylet->sql; + $this->variables = array_merge($this->variables, $querylet->variables); + } - public function append_sql(string $sql) { - $this->sql .= $sql; - } + public function append_sql(string $sql) + { + $this->sql .= $sql; + } - public function add_variable($var) { - $this->variables[] = $var; - } + public function add_variable($var) + { + $this->variables[] = $var; + } } -class TagQuerylet { - /** @var string */ - public $tag; - /** @var bool */ - public $positive; +class TagQuerylet +{ + /** @var string */ + public $tag; + /** @var bool */ + public $positive; - public function __construct(string $tag, bool $positive) { - $this->tag = $tag; - $this->positive = $positive; - } + public function __construct(string $tag, bool $positive) + { + $this->tag = $tag; + $this->positive = $positive; + } } -class ImgQuerylet { - /** @var \Querylet */ - public $qlet; - /** @var bool */ - public $positive; +class ImgQuerylet +{ + /** @var \Querylet */ + public $qlet; + /** @var bool */ + public $positive; - public function __construct(Querylet $qlet, bool $positive) { - $this->qlet = $qlet; - $this->positive = $positive; - } + public function __construct(Querylet $qlet, bool $positive) + { + $this->qlet = $qlet; + $this->positive = $positive; + } } diff --git a/core/imageboard/tag.php b/core/imageboard/tag.php index 594c731b..3e32d524 100644 --- a/core/imageboard/tag.php +++ b/core/imageboard/tag.php @@ -7,96 +7,97 @@ * All the methods are static, one should never actually use a tag object. * */ -class Tag { - public static function implode(array $tags): string { - sort($tags); - $tags = implode(' ', $tags); +class Tag +{ + public static function implode(array $tags): string + { + sort($tags); + $tags = implode(' ', $tags); - return $tags; - } + return $tags; + } - /** - * Turn a human-supplied string into a valid tag array. - * - * #return string[] - */ - public static function explode(string $tags, bool $tagme=true): array { - global $database; + /** + * Turn a human-supplied string into a valid tag array. + * + * #return string[] + */ + public static function explode(string $tags, bool $tagme=true): array + { + global $database; - $tags = explode(' ', trim($tags)); + $tags = explode(' ', trim($tags)); - /* sanitise by removing invisible / dodgy characters */ - $tag_array = array(); - foreach($tags as $tag) { - $tag = preg_replace("/\s/", "", $tag); # whitespace - $tag = preg_replace('/\x20(\x0e|\x0f)/', '', $tag); # unicode RTL - $tag = preg_replace("/\.+/", ".", $tag); # strings of dots? - $tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes? - $tag = trim($tag, ", \t\n\r\0\x0B"); + /* sanitise by removing invisible / dodgy characters */ + $tag_array = []; + foreach ($tags as $tag) { + $tag = preg_replace("/\s/", "", $tag); # whitespace + $tag = preg_replace('/\x20(\x0e|\x0f)/', '', $tag); # unicode RTL + $tag = preg_replace("/\.+/", ".", $tag); # strings of dots? + $tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes? + $tag = trim($tag, ", \t\n\r\0\x0B"); - if(mb_strlen($tag, 'UTF-8') > 255){ - flash_message("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n"); - continue; - } + if (mb_strlen($tag, 'UTF-8') > 255) { + flash_message("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n"); + continue; + } - if(!empty($tag)) { - $tag_array[] = $tag; - } - } + if (!empty($tag)) { + $tag_array[] = $tag; + } + } - /* if user supplied a blank string, add "tagme" */ - if(count($tag_array) === 0 && $tagme) { - $tag_array = array("tagme"); - } + /* if user supplied a blank string, add "tagme" */ + if (count($tag_array) === 0 && $tagme) { + $tag_array = ["tagme"]; + } - /* resolve aliases */ - $new = array(); - $i = 0; - $tag_count = count($tag_array); - while($i<$tag_count) { - $tag = $tag_array[$i]; - $negative = ''; - if(!empty($tag) && ($tag[0] == '-')) { - $negative = '-'; - $tag = substr($tag, 1); - } + /* resolve aliases */ + $new = []; + $i = 0; + $tag_count = count($tag_array); + while ($i<$tag_count) { + $tag = $tag_array[$i]; + $negative = ''; + if (!empty($tag) && ($tag[0] == '-')) { + $negative = '-'; + $tag = substr($tag, 1); + } - $newtags = $database->get_one( - $database->scoreql_to_sql(" + $newtags = $database->get_one( + $database->scoreql_to_sql(" SELECT newtag FROM aliases WHERE SCORE_STRNORM(oldtag)=SCORE_STRNORM(:tag) "), - array("tag"=>$tag) - ); - if(empty($newtags)) { - //tag has no alias, use old tag - $aliases = array($tag); - } - else { - $aliases = explode(" ", $newtags); // Tag::explode($newtags); - recursion can be infinite - } + ["tag"=>$tag] + ); + if (empty($newtags)) { + //tag has no alias, use old tag + $aliases = [$tag]; + } else { + $aliases = explode(" ", $newtags); // Tag::explode($newtags); - recursion can be infinite + } - foreach($aliases as $alias) { - if(!in_array($alias, $new)) { - if($tag == $alias) { - $new[] = $negative.$alias; - } - elseif(!in_array($alias, $tag_array)) { - $tag_array[] = $negative.$alias; - $tag_count++; - } - } - } - $i++; - } + foreach ($aliases as $alias) { + if (!in_array($alias, $new)) { + if ($tag == $alias) { + $new[] = $negative.$alias; + } elseif (!in_array($alias, $tag_array)) { + $tag_array[] = $negative.$alias; + $tag_count++; + } + } + } + $i++; + } - /* remove any duplicate tags */ - $tag_array = array_iunique($new); + /* remove any duplicate tags */ + $tag_array = array_iunique($new); - /* tidy up */ - sort($tag_array); + /* tidy up */ + sort($tag_array); - return $tag_array; - } + return $tag_array; + } } diff --git a/core/logging.php b/core/logging.php index 85d60c3e..22a0431d 100644 --- a/core/logging.php +++ b/core/logging.php @@ -17,39 +17,55 @@ define("SCORE_LOG_NOTSET", 0); * When taking action, a log event should be stored by the server * Quite often, both of these happen at once, hence log_*() having $flash */ -function log_msg(string $section, int $priority, string $message, ?string $flash=null, $args=array()) { - send_event(new LogEvent($section, $priority, $message, $args)); - $threshold = defined("CLI_LOG_LEVEL") ? CLI_LOG_LEVEL : 0; +function log_msg(string $section, int $priority, string $message, ?string $flash=null, $args=[]) +{ + send_event(new LogEvent($section, $priority, $message, $args)); + $threshold = defined("CLI_LOG_LEVEL") ? CLI_LOG_LEVEL : 0; - if((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && ($priority >= $threshold)) { - print date("c")." $section: $message\n"; - } - if(!is_null($flash)) { - flash_message($flash); - } + if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && ($priority >= $threshold)) { + print date("c")." $section: $message\n"; + } + if (!is_null($flash)) { + flash_message($flash); + } } // More shorthand ways of logging -function log_debug( string $section, string $message, ?string $flash=null, $args=array()) {log_msg($section, SCORE_LOG_DEBUG, $message, $flash, $args);} -function log_info( string $section, string $message, ?string $flash=null, $args=array()) {log_msg($section, SCORE_LOG_INFO, $message, $flash, $args);} -function log_warning( string $section, string $message, ?string $flash=null, $args=array()) {log_msg($section, SCORE_LOG_WARNING, $message, $flash, $args);} -function log_error( string $section, string $message, ?string $flash=null, $args=array()) {log_msg($section, SCORE_LOG_ERROR, $message, $flash, $args);} -function log_critical(string $section, string $message, ?string $flash=null, $args=array()) {log_msg($section, SCORE_LOG_CRITICAL, $message, $flash, $args);} +function log_debug(string $section, string $message, ?string $flash=null, $args=[]) +{ + log_msg($section, SCORE_LOG_DEBUG, $message, $flash, $args); +} +function log_info(string $section, string $message, ?string $flash=null, $args=[]) +{ + log_msg($section, SCORE_LOG_INFO, $message, $flash, $args); +} +function log_warning(string $section, string $message, ?string $flash=null, $args=[]) +{ + log_msg($section, SCORE_LOG_WARNING, $message, $flash, $args); +} +function log_error(string $section, string $message, ?string $flash=null, $args=[]) +{ + log_msg($section, SCORE_LOG_ERROR, $message, $flash, $args); +} +function log_critical(string $section, string $message, ?string $flash=null, $args=[]) +{ + log_msg($section, SCORE_LOG_CRITICAL, $message, $flash, $args); +} /** * Get a unique ID for this request, useful for grouping log messages. */ -function get_request_id(): string { - static $request_id = null; - if(!$request_id) { - // not completely trustworthy, as a user can spoof this - if(@$_SERVER['HTTP_X_VARNISH']) { - $request_id = $_SERVER['HTTP_X_VARNISH']; - } - else { - $request_id = "P" . uniqid(); - } - } - return $request_id; +function get_request_id(): string +{ + static $request_id = null; + if (!$request_id) { + // not completely trustworthy, as a user can spoof this + if (@$_SERVER['HTTP_X_VARNISH']) { + $request_id = $_SERVER['HTTP_X_VARNISH']; + } else { + $request_id = "P" . uniqid(); + } + } + return $request_id; } diff --git a/core/page.php b/core/page.php index c0f85ed0..6bd67e75 100644 --- a/core/page.php +++ b/core/page.php @@ -35,331 +35,352 @@ * The various extensions all add whatever they want to this structure, * then Layout turns it into HTML. */ -class Page { - /** @name Overall */ - //@{ - /** @var string */ - public $mode = "page"; - /** @var string */ - public $type = "text/html; charset=utf-8"; +class Page +{ + /** @name Overall */ + //@{ + /** @var string */ + public $mode = "page"; + /** @var string */ + public $type = "text/html; charset=utf-8"; - /** - * Set what this page should do; "page", "data", or "redirect". - */ - public function set_mode(string $mode) { - $this->mode = $mode; - } + /** + * Set what this page should do; "page", "data", or "redirect". + */ + public function set_mode(string $mode) + { + $this->mode = $mode; + } - /** - * Set the page's MIME type. - */ - public function set_type(string $type) { - $this->type = $type; - } + /** + * Set the page's MIME type. + */ + public function set_type(string $type) + { + $this->type = $type; + } - //@} - // ============================================== - /** @name "data" mode */ - //@{ + //@} + // ============================================== + /** @name "data" mode */ + //@{ - /** @var string; public only for unit test */ - public $data = ""; + /** @var string; public only for unit test */ + public $data = ""; - /** @var string; public only for unit test */ - public $filename = null; + /** @var string; public only for unit test */ + public $filename = null; - /** - * Set the raw data to be sent. - */ - public function set_data(string $data) { - $this->data = $data; - } + /** + * Set the raw data to be sent. + */ + public function set_data(string $data) + { + $this->data = $data; + } - /** - * Set the recommended download filename. - */ - public function set_filename(string $filename) { - $this->filename = $filename; - } + /** + * Set the recommended download filename. + */ + public function set_filename(string $filename) + { + $this->filename = $filename; + } - //@} - // ============================================== - /** @name "redirect" mode */ - //@{ + //@} + // ============================================== + /** @name "redirect" mode */ + //@{ - /** @var string */ - private $redirect = ""; + /** @var string */ + private $redirect = ""; - /** - * Set the URL to redirect to (remember to use make_link() if linking - * to a page in the same site). - */ - public function set_redirect(string $redirect) { - $this->redirect = $redirect; - } + /** + * Set the URL to redirect to (remember to use make_link() if linking + * to a page in the same site). + */ + public function set_redirect(string $redirect) + { + $this->redirect = $redirect; + } - //@} - // ============================================== - /** @name "page" mode */ - //@{ + //@} + // ============================================== + /** @name "page" mode */ + //@{ - /** @var int */ - public $code = 200; + /** @var int */ + public $code = 200; - /** @var string */ - public $title = ""; + /** @var string */ + public $title = ""; - /** @var string */ - public $heading = ""; + /** @var string */ + public $heading = ""; - /** @var string */ - public $subheading = ""; + /** @var string */ + public $subheading = ""; - /** @var string */ - public $quicknav = ""; + /** @var string */ + public $quicknav = ""; - /** @var string[] */ - public $html_headers = array(); + /** @var string[] */ + public $html_headers = []; - /** @var string[] */ - public $http_headers = array(); + /** @var string[] */ + public $http_headers = []; - /** @var string[][] */ - public $cookies = array(); + /** @var string[][] */ + public $cookies = []; - /** @var Block[] */ - public $blocks = array(); + /** @var Block[] */ + public $blocks = []; - /** - * Set the HTTP status code - */ - public function set_code(int $code): void { - $this->code = $code; - } + /** + * Set the HTTP status code + */ + public function set_code(int $code): void + { + $this->code = $code; + } - public function set_title(string $title): void { - $this->title = $title; - } + public function set_title(string $title): void + { + $this->title = $title; + } - public function set_heading(string $heading): void { - $this->heading = $heading; - } + public function set_heading(string $heading): void + { + $this->heading = $heading; + } - public function set_subheading(string $subheading): void { - $this->subheading = $subheading; - } + public function set_subheading(string $subheading): void + { + $this->subheading = $subheading; + } - /** - * Add a line to the HTML head section. - */ - public function add_html_header(string $line, int $position=50): void { - while(isset($this->html_headers[$position])) $position++; - $this->html_headers[$position] = $line; - } + /** + * Add a line to the HTML head section. + */ + public function add_html_header(string $line, int $position=50): void + { + while (isset($this->html_headers[$position])) { + $position++; + } + $this->html_headers[$position] = $line; + } - /** - * Add a http header to be sent to the client. - */ - public function add_http_header(string $line, int $position=50): void { - while(isset($this->http_headers[$position])) $position++; - $this->http_headers[$position] = $line; - } + /** + * Add a http header to be sent to the client. + */ + public function add_http_header(string $line, int $position=50): void + { + while (isset($this->http_headers[$position])) { + $position++; + } + $this->http_headers[$position] = $line; + } - /** - * The counterpart for get_cookie, this works like php's - * setcookie method, but prepends the site-wide cookie prefix to - * the $name argument before doing anything. - */ - public function add_cookie(string $name, string $value, int $time, string $path): void { - $full_name = COOKIE_PREFIX."_".$name; - $this->cookies[] = array($full_name, $value, $time, $path); - } + /** + * The counterpart for get_cookie, this works like php's + * setcookie method, but prepends the site-wide cookie prefix to + * the $name argument before doing anything. + */ + public function add_cookie(string $name, string $value, int $time, string $path): void + { + $full_name = COOKIE_PREFIX."_".$name; + $this->cookies[] = [$full_name, $value, $time, $path]; + } - public function get_cookie(string $name): ?string { - $full_name = COOKIE_PREFIX."_".$name; - if(isset($_COOKIE[$full_name])) { - return $_COOKIE[$full_name]; - } - else { - return null; - } - } + public function get_cookie(string $name): ?string + { + $full_name = COOKIE_PREFIX."_".$name; + if (isset($_COOKIE[$full_name])) { + return $_COOKIE[$full_name]; + } else { + return null; + } + } - /** - * Get all the HTML headers that are currently set and return as a string. - */ - public function get_all_html_headers(): string { - $data = ''; - ksort($this->html_headers); - foreach ($this->html_headers as $line) { - $data .= "\t\t" . $line . "\n"; - } - return $data; - } + /** + * Get all the HTML headers that are currently set and return as a string. + */ + public function get_all_html_headers(): string + { + $data = ''; + ksort($this->html_headers); + foreach ($this->html_headers as $line) { + $data .= "\t\t" . $line . "\n"; + } + return $data; + } - /** - * Removes all currently set HTML headers (Be careful..). - */ - public function delete_all_html_headers(): void { - $this->html_headers = array(); - } + /** + * Removes all currently set HTML headers (Be careful..). + */ + public function delete_all_html_headers(): void + { + $this->html_headers = []; + } - /** - * Add a Block of data to the page. - */ - public function add_block(Block $block) { - $this->blocks[] = $block; - } + /** + * Add a Block of data to the page. + */ + public function add_block(Block $block) + { + $this->blocks[] = $block; + } - //@} - // ============================================== + //@} + // ============================================== - /** - * Display the page according to the mode and data given. - */ - public function display(): void { - global $page, $user; + /** + * Display the page according to the mode and data given. + */ + public function display(): void + { + global $page, $user; - header("HTTP/1.0 {$this->code} Shimmie"); - header("Content-type: ".$this->type); - header("X-Powered-By: SCore-".SCORE_VERSION); + header("HTTP/1.0 {$this->code} Shimmie"); + header("Content-type: ".$this->type); + header("X-Powered-By: SCore-".SCORE_VERSION); - if (!headers_sent()) { - foreach($this->http_headers as $head) { - header($head); - } - foreach($this->cookies as $c) { - setcookie($c[0], $c[1], $c[2], $c[3]); - } - } else { - print "Error: Headers have already been sent to the client."; - } + if (!headers_sent()) { + foreach ($this->http_headers as $head) { + header($head); + } + foreach ($this->cookies as $c) { + setcookie($c[0], $c[1], $c[2], $c[3]); + } + } else { + print "Error: Headers have already been sent to the client."; + } - switch($this->mode) { - case "page": - if(CACHE_HTTP) { - header("Vary: Cookie, Accept-Encoding"); - if($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") { - header("Cache-control: public, max-age=600"); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 600) . ' GMT'); - } - else { - #header("Cache-control: private, max-age=0"); - header("Cache-control: no-cache"); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() - 600) . ' GMT'); - } - } - #else { - # header("Cache-control: no-cache"); - # header('Expires: ' . gmdate('D, d M Y H:i:s', time() - 600) . ' GMT'); - #} - if($this->get_cookie("flash_message") !== null) { - $this->add_cookie("flash_message", "", -1, "/"); - } - usort($this->blocks, "blockcmp"); - $this->add_auto_html_headers(); - $layout = new Layout(); - $layout->display_page($page); - break; - case "data": - header("Content-Length: ".strlen($this->data)); - if(!is_null($this->filename)) { - header('Content-Disposition: attachment; filename='.$this->filename); - } - print $this->data; - break; - case "redirect": - header('Location: '.$this->redirect); - print 'You should be redirected to '.$this->redirect.''; - break; - default: - print "Invalid page mode"; - break; - } - } + switch ($this->mode) { + case "page": + if (CACHE_HTTP) { + header("Vary: Cookie, Accept-Encoding"); + if ($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") { + header("Cache-control: public, max-age=600"); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 600) . ' GMT'); + } else { + #header("Cache-control: private, max-age=0"); + header("Cache-control: no-cache"); + header('Expires: ' . gmdate('D, d M Y H:i:s', time() - 600) . ' GMT'); + } + } + #else { + # header("Cache-control: no-cache"); + # header('Expires: ' . gmdate('D, d M Y H:i:s', time() - 600) . ' GMT'); + #} + if ($this->get_cookie("flash_message") !== null) { + $this->add_cookie("flash_message", "", -1, "/"); + } + usort($this->blocks, "blockcmp"); + $this->add_auto_html_headers(); + $layout = new Layout(); + $layout->display_page($page); + break; + case "data": + header("Content-Length: ".strlen($this->data)); + if (!is_null($this->filename)) { + header('Content-Disposition: attachment; filename='.$this->filename); + } + print $this->data; + break; + case "redirect": + header('Location: '.$this->redirect); + print 'You should be redirected to '.$this->redirect.''; + break; + default: + print "Invalid page mode"; + break; + } + } - /** - * This function grabs all the CSS and JavaScript files sprinkled throughout Shimmie's folders, - * concatenates them together into two large files (one for CSS and one for JS) and then stores - * them in the /cache/ directory for serving to the user. - * - * Why do this? Two reasons: - * 1. Reduces the number of files the user's browser needs to download. - * 2. Allows these cached files to be compressed/minified by the admin. - * - * TODO: This should really be configurable somehow... - */ - public function add_auto_html_headers(): void { - global $config; + /** + * This function grabs all the CSS and JavaScript files sprinkled throughout Shimmie's folders, + * concatenates them together into two large files (one for CSS and one for JS) and then stores + * them in the /cache/ directory for serving to the user. + * + * Why do this? Two reasons: + * 1. Reduces the number of files the user's browser needs to download. + * 2. Allows these cached files to be compressed/minified by the admin. + * + * TODO: This should really be configurable somehow... + */ + public function add_auto_html_headers(): void + { + global $config; - $data_href = get_base_href(); - $theme_name = $config->get_string('theme', 'default'); + $data_href = get_base_href(); + $theme_name = $config->get_string('theme', 'default'); - $this->add_html_header("", 40); + $this->add_html_header("", 40); - # static handler will map these to themes/foo/static/bar.ico or ext/handle_static/static/bar.ico - $this->add_html_header("", 41); - $this->add_html_header("", 42); + # static handler will map these to themes/foo/static/bar.ico or ext/handle_static/static/bar.ico + $this->add_html_header("", 41); + $this->add_html_header("", 42); - //We use $config_latest to make sure cache is reset if config is ever updated. - $config_latest = 0; - foreach(zglob("data/config/*") as $conf) { - $config_latest = max($config_latest, filemtime($conf)); - } + //We use $config_latest to make sure cache is reset if config is ever updated. + $config_latest = 0; + foreach (zglob("data/config/*") as $conf) { + $config_latest = max($config_latest, filemtime($conf)); + } - /*** Generate CSS cache files ***/ - $css_latest = $config_latest; - $css_files = array_merge( - zglob("ext/{".ENABLED_EXTS."}/style.css"), - zglob("themes/$theme_name/style.css") - ); - foreach($css_files as $css) { - $css_latest = max($css_latest, filemtime($css)); - } - $css_md5 = md5(serialize($css_files)); - $css_cache_file = data_path("cache/style/{$theme_name}.{$css_latest}.{$css_md5}.css"); - if(!file_exists($css_cache_file)) { - $css_data = ""; - foreach($css_files as $file) { - $file_data = file_get_contents($file); - $pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/'; - $replace = 'url("../../../'.dirname($file).'/$1")'; - $file_data = preg_replace($pattern, $replace, $file_data); - $css_data .= $file_data . "\n"; - } - file_put_contents($css_cache_file, $css_data); - } - $this->add_html_header("", 43); + /*** Generate CSS cache files ***/ + $css_latest = $config_latest; + $css_files = array_merge( + zglob("ext/{".ENABLED_EXTS."}/style.css"), + zglob("themes/$theme_name/style.css") + ); + foreach ($css_files as $css) { + $css_latest = max($css_latest, filemtime($css)); + } + $css_md5 = md5(serialize($css_files)); + $css_cache_file = data_path("cache/style/{$theme_name}.{$css_latest}.{$css_md5}.css"); + if (!file_exists($css_cache_file)) { + $css_data = ""; + foreach ($css_files as $file) { + $file_data = file_get_contents($file); + $pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/'; + $replace = 'url("../../../'.dirname($file).'/$1")'; + $file_data = preg_replace($pattern, $replace, $file_data); + $css_data .= $file_data . "\n"; + } + file_put_contents($css_cache_file, $css_data); + } + $this->add_html_header("", 43); - /*** Generate JS cache files ***/ - $js_latest = $config_latest; - $js_files = array_merge( - [ - "vendor/bower-asset/jquery/dist/jquery.min.js", - "vendor/bower-asset/jquery-timeago/jquery.timeago.js", - "vendor/bower-asset/tablesorter/jquery.tablesorter.min.js", - "vendor/bower-asset/js-cookie/src/js.cookie.js", - "ext/handle_static/modernizr-3.3.1.custom.js", - ], - zglob("ext/{".ENABLED_EXTS."}/script.js"), - zglob("themes/$theme_name/script.js") - ); - foreach($js_files as $js) { - $js_latest = max($js_latest, filemtime($js)); - } - $js_md5 = md5(serialize($js_files)); - $js_cache_file = data_path("cache/script/{$theme_name}.{$js_latest}.{$js_md5}.js"); - if(!file_exists($js_cache_file)) { - $js_data = ""; - foreach($js_files as $file) { - $js_data .= file_get_contents($file) . "\n"; - } - file_put_contents($js_cache_file, $js_data); - } - $this->add_html_header("", 44); - } + /*** Generate JS cache files ***/ + $js_latest = $config_latest; + $js_files = array_merge( + [ + "vendor/bower-asset/jquery/dist/jquery.min.js", + "vendor/bower-asset/jquery-timeago/jquery.timeago.js", + "vendor/bower-asset/tablesorter/jquery.tablesorter.min.js", + "vendor/bower-asset/js-cookie/src/js.cookie.js", + "ext/handle_static/modernizr-3.3.1.custom.js", + ], + zglob("ext/{".ENABLED_EXTS."}/script.js"), + zglob("themes/$theme_name/script.js") + ); + foreach ($js_files as $js) { + $js_latest = max($js_latest, filemtime($js)); + } + $js_md5 = md5(serialize($js_files)); + $js_cache_file = data_path("cache/script/{$theme_name}.{$js_latest}.{$js_md5}.js"); + if (!file_exists($js_cache_file)) { + $js_data = ""; + foreach ($js_files as $file) { + $js_data .= file_get_contents($file) . "\n"; + } + file_put_contents($js_cache_file, $js_data); + } + $this->add_html_header("", 44); + } } diff --git a/core/polyfills.php b/core/polyfills.php index 8081a0db..21a27031 100644 --- a/core/polyfills.php +++ b/core/polyfills.php @@ -6,15 +6,16 @@ /** * Remove an item from an array */ -function array_remove(array $array, $to_remove): array { - $array = array_unique($array); - $a2 = array(); - foreach($array as $existing) { - if($existing != $to_remove) { - $a2[] = $existing; - } - } - return $a2; +function array_remove(array $array, $to_remove): array +{ + $array = array_unique($array); + $a2 = []; + foreach ($array as $existing) { + if ($existing != $to_remove) { + $a2[] = $existing; + } + } + return $a2; } /** @@ -22,31 +23,34 @@ function array_remove(array $array, $to_remove): array { * * Also removes duplicate values from the array. */ -function array_add(array $array, $element): array { - // Could we just use array_push() ? - // http://www.php.net/manual/en/function.array-push.php - $array[] = $element; - $array = array_unique($array); - return $array; +function array_add(array $array, $element): array +{ + // Could we just use array_push() ? + // http://www.php.net/manual/en/function.array-push.php + $array[] = $element; + $array = array_unique($array); + return $array; } /** * Return the unique elements of an array, case insensitively */ -function array_iunique(array $array): array { - $ok = array(); - foreach($array as $element) { - $found = false; - foreach($ok as $existing) { - if(strtolower($element) == strtolower($existing)) { - $found = true; break; - } - } - if(!$found) { - $ok[] = $element; - } - } - return $ok; +function array_iunique(array $array): array +{ + $ok = []; + foreach ($array as $element) { + $found = false; + foreach ($ok as $existing) { + if (strtolower($element) == strtolower($existing)) { + $found = true; + break; + } + } + if (!$found) { + $ok[] = $element; + } + } + return $ok; } /** @@ -54,17 +58,18 @@ function array_iunique(array $array): array { * * from http://uk.php.net/network */ -function ip_in_range(string $IP, string $CIDR): bool { - list ($net, $mask) = explode("/", $CIDR); +function ip_in_range(string $IP, string $CIDR): bool +{ + list($net, $mask) = explode("/", $CIDR); - $ip_net = ip2long ($net); - $ip_mask = ~((1 << (32 - $mask)) - 1); + $ip_net = ip2long($net); + $ip_mask = ~((1 << (32 - $mask)) - 1); - $ip_ip = ip2long ($IP); + $ip_ip = ip2long($IP); - $ip_ip_net = $ip_ip & $ip_mask; + $ip_ip_net = $ip_ip & $ip_mask; - return ($ip_ip_net == $ip_net); + return ($ip_ip_net == $ip_net); } /** @@ -73,42 +78,38 @@ function ip_in_range(string $IP, string $CIDR): bool { * from a patch by Christian Walde; only intended for use in the * "extension manager" extension, but it seems to fit better here */ -function deltree(string $f) { - //Because Windows (I know, bad excuse) - if(PHP_OS === 'WINNT') { - $real = realpath($f); - $path = realpath('./').'\\'.str_replace('/', '\\', $f); - if($path != $real) { - rmdir($path); - } - else { - foreach(glob($f.'/*') as $sf) { - if (is_dir($sf) && !is_link($sf)) { - deltree($sf); - } - else { - unlink($sf); - } - } - rmdir($f); - } - } - else { - if (is_link($f)) { - unlink($f); - } - else if(is_dir($f)) { - foreach(glob($f.'/*') as $sf) { - if (is_dir($sf) && !is_link($sf)) { - deltree($sf); - } - else { - unlink($sf); - } - } - rmdir($f); - } - } +function deltree(string $f) +{ + //Because Windows (I know, bad excuse) + if (PHP_OS === 'WINNT') { + $real = realpath($f); + $path = realpath('./').'\\'.str_replace('/', '\\', $f); + if ($path != $real) { + rmdir($path); + } else { + foreach (glob($f.'/*') as $sf) { + if (is_dir($sf) && !is_link($sf)) { + deltree($sf); + } else { + unlink($sf); + } + } + rmdir($f); + } + } else { + if (is_link($f)) { + unlink($f); + } elseif (is_dir($f)) { + foreach (glob($f.'/*') as $sf) { + if (is_dir($sf) && !is_link($sf)) { + deltree($sf); + } else { + unlink($sf); + } + } + rmdir($f); + } + } } /** @@ -116,149 +117,154 @@ function deltree(string $f) { * * from a comment on http://uk.php.net/copy */ -function full_copy(string $source, string $target) { - if(is_dir($source)) { - @mkdir($target); +function full_copy(string $source, string $target) +{ + if (is_dir($source)) { + @mkdir($target); - $d = dir($source); + $d = dir($source); - while(FALSE !== ($entry = $d->read())) { - if($entry == '.' || $entry == '..') { - continue; - } + while (false !== ($entry = $d->read())) { + if ($entry == '.' || $entry == '..') { + continue; + } - $Entry = $source . '/' . $entry; - if(is_dir($Entry)) { - full_copy($Entry, $target . '/' . $entry); - continue; - } - copy($Entry, $target . '/' . $entry); - } - $d->close(); - } - else { - copy($source, $target); - } + $Entry = $source . '/' . $entry; + if (is_dir($Entry)) { + full_copy($Entry, $target . '/' . $entry); + continue; + } + copy($Entry, $target . '/' . $entry); + } + $d->close(); + } else { + copy($source, $target); + } } /** * Return a list of all the regular files in a directory and subdirectories */ -function list_files(string $base, string $_sub_dir=""): array { - assert(is_dir($base)); +function list_files(string $base, string $_sub_dir=""): array +{ + assert(is_dir($base)); - $file_list = array(); + $file_list = []; - $files = array(); - $dir = opendir("$base/$_sub_dir"); - while($f = readdir($dir)) { - $files[] = $f; - } - closedir($dir); - sort($files); + $files = []; + $dir = opendir("$base/$_sub_dir"); + while ($f = readdir($dir)) { + $files[] = $f; + } + closedir($dir); + sort($files); - foreach($files as $filename) { - $full_path = "$base/$_sub_dir/$filename"; + foreach ($files as $filename) { + $full_path = "$base/$_sub_dir/$filename"; - if(is_link($full_path)) { - // ignore - } - else if(is_dir($full_path)) { - if(!($filename == "." || $filename == "..")) { - //subdirectory found - $file_list = array_merge( - $file_list, - list_files($base, "$_sub_dir/$filename") - ); - } - } - else { - $full_path = str_replace("//", "/", $full_path); - $file_list[] = $full_path; - } - } + if (is_link($full_path)) { + // ignore + } elseif (is_dir($full_path)) { + if (!($filename == "." || $filename == "..")) { + //subdirectory found + $file_list = array_merge( + $file_list, + list_files($base, "$_sub_dir/$filename") + ); + } + } else { + $full_path = str_replace("//", "/", $full_path); + $file_list[] = $full_path; + } + } - return $file_list; + return $file_list; } if (!function_exists('http_parse_headers')) { #http://www.php.net/manual/en/function.http-parse-headers.php#112917 - /** - * #return string[] - */ - function http_parse_headers (string $raw_headers): array { - $headers = array(); // $headers = []; + /** + * #return string[] + */ + function http_parse_headers(string $raw_headers): array + { + $headers = []; // $headers = []; - foreach (explode("\n", $raw_headers) as $i => $h) { - $h = explode(':', $h, 2); + foreach (explode("\n", $raw_headers) as $i => $h) { + $h = explode(':', $h, 2); - if (isset($h[1])){ - if(!isset($headers[$h[0]])){ - $headers[$h[0]] = trim($h[1]); - }else if(is_array($headers[$h[0]])){ - $tmp = array_merge($headers[$h[0]],array(trim($h[1]))); - $headers[$h[0]] = $tmp; - }else{ - $tmp = array_merge(array($headers[$h[0]]),array(trim($h[1]))); - $headers[$h[0]] = $tmp; - } - } - } - return $headers; - } + if (isset($h[1])) { + if (!isset($headers[$h[0]])) { + $headers[$h[0]] = trim($h[1]); + } elseif (is_array($headers[$h[0]])) { + $tmp = array_merge($headers[$h[0]], [trim($h[1])]); + $headers[$h[0]] = $tmp; + } else { + $tmp = array_merge([$headers[$h[0]]], [trim($h[1])]); + $headers[$h[0]] = $tmp; + } + } + } + return $headers; + } } /** * HTTP Headers can sometimes be lowercase which will cause issues. * In cases like these, we need to make sure to check for them if the camelcase version does not exist. */ -function findHeader(array $headers, string $name): ?string { - if (!is_array($headers)) { - return null; - } +function findHeader(array $headers, string $name): ?string +{ + if (!is_array($headers)) { + return null; + } - $header = null; + $header = null; - if(array_key_exists($name, $headers)) { - $header = $headers[$name]; - } else { - $headers = array_change_key_case($headers); // convert all to lower case. - $lc_name = strtolower($name); + if (array_key_exists($name, $headers)) { + $header = $headers[$name]; + } else { + $headers = array_change_key_case($headers); // convert all to lower case. + $lc_name = strtolower($name); - if(array_key_exists($lc_name, $headers)) { - $header = $headers[$lc_name]; - } - } + if (array_key_exists($lc_name, $headers)) { + $header = $headers[$lc_name]; + } + } - return $header; + return $header; } if (!function_exists('mb_strlen')) { - // TODO: we should warn the admin that they are missing multibyte support - function mb_strlen($str, $encoding) { - return strlen($str); - } - function mb_internal_encoding($encoding) {} - function mb_strtolower($str) { - return strtolower($str); - } + // TODO: we should warn the admin that they are missing multibyte support + function mb_strlen($str, $encoding) + { + return strlen($str); + } + function mb_internal_encoding($encoding) + { + } + function mb_strtolower($str) + { + return strtolower($str); + } } const MIME_TYPE_MAP = [ - 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', - 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon', - 'swf' => 'application/x-shockwave-flash', 'video/x-flv' => 'flv', - 'svg' => 'image/svg+xml', 'pdf' => 'application/pdf', - 'zip' => 'application/zip', 'gz' => 'application/x-gzip', - 'tar' => 'application/x-tar', 'bz' => 'application/x-bzip', - 'bz2' => 'application/x-bzip2', 'txt' => 'text/plain', - 'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html', - 'css' => 'text/css', 'js' => 'text/javascript', - 'xml' => 'text/xml', 'xsl' => 'application/xsl+xml', - 'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav', - 'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg', - 'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php', - 'mp4' => 'video/mp4', 'ogv' => 'video/ogg', 'webm' => 'video/webm' + 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', + 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon', + 'swf' => 'application/x-shockwave-flash', 'video/x-flv' => 'flv', + 'svg' => 'image/svg+xml', 'pdf' => 'application/pdf', + 'zip' => 'application/zip', 'gz' => 'application/x-gzip', + 'tar' => 'application/x-tar', 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', 'txt' => 'text/plain', + 'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html', + 'css' => 'text/css', 'js' => 'text/javascript', + 'xml' => 'text/xml', 'xsl' => 'application/xsl+xml', + 'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav', + 'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg', + 'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php', + 'mp4' => 'video/mp4', 'ogv' => 'video/ogg', 'webm' => 'video/webm' ]; /** @@ -268,64 +274,72 @@ const MIME_TYPE_MAP = [ * from the "Amazon S3 PHP class" which is Copyright (c) 2008, Donovan Schönknecht * and released under the 'Simplified BSD License'. */ -function getMimeType(string $file, string $ext=""): string { - // Static extension lookup - $ext = strtolower($ext); +function getMimeType(string $file, string $ext=""): string +{ + // Static extension lookup + $ext = strtolower($ext); - if (array_key_exists($ext, MIME_TYPE_MAP)) { return MIME_TYPE_MAP[$ext]; } + if (array_key_exists($ext, MIME_TYPE_MAP)) { + return MIME_TYPE_MAP[$ext]; + } - $type = false; - // Fileinfo documentation says fileinfo_open() will use the - // MAGIC env var for the magic file - if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) && - ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) - { - if (($type = finfo_file($finfo, $file)) !== false) - { - // Remove the charset and grab the last content-type - $type = explode(' ', str_replace('; charset=', ';charset=', $type)); - $type = array_pop($type); - $type = explode(';', $type); - $type = trim(array_shift($type)); - } - finfo_close($finfo); + $type = false; + // Fileinfo documentation says fileinfo_open() will use the + // MAGIC env var for the magic file + if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) && + ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) { + if (($type = finfo_file($finfo, $file)) !== false) { + // Remove the charset and grab the last content-type + $type = explode(' ', str_replace('; charset=', ';charset=', $type)); + $type = array_pop($type); + $type = explode(';', $type); + $type = trim(array_shift($type)); + } + finfo_close($finfo); - // If anyone is still using mime_content_type() - } elseif (function_exists('mime_content_type')) - $type = trim(mime_content_type($file)); + // If anyone is still using mime_content_type() + } elseif (function_exists('mime_content_type')) { + $type = trim(mime_content_type($file)); + } - if ($type !== false && strlen($type) > 0) return $type; + if ($type !== false && strlen($type) > 0) { + return $type; + } - return 'application/octet-stream'; + return 'application/octet-stream'; } -function getExtension(?string $mime_type): ?string { - if(empty($mime_type)){ - return null; - } +function getExtension(?string $mime_type): ?string +{ + if (empty($mime_type)) { + return null; + } - $ext = array_search($mime_type, MIME_TYPE_MAP); - return ($ext ? $ext : null); + $ext = array_search($mime_type, MIME_TYPE_MAP); + return ($ext ? $ext : null); } /** * Like glob, with support for matching very long patterns with braces. */ -function zglob(string $pattern): array { - $results = array(); - if(preg_match('/(.*)\{(.*)\}(.*)/', $pattern, $matches)) { - $braced = explode(",", $matches[2]); - foreach($braced as $b) { - $sub_pattern = $matches[1].$b.$matches[3]; - $results = array_merge($results, zglob($sub_pattern)); - } - return $results; - } - else { - $r = glob($pattern); - if($r) return $r; - else return array(); - } +function zglob(string $pattern): array +{ + $results = []; + if (preg_match('/(.*)\{(.*)\}(.*)/', $pattern, $matches)) { + $braced = explode(",", $matches[2]); + foreach ($braced as $b) { + $sub_pattern = $matches[1].$b.$matches[3]; + $results = array_merge($results, zglob($sub_pattern)); + } + return $results; + } else { + $r = glob($pattern); + if ($r) { + return $r; + } else { + return []; + } + } } /** @@ -336,33 +350,38 @@ function zglob(string $pattern): array { * * PHP really, really sucks. */ -function get_base_href(): string { - if(defined("BASE_HREF")) return BASE_HREF; - $possible_vars = array('SCRIPT_NAME', 'PHP_SELF', 'PATH_INFO', 'ORIG_PATH_INFO'); - $ok_var = null; - foreach($possible_vars as $var) { - if(isset($_SERVER[$var]) && substr($_SERVER[$var], -4) === '.php') { - $ok_var = $_SERVER[$var]; - break; - } - } - assert(!empty($ok_var)); - $dir = dirname($ok_var); - $dir = str_replace("\\", "/", $dir); - $dir = str_replace("//", "/", $dir); - $dir = rtrim($dir, "/"); - return $dir; +function get_base_href(): string +{ + if (defined("BASE_HREF")) { + return BASE_HREF; + } + $possible_vars = ['SCRIPT_NAME', 'PHP_SELF', 'PATH_INFO', 'ORIG_PATH_INFO']; + $ok_var = null; + foreach ($possible_vars as $var) { + if (isset($_SERVER[$var]) && substr($_SERVER[$var], -4) === '.php') { + $ok_var = $_SERVER[$var]; + break; + } + } + assert(!empty($ok_var)); + $dir = dirname($ok_var); + $dir = str_replace("\\", "/", $dir); + $dir = str_replace("//", "/", $dir); + $dir = rtrim($dir, "/"); + return $dir; } -function startsWith(string $haystack, string $needle): bool { - $length = strlen($needle); - return (substr($haystack, 0, $length) === $needle); +function startsWith(string $haystack, string $needle): bool +{ + $length = strlen($needle); + return (substr($haystack, 0, $length) === $needle); } -function endsWith(string $haystack, string $needle): bool { - $length = strlen($needle); - $start = $length * -1; //negative - return (substr($haystack, $start) === $needle); +function endsWith(string $haystack, string $needle): bool +{ + $length = strlen($needle); + $start = $length * -1; //negative + return (substr($haystack, $start) === $needle); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ @@ -372,323 +391,333 @@ function endsWith(string $haystack, string $needle): bool { /** * Make some data safe for printing into HTML */ -function html_escape(string $input): string { - return htmlentities($input, ENT_QUOTES, "UTF-8"); +function html_escape(string $input): string +{ + return htmlentities($input, ENT_QUOTES, "UTF-8"); } /** * Unescape data that was made safe for printing into HTML */ -function html_unescape(string $input): string { - return html_entity_decode($input, ENT_QUOTES, "UTF-8"); +function html_unescape(string $input): string +{ + return html_entity_decode($input, ENT_QUOTES, "UTF-8"); } /** * Make sure some data is safe to be used in integer context */ -function int_escape(string $input): int { - /* - Side note, Casting to an integer is FASTER than using intval. - http://hakre.wordpress.com/2010/05/13/php-casting-vs-intval/ - */ - return (int)$input; +function int_escape(string $input): int +{ + /* + Side note, Casting to an integer is FASTER than using intval. + http://hakre.wordpress.com/2010/05/13/php-casting-vs-intval/ + */ + return (int)$input; } /** * Make sure some data is safe to be used in URL context */ -function url_escape(string $input): string { - /* - Shish: I have a feeling that these three lines are important, possibly for searching for tags with slashes in them like fate/stay_night - green-ponies: indeed~ +function url_escape(string $input): string +{ + /* + Shish: I have a feeling that these three lines are important, possibly for searching for tags with slashes in them like fate/stay_night + green-ponies: indeed~ - $input = str_replace('^', '^^', $input); - $input = str_replace('/', '^s', $input); - $input = str_replace('\\', '^b', $input); + $input = str_replace('^', '^^', $input); + $input = str_replace('/', '^s', $input); + $input = str_replace('\\', '^b', $input); - /* The function idn_to_ascii is used to support Unicode domains / URLs as well. - See here for more: http://php.net/manual/en/function.filter-var.php - However, it is only supported by PHP version 5.3 and up + /* The function idn_to_ascii is used to support Unicode domains / URLs as well. + See here for more: http://php.net/manual/en/function.filter-var.php + However, it is only supported by PHP version 5.3 and up - if (function_exists('idn_to_ascii')) { - return filter_var(idn_to_ascii($input), FILTER_SANITIZE_URL); - } else { - return filter_var($input, FILTER_SANITIZE_URL); - } - */ - if(is_null($input)) { - return ""; - } - $input = str_replace('^', '^^', $input); - $input = str_replace('/', '^s', $input); - $input = str_replace('\\', '^b', $input); - $input = rawurlencode($input); - return $input; + if (function_exists('idn_to_ascii')) { + return filter_var(idn_to_ascii($input), FILTER_SANITIZE_URL); + } else { + return filter_var($input, FILTER_SANITIZE_URL); + } + */ + if (is_null($input)) { + return ""; + } + $input = str_replace('^', '^^', $input); + $input = str_replace('/', '^s', $input); + $input = str_replace('\\', '^b', $input); + $input = rawurlencode($input); + return $input; } /** * Make sure some data is safe to be used in SQL context */ -function sql_escape(string $input): string { - global $database; - return $database->escape($input); +function sql_escape(string $input): string +{ + global $database; + return $database->escape($input); } /** * Turn all manner of HTML / INI / JS / DB booleans into a PHP one */ -function bool_escape($input): bool { - /* - Sometimes, I don't like PHP -- this, is one of those times... - "a boolean FALSE is not considered a valid boolean value by this function." - Yay for Got'chas! - http://php.net/manual/en/filter.filters.validate.php - */ - if (is_bool($input)) { - return $input; - } else if (is_numeric($input)) { - return ($input === 1); - } else { - $value = filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); - if (!is_null($value)) { - return $value; - } else { - $input = strtolower( trim($input) ); - return ( - $input === "y" || - $input === "yes" || - $input === "t" || - $input === "true" || - $input === "on" || - $input === "1" - ); - } - } +function bool_escape($input): bool +{ + /* + Sometimes, I don't like PHP -- this, is one of those times... + "a boolean FALSE is not considered a valid boolean value by this function." + Yay for Got'chas! + http://php.net/manual/en/filter.filters.validate.php + */ + if (is_bool($input)) { + return $input; + } elseif (is_numeric($input)) { + return ($input === 1); + } else { + $value = filter_var($input, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + if (!is_null($value)) { + return $value; + } else { + $input = strtolower(trim($input)); + return ( + $input === "y" || + $input === "yes" || + $input === "t" || + $input === "true" || + $input === "on" || + $input === "1" + ); + } + } } /** * Some functions require a callback function for escaping, * but we might not want to alter the data */ -function no_escape(string $input): string { - return $input; +function no_escape(string $input): string +{ + return $input; } -function clamp(int $val, int $min=null, int $max=null): int { - if(!is_numeric($val) || (!is_null($min) && $val < $min)) { - $val = $min; - } - if(!is_null($max) && $val > $max) { - $val = $max; - } - if(!is_null($min) && !is_null($max)) { - assert($val >= $min && $val <= $max, "$min <= $val <= $max"); - } - return $val; +function clamp(int $val, int $min=null, int $max=null): int +{ + if (!is_numeric($val) || (!is_null($min) && $val < $min)) { + $val = $min; + } + if (!is_null($max) && $val > $max) { + $val = $max; + } + if (!is_null($min) && !is_null($max)) { + assert($val >= $min && $val <= $max, "$min <= $val <= $max"); + } + return $val; } -function xml_tag(string $name, array $attrs=array(), array $children=array()): string { - $xml = "<$name "; - foreach($attrs as $k => $v) { - $xv = str_replace(''', ''', htmlspecialchars($v, ENT_QUOTES)); - $xml .= "$k=\"$xv\" "; - } - if(count($children) > 0) { - $xml .= ">\n"; - foreach($children as $child) { - $xml .= xml_tag($child); - } - $xml .= "$name>\n"; - } - else { - $xml .= "/>\n"; - } - return $xml; +function xml_tag(string $name, array $attrs=[], array $children=[]): string +{ + $xml = "<$name "; + foreach ($attrs as $k => $v) { + $xv = str_replace(''', ''', htmlspecialchars($v, ENT_QUOTES)); + $xml .= "$k=\"$xv\" "; + } + if (count($children) > 0) { + $xml .= ">\n"; + foreach ($children as $child) { + $xml .= xml_tag($child); + } + $xml .= "$name>\n"; + } else { + $xml .= "/>\n"; + } + return $xml; } /** * Original PHP code by Chirp Internet: www.chirp.com.au * Please acknowledge use of this code by including this header. */ -function truncate(string $string, int $limit, string $break=" ", string $pad="..."): string{ - // return with no change if string is shorter than $limit - if(strlen($string) <= $limit) return $string; +function truncate(string $string, int $limit, string $break=" ", string $pad="..."): string +{ + // return with no change if string is shorter than $limit + if (strlen($string) <= $limit) { + return $string; + } - // is $break present between $limit and the end of the string? - if(false !== ($breakpoint = strpos($string, $break, $limit))) { - if($breakpoint < strlen($string) - 1) { - $string = substr($string, 0, $breakpoint) . $pad; - } - } + // is $break present between $limit and the end of the string? + if (false !== ($breakpoint = strpos($string, $break, $limit))) { + if ($breakpoint < strlen($string) - 1) { + $string = substr($string, 0, $breakpoint) . $pad; + } + } - return $string; + return $string; } /** * Turn a human readable filesize into an integer, eg 1KB -> 1024 */ -function parse_shorthand_int(string $limit): int { - if(preg_match('/^([\d\.]+)([gmk])?b?$/i', (string)$limit, $m)) { - $value = $m[1]; - if (isset($m[2])) { - switch(strtolower($m[2])) { - /** @noinspection PhpMissingBreakStatementInspection */ - case 'g': $value *= 1024; // fall through - /** @noinspection PhpMissingBreakStatementInspection */ - case 'm': $value *= 1024; // fall through - /** @noinspection PhpMissingBreakStatementInspection */ - case 'k': $value *= 1024; break; - default: $value = -1; - } - } - return (int)$value; - } else { - return -1; - } +function parse_shorthand_int(string $limit): int +{ + if (preg_match('/^([\d\.]+)([gmk])?b?$/i', (string)$limit, $m)) { + $value = $m[1]; + if (isset($m[2])) { + switch (strtolower($m[2])) { + /** @noinspection PhpMissingBreakStatementInspection */ + case 'g': $value *= 1024; // fall through + /** @noinspection PhpMissingBreakStatementInspection */ + // no break + case 'm': $value *= 1024; // fall through + /** @noinspection PhpMissingBreakStatementInspection */ + // no break + case 'k': $value *= 1024; break; + default: $value = -1; + } + } + return (int)$value; + } else { + return -1; + } } /** * Turn an integer into a human readable filesize, eg 1024 -> 1KB */ -function to_shorthand_int(int $int): string { - assert($int >= 0); +function to_shorthand_int(int $int): string +{ + assert($int >= 0); - if($int >= pow(1024, 3)) { - return sprintf("%.1fGB", $int / pow(1024, 3)); - } - else if($int >= pow(1024, 2)) { - return sprintf("%.1fMB", $int / pow(1024, 2)); - } - else if($int >= 1024) { - return sprintf("%.1fKB", $int / 1024); - } - else { - return (string)$int; - } + if ($int >= pow(1024, 3)) { + return sprintf("%.1fGB", $int / pow(1024, 3)); + } elseif ($int >= pow(1024, 2)) { + return sprintf("%.1fMB", $int / pow(1024, 2)); + } elseif ($int >= 1024) { + return sprintf("%.1fKB", $int / 1024); + } else { + return (string)$int; + } } /** * Turn a date into a time, a date, an "X minutes ago...", etc */ -function autodate(string $date, bool $html=true): string { - $cpu = date('c', strtotime($date)); - $hum = date('F j, Y; H:i', strtotime($date)); - return ($html ? "" : $hum); +function autodate(string $date, bool $html=true): string +{ + $cpu = date('c', strtotime($date)); + $hum = date('F j, Y; H:i', strtotime($date)); + return ($html ? "" : $hum); } /** * Check if a given string is a valid date-time. ( Format: yyyy-mm-dd hh:mm:ss ) */ -function isValidDateTime(string $dateTime): bool { - if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $dateTime, $matches)) { - if (checkdate($matches[2], $matches[3], $matches[1])) { - return true; - } - } +function isValidDateTime(string $dateTime): bool +{ + if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $dateTime, $matches)) { + if (checkdate($matches[2], $matches[3], $matches[1])) { + return true; + } + } - return false; + return false; } /** * Check if a given string is a valid date. ( Format: yyyy-mm-dd ) */ -function isValidDate(string $date): bool { - if (preg_match("/^(\d{4})-(\d{2})-(\d{2})$/", $date, $matches)) { - // checkdate wants (month, day, year) - if (checkdate($matches[2], $matches[3], $matches[1])) { - return true; - } - } +function isValidDate(string $date): bool +{ + if (preg_match("/^(\d{4})-(\d{2})-(\d{2})$/", $date, $matches)) { + // checkdate wants (month, day, year) + if (checkdate($matches[2], $matches[3], $matches[1])) { + return true; + } + } - return false; + return false; } -function validate_input(array $inputs): array { - $outputs = array(); +function validate_input(array $inputs): array +{ + $outputs = []; - foreach($inputs as $key => $validations) { - $flags = explode(',', $validations); + foreach ($inputs as $key => $validations) { + $flags = explode(',', $validations); - if(in_array('bool', $flags) && !isset($_POST[$key])) { - $_POST[$key] = 'off'; - } + if (in_array('bool', $flags) && !isset($_POST[$key])) { + $_POST[$key] = 'off'; + } - if(in_array('optional', $flags)) { - if(!isset($_POST[$key]) || trim($_POST[$key]) == "") { - $outputs[$key] = null; - continue; - } - } - if(!isset($_POST[$key]) || trim($_POST[$key]) == "") { - throw new InvalidInput("Input '$key' not set"); - } + if (in_array('optional', $flags)) { + if (!isset($_POST[$key]) || trim($_POST[$key]) == "") { + $outputs[$key] = null; + continue; + } + } + if (!isset($_POST[$key]) || trim($_POST[$key]) == "") { + throw new InvalidInput("Input '$key' not set"); + } - $value = trim($_POST[$key]); + $value = trim($_POST[$key]); - if(in_array('user_id', $flags)) { - $id = int_escape($value); - if(in_array('exists', $flags)) { - if(is_null(User::by_id($id))) { - throw new InvalidInput("User #$id does not exist"); - } - } - $outputs[$key] = $id; - } - else if(in_array('user_name', $flags)) { - if(strlen($value) < 1) { - throw new InvalidInput("Username must be at least 1 character"); - } - else if(!preg_match('/^[a-zA-Z0-9-_]+$/', $value)) { - throw new InvalidInput( - "Username contains invalid characters. Allowed characters are ". - "letters, numbers, dash, and underscore"); - } - $outputs[$key] = $value; - } - else if(in_array('user_class', $flags)) { - global $_shm_user_classes; - if(!array_key_exists($value, $_shm_user_classes)) { - throw new InvalidInput("Invalid user class: ".html_escape($value)); - } - $outputs[$key] = $value; - } - else if(in_array('email', $flags)) { - $outputs[$key] = trim($value); - } - else if(in_array('password', $flags)) { - $outputs[$key] = $value; - } - else if(in_array('int', $flags)) { - $value = trim($value); - if(empty($value) || !is_numeric($value)) { - throw new InvalidInput("Invalid int: ".html_escape($value)); - } - $outputs[$key] = (int)$value; - } - else if(in_array('bool', $flags)) { - $outputs[$key] = bool_escape($value); - } - else if(in_array('string', $flags)) { - if(in_array('trim', $flags)) { - $value = trim($value); - } - if(in_array('lower', $flags)) { - $value = strtolower($value); - } - if(in_array('not-empty', $flags)) { - throw new InvalidInput("$key must not be blank"); - } - if(in_array('nullify', $flags)) { - if(empty($value)) $value = null; - } - $outputs[$key] = $value; - } - else { - throw new InvalidInput("Unknown validation '$validations'"); - } - } + if (in_array('user_id', $flags)) { + $id = int_escape($value); + if (in_array('exists', $flags)) { + if (is_null(User::by_id($id))) { + throw new InvalidInput("User #$id does not exist"); + } + } + $outputs[$key] = $id; + } elseif (in_array('user_name', $flags)) { + if (strlen($value) < 1) { + throw new InvalidInput("Username must be at least 1 character"); + } elseif (!preg_match('/^[a-zA-Z0-9-_]+$/', $value)) { + throw new InvalidInput( + "Username contains invalid characters. Allowed characters are ". + "letters, numbers, dash, and underscore" + ); + } + $outputs[$key] = $value; + } elseif (in_array('user_class', $flags)) { + global $_shm_user_classes; + if (!array_key_exists($value, $_shm_user_classes)) { + throw new InvalidInput("Invalid user class: ".html_escape($value)); + } + $outputs[$key] = $value; + } elseif (in_array('email', $flags)) { + $outputs[$key] = trim($value); + } elseif (in_array('password', $flags)) { + $outputs[$key] = $value; + } elseif (in_array('int', $flags)) { + $value = trim($value); + if (empty($value) || !is_numeric($value)) { + throw new InvalidInput("Invalid int: ".html_escape($value)); + } + $outputs[$key] = (int)$value; + } elseif (in_array('bool', $flags)) { + $outputs[$key] = bool_escape($value); + } elseif (in_array('string', $flags)) { + if (in_array('trim', $flags)) { + $value = trim($value); + } + if (in_array('lower', $flags)) { + $value = strtolower($value); + } + if (in_array('not-empty', $flags)) { + throw new InvalidInput("$key must not be blank"); + } + if (in_array('nullify', $flags)) { + if (empty($value)) { + $value = null; + } + } + $outputs[$key] = $value; + } else { + throw new InvalidInput("Unknown validation '$validations'"); + } + } - return $outputs; + return $outputs; } diff --git a/core/send_event.php b/core/send_event.php index 55328935..52d6dadf 100644 --- a/core/send_event.php +++ b/core/send_event.php @@ -5,90 +5,94 @@ /** @private */ global $_shm_event_listeners; -$_shm_event_listeners = array(); +$_shm_event_listeners = []; -function _load_event_listeners() { - global $_shm_event_listeners, $_shm_ctx; +function _load_event_listeners() +{ + global $_shm_event_listeners, $_shm_ctx; - $_shm_ctx->log_start("Loading extensions"); + $_shm_ctx->log_start("Loading extensions"); - $cache_path = data_path("cache/shm_event_listeners.php"); - if(COMPILE_ELS && file_exists($cache_path)) { - require_once($cache_path); - } - else { - _set_event_listeners(); + $cache_path = data_path("cache/shm_event_listeners.php"); + if (COMPILE_ELS && file_exists($cache_path)) { + require_once($cache_path); + } else { + _set_event_listeners(); - if(COMPILE_ELS) { - _dump_event_listeners($_shm_event_listeners, $cache_path); - } - } + if (COMPILE_ELS) { + _dump_event_listeners($_shm_event_listeners, $cache_path); + } + } - $_shm_ctx->log_endok(); + $_shm_ctx->log_endok(); } -function _set_event_listeners() { - global $_shm_event_listeners; - $_shm_event_listeners = array(); +function _set_event_listeners() +{ + global $_shm_event_listeners; + $_shm_event_listeners = []; - foreach(get_declared_classes() as $class) { - $rclass = new ReflectionClass($class); - if($rclass->isAbstract()) { - // don't do anything - } - elseif(is_subclass_of($class, "Extension")) { - /** @var Extension $extension */ - $extension = new $class(); + foreach (get_declared_classes() as $class) { + $rclass = new ReflectionClass($class); + if ($rclass->isAbstract()) { + // don't do anything + } elseif (is_subclass_of($class, "Extension")) { + /** @var Extension $extension */ + $extension = new $class(); - // skip extensions which don't support our current database - if(!$extension->is_live()) continue; + // skip extensions which don't support our current database + if (!$extension->is_live()) { + continue; + } - foreach(get_class_methods($extension) as $method) { - if(substr($method, 0, 2) == "on") { - $event = substr($method, 2) . "Event"; - $pos = $extension->get_priority() * 100; - while(isset($_shm_event_listeners[$event][$pos])) { - $pos += 1; - } - $_shm_event_listeners[$event][$pos] = $extension; - } - } - } - } + foreach (get_class_methods($extension) as $method) { + if (substr($method, 0, 2) == "on") { + $event = substr($method, 2) . "Event"; + $pos = $extension->get_priority() * 100; + while (isset($_shm_event_listeners[$event][$pos])) { + $pos += 1; + } + $_shm_event_listeners[$event][$pos] = $extension; + } + } + } + } } -function _dump_event_listeners(array $event_listeners, string $path): void { - $p = "<"."?php\n"; +function _dump_event_listeners(array $event_listeners, string $path): void +{ + $p = "<"."?php\n"; - foreach(get_declared_classes() as $class) { - $rclass = new ReflectionClass($class); - if($rclass->isAbstract()) {} - elseif(is_subclass_of($class, "Extension")) { - $p .= "\$$class = new $class(); "; - } - } + foreach (get_declared_classes() as $class) { + $rclass = new ReflectionClass($class); + if ($rclass->isAbstract()) { + } elseif (is_subclass_of($class, "Extension")) { + $p .= "\$$class = new $class(); "; + } + } - $p .= "\$_shm_event_listeners = array(\n"; - foreach($event_listeners as $event => $listeners) { - $p .= "\t'$event' => array(\n"; - foreach($listeners as $id => $listener) { - $p .= "\t\t$id => \$".get_class($listener).",\n"; - } - $p .= "\t),\n"; - } - $p .= ");\n"; + $p .= "\$_shm_event_listeners = array(\n"; + foreach ($event_listeners as $event => $listeners) { + $p .= "\t'$event' => array(\n"; + foreach ($listeners as $id => $listener) { + $p .= "\t\t$id => \$".get_class($listener).",\n"; + } + $p .= "\t),\n"; + } + $p .= ");\n"; - $p .= "?".">"; - file_put_contents($path, $p); + $p .= "?".">"; + file_put_contents($path, $p); } -function ext_is_live(string $ext_name): bool { - if (class_exists($ext_name)) { - /** @var Extension $ext */ - $ext = new $ext_name(); - return $ext->is_live(); - } - return false; +function ext_is_live(string $ext_name): bool +{ + if (class_exists($ext_name)) { + /** @var Extension $ext */ + $ext = new $ext_name(); + return $ext->is_live(); + } + return false; } @@ -99,26 +103,37 @@ $_shm_event_count = 0; /** * Send an event to all registered Extensions. */ -function send_event(Event $event): void { - global $_shm_event_listeners, $_shm_event_count, $_shm_ctx; - if(!isset($_shm_event_listeners[get_class($event)])) return; - $method_name = "on".str_replace("Event", "", get_class($event)); +function send_event(Event $event): void +{ + global $_shm_event_listeners, $_shm_event_count, $_shm_ctx; + if (!isset($_shm_event_listeners[get_class($event)])) { + return; + } + $method_name = "on".str_replace("Event", "", get_class($event)); - // send_event() is performance sensitive, and with the number - // of times context gets called the time starts to add up - $ctx_enabled = constant('CONTEXT'); + // send_event() is performance sensitive, and with the number + // of times context gets called the time starts to add up + $ctx_enabled = constant('CONTEXT'); - if($ctx_enabled) $_shm_ctx->log_start(get_class($event)); - // SHIT: http://bugs.php.net/bug.php?id=35106 - $my_event_listeners = $_shm_event_listeners[get_class($event)]; - ksort($my_event_listeners); - foreach($my_event_listeners as $listener) { - if($ctx_enabled) $_shm_ctx->log_start(get_class($listener)); - if(method_exists($listener, $method_name)) { - $listener->$method_name($event); - } - if($ctx_enabled) $_shm_ctx->log_endok(); - } - $_shm_event_count++; - if($ctx_enabled) $_shm_ctx->log_endok(); + if ($ctx_enabled) { + $_shm_ctx->log_start(get_class($event)); + } + // SHIT: http://bugs.php.net/bug.php?id=35106 + $my_event_listeners = $_shm_event_listeners[get_class($event)]; + ksort($my_event_listeners); + foreach ($my_event_listeners as $listener) { + if ($ctx_enabled) { + $_shm_ctx->log_start(get_class($listener)); + } + if (method_exists($listener, $method_name)) { + $listener->$method_name($event); + } + if ($ctx_enabled) { + $_shm_ctx->log_endok(); + } + } + $_shm_event_count++; + if ($ctx_enabled) { + $_shm_ctx->log_endok(); + } } diff --git a/core/sys_config.php b/core/sys_config.php index 8c26f2a9..4c6d648e 100644 --- a/core/sys_config.php +++ b/core/sys_config.php @@ -19,7 +19,12 @@ * */ -function _d(string $name, $value) {if(!defined($name)) define($name, $value);} +function _d(string $name, $value) +{ + if (!defined($name)) { + define($name, $value); + } +} _d("DATABASE_DSN", null); // string PDO database connection details _d("DATABASE_KA", true); // string Keep database connection alive _d("CACHE_DSN", null); // string cache connection details @@ -50,5 +55,3 @@ _d("ENABLED_MODS", "imageboard"); */ _d("SCORE_VERSION", 'develop/'.VERSION); // string SCore version _d("ENABLED_EXTS", CORE_EXTS.",".EXTRA_EXTS); - - diff --git a/core/tests/polyfills.test.php b/core/tests/polyfills.test.php index c1797092..7aadec3d 100644 --- a/core/tests/polyfills.test.php +++ b/core/tests/polyfills.test.php @@ -1,43 +1,48 @@ assertEquals( - html_escape("Foo &"), - "Foo & <waffles>" - ); +class PolyfillsTest extends \PHPUnit\Framework\TestCase +{ + public function test_html_escape() + { + $this->assertEquals( + html_escape("Foo & "), + "Foo & <waffles>" + ); - $this->assertEquals( - html_unescape("Foo & <waffles>"), - "Foo & " - ); + $this->assertEquals( + html_unescape("Foo & <waffles>"), + "Foo & " + ); - $x = "Foo & <waffles>"; - $this->assertEquals(html_escape(html_unescape($x)), $x); - } + $x = "Foo & <waffles>"; + $this->assertEquals(html_escape(html_unescape($x)), $x); + } - public function test_int_escape() { - $this->assertEquals(int_escape(""), 0); - $this->assertEquals(int_escape("1"), 1); - $this->assertEquals(int_escape("-1"), -1); - $this->assertEquals(int_escape("-1.5"), -1); - } + public function test_int_escape() + { + $this->assertEquals(int_escape(""), 0); + $this->assertEquals(int_escape("1"), 1); + $this->assertEquals(int_escape("-1"), -1); + $this->assertEquals(int_escape("-1.5"), -1); + } - public function test_clamp() { - $this->assertEquals(clamp(0, 5, 10), 5); - $this->assertEquals(clamp(5, 5, 10), 5); - $this->assertEquals(clamp(7, 5, 10), 7); - $this->assertEquals(clamp(10, 5, 10), 10); - $this->assertEquals(clamp(15, 5, 10), 10); - } + public function test_clamp() + { + $this->assertEquals(clamp(0, 5, 10), 5); + $this->assertEquals(clamp(5, 5, 10), 5); + $this->assertEquals(clamp(7, 5, 10), 7); + $this->assertEquals(clamp(10, 5, 10), 10); + $this->assertEquals(clamp(15, 5, 10), 10); + } - public function test_shorthand_int() { - $this->assertEquals(to_shorthand_int(1231231231), "1.1GB"); + public function test_shorthand_int() + { + $this->assertEquals(to_shorthand_int(1231231231), "1.1GB"); - $this->assertEquals(parse_shorthand_int("foo"), -1); - $this->assertEquals(parse_shorthand_int("32M"), 33554432); - $this->assertEquals(parse_shorthand_int("43.4KB"), 44441); - $this->assertEquals(parse_shorthand_int("1231231231"), 1231231231); - } + $this->assertEquals(parse_shorthand_int("foo"), -1); + $this->assertEquals(parse_shorthand_int("32M"), 33554432); + $this->assertEquals(parse_shorthand_int("43.4KB"), 44441); + $this->assertEquals(parse_shorthand_int("1231231231"), 1231231231); + } } diff --git a/core/urls.php b/core/urls.php index 7185e839..e4fc0977 100644 --- a/core/urls.php +++ b/core/urls.php @@ -9,92 +9,94 @@ * * eg make_link("post/list") becomes "/v2/index.php?q=post/list" */ -function make_link(?string $page=null, ?string $query=null): string { - global $config; +function make_link(?string $page=null, ?string $query=null): string +{ + global $config; - if(is_null($page)) $page = $config->get_string('main_page'); + if (is_null($page)) { + $page = $config->get_string('main_page'); + } - if(!is_null(BASE_URL)) { - $base = BASE_URL; - } - elseif(NICE_URLS || $config->get_bool('nice_urls', false)) { - $base = str_replace('/'.basename($_SERVER["SCRIPT_FILENAME"]), "", $_SERVER["PHP_SELF"]); - } - else { - $base = "./".basename($_SERVER["SCRIPT_FILENAME"])."?q="; - } + if (!is_null(BASE_URL)) { + $base = BASE_URL; + } elseif (NICE_URLS || $config->get_bool('nice_urls', false)) { + $base = str_replace('/'.basename($_SERVER["SCRIPT_FILENAME"]), "", $_SERVER["PHP_SELF"]); + } else { + $base = "./".basename($_SERVER["SCRIPT_FILENAME"])."?q="; + } - if(is_null($query)) { - return str_replace("//", "/", $base.'/'.$page ); - } - else { - if(strpos($base, "?")) { - return $base .'/'. $page .'&'. $query; - } - else if(strpos($query, "#") === 0) { - return $base .'/'. $page . $query; - } - else { - return $base .'/'. $page .'?'. $query; - } - } + if (is_null($query)) { + return str_replace("//", "/", $base.'/'.$page); + } else { + if (strpos($base, "?")) { + return $base .'/'. $page .'&'. $query; + } elseif (strpos($query, "#") === 0) { + return $base .'/'. $page . $query; + } else { + return $base .'/'. $page .'?'. $query; + } + } } /** * Take the current URL and modify some parameters */ -function modify_current_url(array $changes): string { - return modify_url($_SERVER['QUERY_STRING'], $changes); +function modify_current_url(array $changes): string +{ + return modify_url($_SERVER['QUERY_STRING'], $changes); } -function modify_url(string $url, array $changes): string { - // SHIT: PHP is officially the worst web API ever because it does not - // have a built-in function to do this. +function modify_url(string $url, array $changes): string +{ + // SHIT: PHP is officially the worst web API ever because it does not + // have a built-in function to do this. - // SHIT: parse_str is magically retarded; not only is it a useless name, it also - // didn't return the parsed array, preferring to overwrite global variables with - // whatever data the user supplied. Thankfully, 4.0.3 added an extra option to - // give it an array to use... - $params = array(); - parse_str($url, $params); + // SHIT: parse_str is magically retarded; not only is it a useless name, it also + // didn't return the parsed array, preferring to overwrite global variables with + // whatever data the user supplied. Thankfully, 4.0.3 added an extra option to + // give it an array to use... + $params = []; + parse_str($url, $params); - if(isset($changes['q'])) { - $base = $changes['q']; - unset($changes['q']); - } - else { - $base = _get_query(); - } + if (isset($changes['q'])) { + $base = $changes['q']; + unset($changes['q']); + } else { + $base = _get_query(); + } - if(isset($params['q'])) { - unset($params['q']); - } + if (isset($params['q'])) { + unset($params['q']); + } - foreach($changes as $k => $v) { - if(is_null($v) and isset($params[$k])) unset($params[$k]); - $params[$k] = $v; - } + foreach ($changes as $k => $v) { + if (is_null($v) and isset($params[$k])) { + unset($params[$k]); + } + $params[$k] = $v; + } - return make_link($base, http_build_query($params)); + return make_link($base, http_build_query($params)); } /** * Turn a relative link into an absolute one, including hostname */ -function make_http(string $link): string { - if(strpos($link, "://") > 0) { - return $link; - } +function make_http(string $link): string +{ + if (strpos($link, "://") > 0) { + return $link; + } - if(strlen($link) > 0 && $link[0] != '/') { - $link = get_base_href() . '/' . $link; - } + if (strlen($link) > 0 && $link[0] != '/') { + $link = get_base_href() . '/' . $link; + } - $protocol = is_https_enabled() ? "https://" : "http://"; - $link = $protocol . $_SERVER["HTTP_HOST"] . $link; - $link = str_replace("/./", "/", $link); + $protocol = is_https_enabled() ? "https://" : "http://"; + $link = $protocol . $_SERVER["HTTP_HOST"] . $link; + $link = str_replace("/./", "/", $link); - return $link; + return $link; } diff --git a/core/user.php b/core/user.php index 68676738..ae3a0a5f 100644 --- a/core/user.php +++ b/core/user.php @@ -1,7 +1,8 @@ id = int_escape($row['id']); - $this->name = $row['name']; - $this->email = $row['email']; - $this->join_date = $row['joindate']; - $this->passhash = $row['pass']; + $this->id = int_escape($row['id']); + $this->name = $row['name']; + $this->email = $row['email']; + $this->join_date = $row['joindate']; + $this->passhash = $row['pass']; - if(array_key_exists($row["class"], $_shm_user_classes)) { - $this->class = $_shm_user_classes[$row["class"]]; - } - else { - throw new SCoreException("User '{$this->name}' has invalid class '{$row["class"]}'"); - } - } + if (array_key_exists($row["class"], $_shm_user_classes)) { + $this->class = $_shm_user_classes[$row["class"]]; + } else { + throw new SCoreException("User '{$this->name}' has invalid class '{$row["class"]}'"); + } + } - public static function by_session(string $name, string $session) { - global $config, $database; - $row = $database->cache->get("user-session:$name-$session"); - if(!$row) { - if($database->get_driver_name() === "mysql") { - $query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess"; - } - else { - $query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess"; - } - $row = $database->get_row($query, array("name"=>$name, "ip"=>get_session_ip($config), "sess"=>$session)); - $database->cache->set("user-session:$name-$session", $row, 600); - } - return is_null($row) ? null : new User($row); - } + public static function by_session(string $name, string $session) + { + global $config, $database; + $row = $database->cache->get("user-session:$name-$session"); + if (!$row) { + if ($database->get_driver_name() === "mysql") { + $query = "SELECT * FROM users WHERE name = :name AND md5(concat(pass, :ip)) = :sess"; + } else { + $query = "SELECT * FROM users WHERE name = :name AND md5(pass || :ip) = :sess"; + } + $row = $database->get_row($query, ["name"=>$name, "ip"=>get_session_ip($config), "sess"=>$session]); + $database->cache->set("user-session:$name-$session", $row, 600); + } + return is_null($row) ? null : new User($row); + } - public static function by_id(int $id) { - global $database; - if($id === 1) { - $cached = $database->cache->get('user-id:'.$id); - if($cached) return new User($cached); - } - $row = $database->get_row("SELECT * FROM users WHERE id = :id", array("id"=>$id)); - if($id === 1) $database->cache->set('user-id:'.$id, $row, 600); - return is_null($row) ? null : new User($row); - } + public static function by_id(int $id) + { + global $database; + if ($id === 1) { + $cached = $database->cache->get('user-id:'.$id); + if ($cached) { + return new User($cached); + } + } + $row = $database->get_row("SELECT * FROM users WHERE id = :id", ["id"=>$id]); + if ($id === 1) { + $database->cache->set('user-id:'.$id, $row, 600); + } + return is_null($row) ? null : new User($row); + } - public static function by_name(string $name) { - global $database; - $row = $database->get_row($database->scoreql_to_sql("SELECT * FROM users WHERE SCORE_STRNORM(name) = SCORE_STRNORM(:name)"), array("name"=>$name)); - return is_null($row) ? null : new User($row); - } + public static function by_name(string $name) + { + global $database; + $row = $database->get_row($database->scoreql_to_sql("SELECT * FROM users WHERE SCORE_STRNORM(name) = SCORE_STRNORM(:name)"), ["name"=>$name]); + return is_null($row) ? null : new User($row); + } - public static function by_name_and_pass(string $name, string $pass) { - $user = User::by_name($name); - if($user) { - if($user->passhash == md5(strtolower($name) . $pass)) { - log_info("core-user", "Migrating from md5 to bcrypt for ".html_escape($name)); - $user->set_password($pass); - } - if(password_verify($pass, $user->passhash)) { - log_info("core-user", "Logged in as ".html_escape($name)." ({$user->class->name})"); - return $user; - } - else { - log_warning("core-user", "Failed to log in as ".html_escape($name)." (Invalid password)"); - } - } - else { - log_warning("core-user", "Failed to log in as ".html_escape($name)." (Invalid username)"); - } - return null; - } + public static function by_name_and_pass(string $name, string $pass) + { + $user = User::by_name($name); + if ($user) { + if ($user->passhash == md5(strtolower($name) . $pass)) { + log_info("core-user", "Migrating from md5 to bcrypt for ".html_escape($name)); + $user->set_password($pass); + } + if (password_verify($pass, $user->passhash)) { + log_info("core-user", "Logged in as ".html_escape($name)." ({$user->class->name})"); + return $user; + } else { + log_warning("core-user", "Failed to log in as ".html_escape($name)." (Invalid password)"); + } + } else { + log_warning("core-user", "Failed to log in as ".html_escape($name)." (Invalid username)"); + } + return null; + } - /* useful user object functions start here */ + /* useful user object functions start here */ - public function can(string $ability): bool { - return $this->class->can($ability); - } + public function can(string $ability): bool + { + return $this->class->can($ability); + } - public function is_anonymous(): bool { - global $config; - return ($this->id === $config->get_int('anon_id')); - } + public function is_anonymous(): bool + { + global $config; + return ($this->id === $config->get_int('anon_id')); + } - public function is_logged_in(): bool { - global $config; - return ($this->id !== $config->get_int('anon_id')); - } + public function is_logged_in(): bool + { + global $config; + return ($this->id !== $config->get_int('anon_id')); + } - public function is_admin(): bool { - return ($this->class->name === "admin"); - } + public function is_admin(): bool + { + return ($this->class->name === "admin"); + } - public function set_class(string $class) { - global $database; - $database->Execute("UPDATE users SET class=:class WHERE id=:id", array("class"=>$class, "id"=>$this->id)); - log_info("core-user", 'Set class for '.$this->name.' to '.$class); - } + public function set_class(string $class) + { + global $database; + $database->Execute("UPDATE users SET class=:class WHERE id=:id", ["class"=>$class, "id"=>$this->id]); + log_info("core-user", 'Set class for '.$this->name.' to '.$class); + } - public function set_name(string $name) { - global $database; - if(User::by_name($name)) { - throw new Exception("Desired username is already in use"); - } - $old_name = $this->name; - $this->name = $name; - $database->Execute("UPDATE users SET name=:name WHERE id=:id", array("name"=>$this->name, "id"=>$this->id)); - log_info("core-user", "Changed username for {$old_name} to {$this->name}"); - } + public function set_name(string $name) + { + global $database; + if (User::by_name($name)) { + throw new Exception("Desired username is already in use"); + } + $old_name = $this->name; + $this->name = $name; + $database->Execute("UPDATE users SET name=:name WHERE id=:id", ["name"=>$this->name, "id"=>$this->id]); + log_info("core-user", "Changed username for {$old_name} to {$this->name}"); + } - public function set_password(string $password) { - global $database; - $hash = password_hash($password, PASSWORD_BCRYPT); - if(is_string($hash)) { - $this->passhash = $hash; - $database->Execute("UPDATE users SET pass=:hash WHERE id=:id", array("hash"=>$this->passhash, "id"=>$this->id)); - log_info("core-user", 'Set password for '.$this->name); - } - else { - throw new SCoreException("Failed to hash password"); - } - } + public function set_password(string $password) + { + global $database; + $hash = password_hash($password, PASSWORD_BCRYPT); + if (is_string($hash)) { + $this->passhash = $hash; + $database->Execute("UPDATE users SET pass=:hash WHERE id=:id", ["hash"=>$this->passhash, "id"=>$this->id]); + log_info("core-user", 'Set password for '.$this->name); + } else { + throw new SCoreException("Failed to hash password"); + } + } - public function set_email(string $address) { - global $database; - $database->Execute("UPDATE users SET email=:email WHERE id=:id", array("email"=>$address, "id"=>$this->id)); - log_info("core-user", 'Set email for '.$this->name); - } + public function set_email(string $address) + { + global $database; + $database->Execute("UPDATE users SET email=:email WHERE id=:id", ["email"=>$address, "id"=>$this->id]); + log_info("core-user", 'Set email for '.$this->name); + } - /** - * Get a snippet of HTML which will render the user's avatar, be that - * a local file, a remote file, a gravatar, a something else, etc. - */ - public function get_avatar_html(): string { - // FIXME: configurable - global $config; - if($config->get_string("avatar_host") === "gravatar") { - if(!empty($this->email)) { - $hash = md5(strtolower($this->email)); - $s = $config->get_string("avatar_gravatar_size"); - $d = urlencode($config->get_string("avatar_gravatar_default")); - $r = $config->get_string("avatar_gravatar_rating"); - $cb = date("Y-m-d"); - return ""; - } - } - return ""; - } + /** + * Get a snippet of HTML which will render the user's avatar, be that + * a local file, a remote file, a gravatar, a something else, etc. + */ + public function get_avatar_html(): string + { + // FIXME: configurable + global $config; + if ($config->get_string("avatar_host") === "gravatar") { + if (!empty($this->email)) { + $hash = md5(strtolower($this->email)); + $s = $config->get_string("avatar_gravatar_size"); + $d = urlencode($config->get_string("avatar_gravatar_default")); + $r = $config->get_string("avatar_gravatar_rating"); + $cb = date("Y-m-d"); + return ""; + } + } + return ""; + } - /** - * Get an auth token to be used in POST forms - * - * password = secret, avoid storing directly - * passhash = bcrypt(password), so someone who gets to the database can't get passwords - * sesskey = md5(passhash . IP), so if it gets sniffed it can't be used from another IP, - * and it can't be used to get the passhash to generate new sesskeys - * authtok = md5(sesskey, salt), presented to the user in web forms, to make sure that - * the form was generated within the session. Salted and re-hashed so that - * reading a web page from the user's cache doesn't give access to the session key - */ - public function get_auth_token(): string { - global $config; - $salt = DATABASE_DSN; - $addr = get_session_ip($config); - return md5(md5($this->passhash . $addr) . "salty-csrf-" . $salt); - } + /** + * Get an auth token to be used in POST forms + * + * password = secret, avoid storing directly + * passhash = bcrypt(password), so someone who gets to the database can't get passwords + * sesskey = md5(passhash . IP), so if it gets sniffed it can't be used from another IP, + * and it can't be used to get the passhash to generate new sesskeys + * authtok = md5(sesskey, salt), presented to the user in web forms, to make sure that + * the form was generated within the session. Salted and re-hashed so that + * reading a web page from the user's cache doesn't give access to the session key + */ + public function get_auth_token(): string + { + global $config; + $salt = DATABASE_DSN; + $addr = get_session_ip($config); + return md5(md5($this->passhash . $addr) . "salty-csrf-" . $salt); + } - public function get_auth_html(): string { - $at = $this->get_auth_token(); - return ''; - } + public function get_auth_html(): string + { + $at = $this->get_auth_token(); + return ''; + } - public function check_auth_token(): bool { - return (isset($_POST["auth_token"]) && $_POST["auth_token"] == $this->get_auth_token()); - } + public function check_auth_token(): bool + { + return (isset($_POST["auth_token"]) && $_POST["auth_token"] == $this->get_auth_token()); + } } diff --git a/core/userclass.php b/core/userclass.php index 86af3b79..862b4194 100644 --- a/core/userclass.php +++ b/core/userclass.php @@ -3,191 +3,191 @@ * @global UserClass[] $_shm_user_classes */ global $_shm_user_classes; -$_shm_user_classes = array(); +$_shm_user_classes = []; /** * Class UserClass */ -class UserClass { +class UserClass +{ - /** - * @var null|string - */ - public $name = null; + /** + * @var null|string + */ + public $name = null; - /** - * @var \UserClass|null - */ - public $parent = null; + /** + * @var \UserClass|null + */ + public $parent = null; - /** - * @var array - */ - public $abilities = array(); + /** + * @var array + */ + public $abilities = []; - public function __construct(string $name, string $parent=null, array $abilities=array()) { - global $_shm_user_classes; + public function __construct(string $name, string $parent=null, array $abilities=[]) + { + global $_shm_user_classes; - $this->name = $name; - $this->abilities = $abilities; + $this->name = $name; + $this->abilities = $abilities; - if(!is_null($parent)) { - $this->parent = $_shm_user_classes[$parent]; - } + if (!is_null($parent)) { + $this->parent = $_shm_user_classes[$parent]; + } - $_shm_user_classes[$name] = $this; - } + $_shm_user_classes[$name] = $this; + } - /** - * Determine if this class of user can perform an action or has ability. - * - * @throws SCoreException - */ - public function can(string $ability): bool { - if(array_key_exists($ability, $this->abilities)) { - $val = $this->abilities[$ability]; - return $val; - } - else if(!is_null($this->parent)) { - return $this->parent->can($ability); - } - else { - global $_shm_user_classes; - $min_dist = 9999; - $min_ability = null; - foreach($_shm_user_classes['base']->abilities as $a => $cando) { - $v = levenshtein($ability, $a); - if($v < $min_dist) { - $min_dist = $v; - $min_ability = $a; - } - } - throw new SCoreException("Unknown ability '".html_escape($ability)."'. Did the developer mean '".html_escape($min_ability)."'?"); - } - } + /** + * Determine if this class of user can perform an action or has ability. + * + * @throws SCoreException + */ + public function can(string $ability): bool + { + if (array_key_exists($ability, $this->abilities)) { + $val = $this->abilities[$ability]; + return $val; + } elseif (!is_null($this->parent)) { + return $this->parent->can($ability); + } else { + global $_shm_user_classes; + $min_dist = 9999; + $min_ability = null; + foreach ($_shm_user_classes['base']->abilities as $a => $cando) { + $v = levenshtein($ability, $a); + if ($v < $min_dist) { + $min_dist = $v; + $min_ability = $a; + } + } + throw new SCoreException("Unknown ability '".html_escape($ability)."'. Did the developer mean '".html_escape($min_ability)."'?"); + } + } } // action_object_attribute // action = create / view / edit / delete // object = image / user / tag / setting -new UserClass("base", null, array( - "change_setting" => False, # modify web-level settings, eg the config table - "override_config" => False, # modify sys-level settings, eg shimmie.conf.php - "big_search" => False, # search for more than 3 tags at once (speed mode only) +new UserClass("base", null, [ + "change_setting" => false, # modify web-level settings, eg the config table + "override_config" => false, # modify sys-level settings, eg shimmie.conf.php + "big_search" => false, # search for more than 3 tags at once (speed mode only) - "manage_extension_list" => False, - "manage_alias_list" => False, - "mass_tag_edit" => False, + "manage_extension_list" => false, + "manage_alias_list" => false, + "mass_tag_edit" => false, - "view_ip" => False, # view IP addresses associated with things - "ban_ip" => False, + "view_ip" => false, # view IP addresses associated with things + "ban_ip" => false, - "edit_user_name" => False, - "edit_user_password" => False, - "edit_user_info" => False, # email address, etc - "edit_user_class" => False, - "delete_user" => False, + "edit_user_name" => false, + "edit_user_password" => false, + "edit_user_info" => false, # email address, etc + "edit_user_class" => false, + "delete_user" => false, - "create_comment" => False, - "delete_comment" => False, - "bypass_comment_checks" => False, # spam etc + "create_comment" => false, + "delete_comment" => false, + "bypass_comment_checks" => false, # spam etc - "replace_image" => False, - "create_image" => False, - "edit_image_tag" => False, - "edit_image_source" => False, - "edit_image_owner" => False, - "edit_image_lock" => False, - "bulk_edit_image_tag" => False, - "bulk_edit_image_source" => False, - "delete_image" => False, + "replace_image" => false, + "create_image" => false, + "edit_image_tag" => false, + "edit_image_source" => false, + "edit_image_owner" => false, + "edit_image_lock" => false, + "bulk_edit_image_tag" => false, + "bulk_edit_image_source" => false, + "delete_image" => false, - "ban_image" => False, + "ban_image" => false, - "view_eventlog" => False, - "ignore_downtime" => False, + "view_eventlog" => false, + "ignore_downtime" => false, - "create_image_report" => False, - "view_image_report" => False, # deal with reported images + "create_image_report" => false, + "view_image_report" => false, # deal with reported images - "edit_wiki_page" => False, - "delete_wiki_page" => False, + "edit_wiki_page" => false, + "delete_wiki_page" => false, - "manage_blocks" => False, + "manage_blocks" => false, - "manage_admintools" => False, + "manage_admintools" => false, - "view_other_pms" => False, - "edit_feature" => False, - "bulk_edit_vote" => False, - "edit_other_vote" => False, - "view_sysinfo" => False, + "view_other_pms" => false, + "edit_feature" => false, + "bulk_edit_vote" => false, + "edit_other_vote" => false, + "view_sysinfo" => false, - "hellbanned" => False, - "view_hellbanned" => False, + "hellbanned" => false, + "view_hellbanned" => false, - "protected" => False, # only admins can modify protected users (stops a moderator changing an admin's password) -)); + "protected" => false, # only admins can modify protected users (stops a moderator changing an admin's password) +]); -new UserClass("anonymous", "base", array( -)); +new UserClass("anonymous", "base", [ +]); -new UserClass("user", "base", array( - "big_search" => True, - "create_image" => True, - "create_comment" => True, - "edit_image_tag" => True, - "edit_image_source" => True, - "create_image_report" => True, -)); +new UserClass("user", "base", [ + "big_search" => true, + "create_image" => true, + "create_comment" => true, + "edit_image_tag" => true, + "edit_image_source" => true, + "create_image_report" => true, +]); -new UserClass("admin", "base", array( - "change_setting" => True, - "override_config" => True, - "big_search" => True, - "edit_image_lock" => True, - "view_ip" => True, - "ban_ip" => True, - "edit_user_name" => True, - "edit_user_password" => True, - "edit_user_info" => True, - "edit_user_class" => True, - "delete_user" => True, - "create_image" => True, - "delete_image" => True, - "ban_image" => True, - "create_comment" => True, - "delete_comment" => True, - "bypass_comment_checks" => True, - "replace_image" => True, - "manage_extension_list" => True, - "manage_alias_list" => True, - "edit_image_tag" => True, - "edit_image_source" => True, - "edit_image_owner" => True, - "bulk_edit_image_tag" => True, - "bulk_edit_image_source" => True, - "mass_tag_edit" => True, - "create_image_report" => True, - "view_image_report" => True, - "edit_wiki_page" => True, - "delete_wiki_page" => True, - "view_eventlog" => True, - "manage_blocks" => True, - "manage_admintools" => True, - "ignore_downtime" => True, - "view_other_pms" => True, - "edit_feature" => True, - "bulk_edit_vote" => True, - "edit_other_vote" => True, - "view_sysinfo" => True, - "view_hellbanned" => True, - "protected" => True, -)); +new UserClass("admin", "base", [ + "change_setting" => true, + "override_config" => true, + "big_search" => true, + "edit_image_lock" => true, + "view_ip" => true, + "ban_ip" => true, + "edit_user_name" => true, + "edit_user_password" => true, + "edit_user_info" => true, + "edit_user_class" => true, + "delete_user" => true, + "create_image" => true, + "delete_image" => true, + "ban_image" => true, + "create_comment" => true, + "delete_comment" => true, + "bypass_comment_checks" => true, + "replace_image" => true, + "manage_extension_list" => true, + "manage_alias_list" => true, + "edit_image_tag" => true, + "edit_image_source" => true, + "edit_image_owner" => true, + "bulk_edit_image_tag" => true, + "bulk_edit_image_source" => true, + "mass_tag_edit" => true, + "create_image_report" => true, + "view_image_report" => true, + "edit_wiki_page" => true, + "delete_wiki_page" => true, + "view_eventlog" => true, + "manage_blocks" => true, + "manage_admintools" => true, + "ignore_downtime" => true, + "view_other_pms" => true, + "edit_feature" => true, + "bulk_edit_vote" => true, + "edit_other_vote" => true, + "view_sysinfo" => true, + "view_hellbanned" => true, + "protected" => true, +]); -new UserClass("hellbanned", "user", array( - "hellbanned" => True, -)); +new UserClass("hellbanned", "user", [ + "hellbanned" => true, +]); @include_once "data/config/user-classes.conf.php"; - diff --git a/core/util.php b/core/util.php index 9ac1477f..b5908246 100644 --- a/core/util.php +++ b/core/util.php @@ -5,117 +5,126 @@ require_once "vendor/shish/libcontext-php/context.php"; * Misc * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -function mtimefile(string $file): string { - $data_href = get_base_href(); - $mtime = filemtime($file); - return "$data_href/$file?$mtime"; +function mtimefile(string $file): string +{ + $data_href = get_base_href(); + $mtime = filemtime($file); + return "$data_href/$file?$mtime"; } -function get_theme(): string { - global $config; - $theme = $config->get_string("theme", "default"); - if(!file_exists("themes/$theme")) $theme = "default"; - return $theme; +function get_theme(): string +{ + global $config; + $theme = $config->get_string("theme", "default"); + if (!file_exists("themes/$theme")) { + $theme = "default"; + } + return $theme; } -function contact_link(): ?string { - global $config; - $text = $config->get_string('contact_link'); - if(is_null($text)) return null; +function contact_link(): ?string +{ + global $config; + $text = $config->get_string('contact_link'); + if (is_null($text)) { + return null; + } - if( - startsWith($text, "http:") || - startsWith($text, "https:") || - startsWith($text, "mailto:") - ) { - return $text; - } + if ( + startsWith($text, "http:") || + startsWith($text, "https:") || + startsWith($text, "mailto:") + ) { + return $text; + } - if(strpos($text, "@")) { - return "mailto:$text"; - } + if (strpos($text, "@")) { + return "mailto:$text"; + } - if(strpos($text, "/")) { - return "http://$text"; - } + if (strpos($text, "/")) { + return "http://$text"; + } - return $text; + return $text; } /** * Check if HTTPS is enabled for the server. */ -function is_https_enabled(): bool { - return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); +function is_https_enabled(): bool +{ + return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); } /** * Compare two Block objects, used to sort them before being displayed */ -function blockcmp(Block $a, Block $b): int { - if($a->position == $b->position) { - return 0; - } - else { - return ($a->position > $b->position); - } +function blockcmp(Block $a, Block $b): int +{ + if ($a->position == $b->position) { + return 0; + } else { + return ($a->position > $b->position); + } } /** * Figure out PHP's internal memory limit */ -function get_memory_limit(): int { - global $config; +function get_memory_limit(): int +{ + global $config; - // thumbnail generation requires lots of memory - $default_limit = 8*1024*1024; // 8 MB of memory is PHP's default. - $shimmie_limit = parse_shorthand_int($config->get_int("thumb_mem_limit")); + // thumbnail generation requires lots of memory + $default_limit = 8*1024*1024; // 8 MB of memory is PHP's default. + $shimmie_limit = parse_shorthand_int($config->get_int("thumb_mem_limit")); - if($shimmie_limit < 3*1024*1024) { - // we aren't going to fit, override - $shimmie_limit = $default_limit; - } + if ($shimmie_limit < 3*1024*1024) { + // we aren't going to fit, override + $shimmie_limit = $default_limit; + } - /* - Get PHP's configured memory limit. - Note that this is set to -1 for NO memory limit. + /* + Get PHP's configured memory limit. + Note that this is set to -1 for NO memory limit. - http://ca2.php.net/manual/en/ini.core.php#ini.memory-limit - */ - $memory = parse_shorthand_int(ini_get("memory_limit")); + http://ca2.php.net/manual/en/ini.core.php#ini.memory-limit + */ + $memory = parse_shorthand_int(ini_get("memory_limit")); - if($memory == -1) { - // No memory limit. - // Return the larger of the set limits. - return max($shimmie_limit, $default_limit); - } - else { - // PHP has a memory limit set. - if ($shimmie_limit > $memory) { - // Shimmie wants more memory than what PHP is currently set for. + if ($memory == -1) { + // No memory limit. + // Return the larger of the set limits. + return max($shimmie_limit, $default_limit); + } else { + // PHP has a memory limit set. + if ($shimmie_limit > $memory) { + // Shimmie wants more memory than what PHP is currently set for. - // Attempt to set PHP's memory limit. - if ( ini_set("memory_limit", $shimmie_limit) === false ) { - /* We can't change PHP's limit, oh well, return whatever its currently set to */ - return $memory; - } - $memory = parse_shorthand_int(ini_get("memory_limit")); - } + // Attempt to set PHP's memory limit. + if (ini_set("memory_limit", $shimmie_limit) === false) { + /* We can't change PHP's limit, oh well, return whatever its currently set to */ + return $memory; + } + $memory = parse_shorthand_int(ini_get("memory_limit")); + } - // PHP's memory limit is more than Shimmie needs. - return $memory; // return the current setting - } + // PHP's memory limit is more than Shimmie needs. + return $memory; // return the current setting + } } /** * Get the currently active IP, masked to make it not change when the last * octet or two change, for use in session cookies and such */ -function get_session_ip(Config $config): string { - $mask = $config->get_string("session_hash_mask", "255.255.0.0"); - $addr = $_SERVER['REMOTE_ADDR']; - $addr = inet_ntop(inet_pton($addr) & inet_pton($mask)); - return $addr; +function get_session_ip(Config $config): string +{ + $mask = $config->get_string("session_hash_mask", "255.255.0.0"); + $addr = $_SERVER['REMOTE_ADDR']; + $addr = inet_ntop(inet_pton($addr) & inet_pton($mask)); + return $addr; } @@ -128,146 +137,159 @@ function get_session_ip(Config $config): string { * the action actually takes place (eg onWhateverElse) - but much of the time, actions * are taken from within onPageRequest... */ -function flash_message(string $text, string $type="info") { - global $page; - $current = $page->get_cookie("flash_message"); - if($current) { - $text = $current . "\n" . $text; - } - # the message should be viewed pretty much immediately, - # so 60s timeout should be more than enough - $page->add_cookie("flash_message", $text, time()+60, "/"); +function flash_message(string $text, string $type="info") +{ + global $page; + $current = $page->get_cookie("flash_message"); + if ($current) { + $text = $current . "\n" . $text; + } + # the message should be viewed pretty much immediately, + # so 60s timeout should be more than enough + $page->add_cookie("flash_message", $text, time()+60, "/"); } /** * A shorthand way to send a TextFormattingEvent and get the results. */ -function format_text(string $string): string { - $tfe = new TextFormattingEvent($string); - send_event($tfe); - return $tfe->formatted; +function format_text(string $string): string +{ + $tfe = new TextFormattingEvent($string); + send_event($tfe); + return $tfe->formatted; } -function warehouse_path(string $base, string $hash, bool $create=true): string { - $ab = substr($hash, 0, 2); - $cd = substr($hash, 2, 2); - if(WH_SPLITS == 2) { - $pa = 'data/'.$base.'/'.$ab.'/'.$cd.'/'.$hash; - } - else { - $pa = 'data/'.$base.'/'.$ab.'/'.$hash; - } - if($create && !file_exists(dirname($pa))) mkdir(dirname($pa), 0755, true); - return $pa; +function warehouse_path(string $base, string $hash, bool $create=true): string +{ + $ab = substr($hash, 0, 2); + $cd = substr($hash, 2, 2); + if (WH_SPLITS == 2) { + $pa = 'data/'.$base.'/'.$ab.'/'.$cd.'/'.$hash; + } else { + $pa = 'data/'.$base.'/'.$ab.'/'.$hash; + } + if ($create && !file_exists(dirname($pa))) { + mkdir(dirname($pa), 0755, true); + } + return $pa; } -function data_path(string $filename): string { - $filename = "data/" . $filename; - if(!file_exists(dirname($filename))) mkdir(dirname($filename), 0755, true); - return $filename; +function data_path(string $filename): string +{ + $filename = "data/" . $filename; + if (!file_exists(dirname($filename))) { + mkdir(dirname($filename), 0755, true); + } + return $filename; } -function transload(string $url, string $mfile): ?array { - global $config; +function transload(string $url, string $mfile): ?array +{ + global $config; - if($config->get_string("transload_engine") === "curl" && function_exists("curl_init")) { - $ch = curl_init($url); - $fp = fopen($mfile, "w"); + if ($config->get_string("transload_engine") === "curl" && function_exists("curl_init")) { + $ch = curl_init($url); + $fp = fopen($mfile, "w"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_VERBOSE, 1); - curl_setopt($ch, CURLOPT_HEADER, 1); - curl_setopt($ch, CURLOPT_REFERER, $url); - curl_setopt($ch, CURLOPT_USERAGENT, "Shimmie-".VERSION); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_VERBOSE, 1); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_REFERER, $url); + curl_setopt($ch, CURLOPT_USERAGENT, "Shimmie-".VERSION); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - $response = curl_exec($ch); + $response = curl_exec($ch); - $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $headers = http_parse_headers(implode("\n", preg_split('/\R/', rtrim(substr($response, 0, $header_size))))); - $body = substr($response, $header_size); + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $headers = http_parse_headers(implode("\n", preg_split('/\R/', rtrim(substr($response, 0, $header_size))))); + $body = substr($response, $header_size); - curl_close($ch); - fwrite($fp, $body); - fclose($fp); + curl_close($ch); + fwrite($fp, $body); + fclose($fp); - return $headers; - } + return $headers; + } - if($config->get_string("transload_engine") === "wget") { - $s_url = escapeshellarg($url); - $s_mfile = escapeshellarg($mfile); - system("wget --no-check-certificate $s_url --output-document=$s_mfile"); + if ($config->get_string("transload_engine") === "wget") { + $s_url = escapeshellarg($url); + $s_mfile = escapeshellarg($mfile); + system("wget --no-check-certificate $s_url --output-document=$s_mfile"); - return file_exists($mfile); - } + return file_exists($mfile); + } - if($config->get_string("transload_engine") === "fopen") { - $fp_in = @fopen($url, "r"); - $fp_out = fopen($mfile, "w"); - if(!$fp_in || !$fp_out) { - return null; - } - $length = 0; - while(!feof($fp_in) && $length <= $config->get_int('upload_size')) { - $data = fread($fp_in, 8192); - $length += strlen($data); - fwrite($fp_out, $data); - } - fclose($fp_in); - fclose($fp_out); + if ($config->get_string("transload_engine") === "fopen") { + $fp_in = @fopen($url, "r"); + $fp_out = fopen($mfile, "w"); + if (!$fp_in || !$fp_out) { + return null; + } + $length = 0; + while (!feof($fp_in) && $length <= $config->get_int('upload_size')) { + $data = fread($fp_in, 8192); + $length += strlen($data); + fwrite($fp_out, $data); + } + fclose($fp_in); + fclose($fp_out); - $headers = http_parse_headers(implode("\n", $http_response_header)); + $headers = http_parse_headers(implode("\n", $http_response_header)); - return $headers; - } + return $headers; + } - return null; + return null; } /** * Get the active contents of a .php file */ -function manual_include(string $fname): ?string { - static $included = array(); +function manual_include(string $fname): ?string +{ + static $included = []; - if(!file_exists($fname)) return null; + if (!file_exists($fname)) { + return null; + } - if(in_array($fname, $included)) return null; + if (in_array($fname, $included)) { + return null; + } - $included[] = $fname; + $included[] = $fname; - print "$fname\n"; + print "$fname\n"; - $text = file_get_contents($fname); + $text = file_get_contents($fname); - // we want one continuous file - $text = str_replace('<'.'?php', '', $text); - $text = str_replace('?'.'>', '', $text); + // we want one continuous file + $text = str_replace('<'.'?php', '', $text); + $text = str_replace('?'.'>', '', $text); - // most requires are built-in, but we want /lib separately - $text = str_replace('require_', '// require_', $text); - $text = str_replace('// require_once "lib', 'require_once "lib', $text); + // most requires are built-in, but we want /lib separately + $text = str_replace('require_', '// require_', $text); + $text = str_replace('// require_once "lib', 'require_once "lib', $text); - // @include_once is used for user-creatable config files - $text = preg_replace('/@include_once "(.*)";/e', "manual_include('$1')", $text); + // @include_once is used for user-creatable config files + $text = preg_replace('/@include_once "(.*)";/e', "manual_include('$1')", $text); - return $text; + return $text; } -function path_to_tags(string $path): string { - $matches = array(); - if(preg_match("/\d+ - (.*)\.([a-zA-Z]+)/", basename($path), $matches)) { - $tags = $matches[1]; - } - else { - $tags = dirname($path); - $tags = str_replace("/", " ", $tags); - $tags = str_replace("__", " ", $tags); - $tags = trim($tags); - } - return $tags; +function path_to_tags(string $path): string +{ + $matches = []; + if (preg_match("/\d+ - (.*)\.([a-zA-Z]+)/", basename($path), $matches)) { + $tags = $matches[1]; + } else { + $tags = dirname($path); + $tags = str_replace("/", " ", $tags); + $tags = str_replace("__", " ", $tags); + $tags = trim($tags); + } + return $tags; } @@ -284,52 +306,54 @@ $_shm_load_start = microtime(true); * Collects some debug information (execution time, memory usage, queries, etc) * and formats it to stick in the footer of the page. */ -function get_debug_info(): string { - global $config, $_shm_event_count, $database, $_shm_load_start; +function get_debug_info(): string +{ + global $config, $_shm_event_count, $database, $_shm_load_start; - $i_mem = sprintf("%5.2f", ((memory_get_peak_usage(true)+512)/1024)/1024); + $i_mem = sprintf("%5.2f", ((memory_get_peak_usage(true)+512)/1024)/1024); - if($config->get_string("commit_hash", "unknown") == "unknown"){ - $commit = ""; - } - else { - $commit = " (".$config->get_string("commit_hash").")"; - } - $time = sprintf("%.2f", microtime(true) - $_shm_load_start); - $dbtime = sprintf("%.2f", $database->dbtime); - $i_files = count(get_included_files()); - $hits = $database->cache->get_hits(); - $miss = $database->cache->get_misses(); + if ($config->get_string("commit_hash", "unknown") == "unknown") { + $commit = ""; + } else { + $commit = " (".$config->get_string("commit_hash").")"; + } + $time = sprintf("%.2f", microtime(true) - $_shm_load_start); + $dbtime = sprintf("%.2f", $database->dbtime); + $i_files = count(get_included_files()); + $hits = $database->cache->get_hits(); + $miss = $database->cache->get_misses(); - $debug = "
Took $time seconds (db:$dbtime) and {$i_mem}MB of RAM"; - $debug .= "; Used $i_files files and {$database->query_count} queries"; - $debug .= "; Sent $_shm_event_count events"; - $debug .= "; $hits cache hits and $miss misses"; - $debug .= "; Shimmie version ". VERSION . $commit; // .", SCore Version ". SCORE_VERSION; + $debug = "
Took $time seconds (db:$dbtime) and {$i_mem}MB of RAM"; + $debug .= "; Used $i_files files and {$database->query_count} queries"; + $debug .= "; Sent $_shm_event_count events"; + $debug .= "; $hits cache hits and $miss misses"; + $debug .= "; Shimmie version ". VERSION . $commit; // .", SCore Version ". SCORE_VERSION; - return $debug; + return $debug; } -function log_slow() { - global $_shm_load_start; - if(!is_null(SLOW_PAGES)) { - $_time = microtime(true) - $_shm_load_start; - if($_time > SLOW_PAGES) { - $_query = _get_query(); - $_dbg = get_debug_info(); - file_put_contents("data/slow-pages.log", "$_time $_query $_dbg\n", FILE_APPEND | LOCK_EX); - } - } +function log_slow() +{ + global $_shm_load_start; + if (!is_null(SLOW_PAGES)) { + $_time = microtime(true) - $_shm_load_start; + if ($_time > SLOW_PAGES) { + $_query = _get_query(); + $_dbg = get_debug_info(); + file_put_contents("data/slow-pages.log", "$_time $_query $_dbg\n", FILE_APPEND | LOCK_EX); + } + } } -function score_assert_handler($file, $line, $code, $desc = null) { - $file = basename($file); - print("Assertion failed at $file:$line: $code ($desc)"); - /* - print(""); - debug_print_backtrace(); - print(""); - */ +function score_assert_handler($file, $line, $code, $desc = null) +{ + $file = basename($file); + print("Assertion failed at $file:$line: $code ($desc)"); + /* + print(""); + debug_print_backtrace(); + print(""); + */ } @@ -339,88 +363,94 @@ function score_assert_handler($file, $line, $code, $desc = null) { /** @privatesection */ -function _version_check() { - if(MIN_PHP_VERSION) { - if(version_compare(phpversion(), MIN_PHP_VERSION, ">=") === FALSE) { - print " +function _version_check() +{ + if (MIN_PHP_VERSION) { + if (version_compare(phpversion(), MIN_PHP_VERSION, ">=") === false) { + print " Shimmie (SCore Engine) does not support versions of PHP lower than ".MIN_PHP_VERSION." (PHP reports that it is version ".phpversion().") If your web host is running an older version, they are dangerously out of date and you should plan on moving elsewhere. "; - exit; - } - } + exit; + } + } } -function _sanitise_environment() { - global $_shm_ctx; +function _sanitise_environment() +{ + global $_shm_ctx; - if(TIMEZONE) { - date_default_timezone_set(TIMEZONE); - } + if (TIMEZONE) { + date_default_timezone_set(TIMEZONE); + } - # ini_set('zend.assertions', 1); // generate assertions - ini_set('assert.exception', 1); // throw exceptions when failed - if(DEBUG) { - error_reporting(E_ALL); - assert_options(ASSERT_ACTIVE, 1); - assert_options(ASSERT_BAIL, 1); - assert_options(ASSERT_WARNING, 0); - assert_options(ASSERT_QUIET_EVAL, 1); - assert_options(ASSERT_CALLBACK, 'score_assert_handler'); - } + # ini_set('zend.assertions', 1); // generate assertions + ini_set('assert.exception', 1); // throw exceptions when failed + if (DEBUG) { + error_reporting(E_ALL); + assert_options(ASSERT_ACTIVE, 1); + assert_options(ASSERT_BAIL, 1); + assert_options(ASSERT_WARNING, 0); + assert_options(ASSERT_QUIET_EVAL, 1); + assert_options(ASSERT_CALLBACK, 'score_assert_handler'); + } - $_shm_ctx = new Context(); - if(CONTEXT) { - $_shm_ctx->set_log(CONTEXT); - } + $_shm_ctx = new Context(); + if (CONTEXT) { + $_shm_ctx->set_log(CONTEXT); + } - if(COVERAGE) { - _start_coverage(); - register_shutdown_function("_end_coverage"); - } + if (COVERAGE) { + _start_coverage(); + register_shutdown_function("_end_coverage"); + } - ob_start(); + ob_start(); - if(PHP_SAPI === 'cli' || PHP_SAPI == 'phpdbg') { - if(isset($_SERVER['REMOTE_ADDR'])) { - die("CLI with remote addr? Confused, not taking the risk."); - } - $_SERVER['REMOTE_ADDR'] = "0.0.0.0"; - $_SERVER['HTTP_HOST'] = ""; - } + if (PHP_SAPI === 'cli' || PHP_SAPI == 'phpdbg') { + if (isset($_SERVER['REMOTE_ADDR'])) { + die("CLI with remote addr? Confused, not taking the risk."); + } + $_SERVER['REMOTE_ADDR'] = "0.0.0.0"; + $_SERVER['HTTP_HOST'] = " "; + } } -function _get_themelet_files(string $_theme): array { - $base_themelets = array(); - if(file_exists('themes/'.$_theme.'/custompage.class.php')) $base_themelets[] = 'themes/'.$_theme.'/custompage.class.php'; - $base_themelets[] = 'themes/'.$_theme.'/layout.class.php'; - $base_themelets[] = 'themes/'.$_theme.'/themelet.class.php'; +function _get_themelet_files(string $_theme): array +{ + $base_themelets = []; + if (file_exists('themes/'.$_theme.'/custompage.class.php')) { + $base_themelets[] = 'themes/'.$_theme.'/custompage.class.php'; + } + $base_themelets[] = 'themes/'.$_theme.'/layout.class.php'; + $base_themelets[] = 'themes/'.$_theme.'/themelet.class.php'; - $ext_themelets = zglob("ext/{".ENABLED_EXTS."}/theme.php"); - $custom_themelets = zglob('themes/'.$_theme.'/{'.ENABLED_EXTS.'}.theme.php'); + $ext_themelets = zglob("ext/{".ENABLED_EXTS."}/theme.php"); + $custom_themelets = zglob('themes/'.$_theme.'/{'.ENABLED_EXTS.'}.theme.php'); - return array_merge($base_themelets, $ext_themelets, $custom_themelets); + return array_merge($base_themelets, $ext_themelets, $custom_themelets); } /** * Used to display fatal errors to the web user. */ -function _fatal_error(Exception $e) { - $version = VERSION; - $message = $e->getMessage(); +function _fatal_error(Exception $e) +{ + $version = VERSION; + $message = $e->getMessage(); - //$trace = var_dump($e->getTrace()); + //$trace = var_dump($e->getTrace()); - //$hash = exec("git rev-parse HEAD"); - //$h_hash = $hash ? " Hash: $hash" : ""; - //'.$h_hash.' + //$hash = exec("git rev-parse HEAD"); + //$h_hash = $hash ? "
Hash: $hash" : ""; + //'.$h_hash.' - header("HTTP/1.0 500 Internal Error"); - echo ' + header("HTTP/1.0 500 Internal Error"); + echo '
Internal error - SCore-'.$version.' @@ -440,42 +470,50 @@ function _fatal_error(Exception $e) { * Necessary because various servers and various clients * think that / is special... */ -function _decaret(string $str): string { - $out = ""; - $length = strlen($str); - for($i=0; $i<$length; $i++) { - if($str[$i] == "^") { - $i++; - if($str[$i] == "^") $out .= "^"; - if($str[$i] == "s") $out .= "/"; - if($str[$i] == "b") $out .= "\\"; - } - else { - $out .= $str[$i]; - } - } - return $out; +function _decaret(string $str): string +{ + $out = ""; + $length = strlen($str); + for ($i=0; $i<$length; $i++) { + if ($str[$i] == "^") { + $i++; + if ($str[$i] == "^") { + $out .= "^"; + } + if ($str[$i] == "s") { + $out .= "/"; + } + if ($str[$i] == "b") { + $out .= "\\"; + } + } else { + $out .= $str[$i]; + } + } + return $out; } -function _get_user(): User { - global $config, $page; - $user = null; - if($page->get_cookie("user") && $page->get_cookie("session")) { - $tmp_user = User::by_session($page->get_cookie("user"), $page->get_cookie("session")); - if(!is_null($tmp_user)) { - $user = $tmp_user; - } - } - if(is_null($user)) { - $user = User::by_id($config->get_int("anon_id", 0)); - } - assert(!is_null($user)); +function _get_user(): User +{ + global $config, $page; + $user = null; + if ($page->get_cookie("user") && $page->get_cookie("session")) { + $tmp_user = User::by_session($page->get_cookie("user"), $page->get_cookie("session")); + if (!is_null($tmp_user)) { + $user = $tmp_user; + } + } + if (is_null($user)) { + $user = User::by_id($config->get_int("anon_id", 0)); + } + assert(!is_null($user)); - return $user; + return $user; } -function _get_query(): string { - return (@$_POST["q"]?:@$_GET["q"])?:"/"; +function _get_query(): string +{ + return (@$_POST["q"]?:@$_GET["q"])?:"/"; } @@ -483,24 +521,30 @@ function _get_query(): string { * Code coverage * \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -function _start_coverage(): void { - if(function_exists("xdebug_start_code_coverage")) { - #xdebug_start_code_coverage(XDEBUG_CC_UNUSED|XDEBUG_CC_DEAD_CODE); - xdebug_start_code_coverage(XDEBUG_CC_UNUSED); - } +function _start_coverage(): void +{ + if (function_exists("xdebug_start_code_coverage")) { + #xdebug_start_code_coverage(XDEBUG_CC_UNUSED|XDEBUG_CC_DEAD_CODE); + xdebug_start_code_coverage(XDEBUG_CC_UNUSED); + } } -function _end_coverage(): void { - if(function_exists("xdebug_get_code_coverage")) { - // Absolute path is necessary because working directory - // inside register_shutdown_function is unpredictable. - $absolute_path = dirname(dirname(__FILE__)) . "/data/coverage"; - if(!file_exists($absolute_path)) mkdir($absolute_path); - $n = 0; - $t = time(); - while(file_exists("$absolute_path/$t.$n.log")) $n++; - file_put_contents("$absolute_path/$t.$n.log", gzdeflate(serialize(xdebug_get_code_coverage()))); - } +function _end_coverage(): void +{ + if (function_exists("xdebug_get_code_coverage")) { + // Absolute path is necessary because working directory + // inside register_shutdown_function is unpredictable. + $absolute_path = dirname(dirname(__FILE__)) . "/data/coverage"; + if (!file_exists($absolute_path)) { + mkdir($absolute_path); + } + $n = 0; + $t = time(); + while (file_exists("$absolute_path/$t.$n.log")) { + $n++; + } + file_put_contents("$absolute_path/$t.$n.log", gzdeflate(serialize(xdebug_get_code_coverage()))); + } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ @@ -513,35 +557,36 @@ function _end_coverage(): void { * * FIXME: also check that IP ban ext is installed */ -function show_ip(string $ip, string $ban_reason): string { - global $user; - $u_reason = url_escape($ban_reason); - $u_end = url_escape("+1 week"); - $ban = $user->can("ban_ip") ? ", Ban" : ""; - $ip = $user->can("view_ip") ? $ip.$ban : ""; - return $ip; +function show_ip(string $ip, string $ban_reason): string +{ + global $user; + $u_reason = url_escape($ban_reason); + $u_end = url_escape("+1 week"); + $ban = $user->can("ban_ip") ? ", Ban" : ""; + $ip = $user->can("view_ip") ? $ip.$ban : ""; + return $ip; } /** * Make a form tag with relevant auth token and stuff */ -function make_form(string $target, string $method="POST", bool $multipart=False, string $form_id="", string $onsubmit=""): string { - global $user; - if($method == "GET") { - $link = html_escape($target); - $target = make_link($target); - $extra_inputs = ""; - } - else { - $extra_inputs = $user->get_auth_html(); - } +function make_form(string $target, string $method="POST", bool $multipart=false, string $form_id="", string $onsubmit=""): string +{ + global $user; + if ($method == "GET") { + $link = html_escape($target); + $target = make_link($target); + $extra_inputs = ""; + } else { + $extra_inputs = $user->get_auth_html(); + } - $extra = empty($form_id) ? '' : 'id="'. $form_id .'"'; - if($multipart) { - $extra .= " enctype='multipart/form-data'"; - } - if($onsubmit) { - $extra .= ' onsubmit="'.$onsubmit.'"'; - } - return '\n"; - return $html; - } + protected function button(string $name, string $action, bool $protected=false): string + { + $c_protected = $protected ? " protected" : ""; + $html = make_form(make_link("admin/$action"), "POST", false, "admin$c_protected"); + if ($protected) { + $html .= ""; + $html .= ""; + } else { + $html .= ""; + } + $html .= "\n"; + return $html; + } - /* - * Show a form which links to admin_utils with POST[action] set to one of: - * 'lowercase all tags' - * 'recount tag use' - * etc - */ - public function display_form() { - global $page, $database; + /* + * Show a form which links to admin_utils with POST[action] set to one of: + * 'lowercase all tags' + * 'recount tag use' + * etc + */ + public function display_form() + { + global $page, $database; - $html = ""; - $html .= $this->button("All tags to lowercase", "lowercase_all_tags", true); - $html .= $this->button("Recount tag use", "recount_tag_use", false); - if(class_exists('ZipArchive')) - $html .= $this->button("Download all images", "download_all_images", false); + $html = ""; + $html .= $this->button("All tags to lowercase", "lowercase_all_tags", true); + $html .= $this->button("Recount tag use", "recount_tag_use", false); + if (class_exists('ZipArchive')) { + $html .= $this->button("Download all images", "download_all_images", false); + } $html .= $this->button("Download database contents", "database_dump", false); - if($database->get_driver_name() == "mysql") - $html .= $this->button("Reset image IDs", "reset_image_ids", true); - $page->add_block(new Block("Misc Admin Tools", $html)); + if ($database->get_driver_name() == "mysql") { + $html .= $this->button("Reset image IDs", "reset_image_ids", true); + } + $page->add_block(new Block("Misc Admin Tools", $html)); - $html = make_form(make_link("admin/set_tag_case"), "POST"); - $html .= ""; - $html .= ""; - $html .= "\n"; - $page->add_block(new Block("Set Tag Case", $html)); - } + $html = make_form(make_link("admin/set_tag_case"), "POST"); + $html .= ""; + $html .= ""; + $html .= "\n"; + $page->add_block(new Block("Set Tag Case", $html)); + } - public function dbq_html($terms) { - $h_terms = html_escape($terms); - $h_reason = ""; - if(class_exists("ImageBan")) { - $h_reason = ""; - } - $html = make_form(make_link("admin/delete_by_query"), "POST") . " + public function dbq_html($terms) + { + $h_terms = html_escape($terms); + $h_reason = ""; + if (class_exists("ImageBan")) { + $h_reason = ""; + } + $html = make_form(make_link("admin/delete_by_query"), "POST") . " $h_reason "; - return $html; - } + return $html; + } } - diff --git a/ext/alias_editor/main.php b/ext/alias_editor/main.php index 40c0117a..9e7139cf 100644 --- a/ext/alias_editor/main.php +++ b/ext/alias_editor/main.php @@ -10,155 +10,156 @@ * site admins can edit it, other people can view and download it */ -class AddAliasEvent extends Event { - /** @var string */ - public $oldtag; - /** @var string */ - public $newtag; +class AddAliasEvent extends Event +{ + /** @var string */ + public $oldtag; + /** @var string */ + public $newtag; - public function __construct(string $oldtag, string $newtag) { - $this->oldtag = trim($oldtag); - $this->newtag = trim($newtag); - } + public function __construct(string $oldtag, string $newtag) + { + $this->oldtag = trim($oldtag); + $this->newtag = trim($newtag); + } } -class AddAliasException extends SCoreException {} - -class AliasEditor extends Extension { - public function onPageRequest(PageRequestEvent $event) { - global $config, $database, $page, $user; - - if($event->page_matches("alias")) { - if($event->get_arg(0) == "add") { - if($user->can("manage_alias_list")) { - if(isset($_POST['oldtag']) && isset($_POST['newtag'])) { - try { - $aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); - send_event($aae); - $page->set_mode("redirect"); - $page->set_redirect(make_link("alias/list")); - } - catch(AddAliasException $ex) { - $this->theme->display_error(500, "Error adding alias", $ex->getMessage()); - } - } - } - } - else if($event->get_arg(0) == "remove") { - if($user->can("manage_alias_list")) { - if(isset($_POST['oldtag'])) { - $database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", array("oldtag" => $_POST['oldtag'])); - log_info("alias_editor", "Deleted alias for ".$_POST['oldtag'], "Deleted alias"); - - $page->set_mode("redirect"); - $page->set_redirect(make_link("alias/list")); - } - } - } - else if($event->get_arg(0) == "list") { - $page_number = $event->get_arg(1); - if(is_null($page_number) || !is_numeric($page_number)) { - $page_number = 0; - } - else if ($page_number <= 0) { - $page_number = 0; - } - else { - $page_number--; - } - - $alias_per_page = $config->get_int('alias_items_per_page', 30); - - $query = "SELECT oldtag, newtag FROM aliases ORDER BY newtag ASC LIMIT :limit OFFSET :offset"; - $alias = $database->get_pairs($query, - array("limit"=>$alias_per_page, "offset"=>$page_number * $alias_per_page) - ); - - $total_pages = ceil($database->get_one("SELECT COUNT(*) FROM aliases") / $alias_per_page); - - $this->theme->display_aliases($alias, $page_number + 1, $total_pages); - } - else if($event->get_arg(0) == "export") { - $page->set_mode("data"); - $page->set_type("text/csv"); - $page->set_filename("aliases.csv"); - $page->set_data($this->get_alias_csv($database)); - } - else if($event->get_arg(0) == "import") { - if($user->can("manage_alias_list")) { - if(count($_FILES) > 0) { - $tmp = $_FILES['alias_file']['tmp_name']; - $contents = file_get_contents($tmp); - $this->add_alias_csv($database, $contents); - log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many? - $page->set_mode("redirect"); - $page->set_redirect(make_link("alias/list")); - } - else { - $this->theme->display_error(400, "No File Specified", "You have to upload a file"); - } - } - else { - $this->theme->display_error(401, "Admins Only", "Only admins can edit the alias list"); - } - } - } - } - - public function onAddAlias(AddAliasEvent $event) { - global $database; - $pair = array("oldtag" => $event->oldtag, "newtag" => $event->newtag); - if($database->get_row("SELECT * FROM aliases WHERE oldtag=:oldtag AND lower(newtag)=lower(:newtag)", $pair)) { - throw new AddAliasException("That alias already exists"); - } - else if($database->get_row("SELECT * FROM aliases WHERE oldtag=:newtag", array("newtag" => $event->newtag))) { - throw new AddAliasException("{$event->newtag} is itself an alias"); - } - else { - $database->execute("INSERT INTO aliases(oldtag, newtag) VALUES(:oldtag, :newtag)", $pair); - log_info("alias_editor", "Added alias for {$event->oldtag} -> {$event->newtag}", "Added alias"); - } - } - - public function onUserBlockBuilding(UserBlockBuildingEvent $event) { - global $user; - if($user->can("manage_alias_list")) { - $event->add_link("Alias Editor", make_link("alias/list")); - } - } - - private function get_alias_csv(Database $database): string { - $csv = ""; - $aliases = $database->get_pairs("SELECT oldtag, newtag FROM aliases ORDER BY newtag"); - foreach($aliases as $old => $new) { - $csv .= "\"$old\",\"$new\"\n"; - } - return $csv; - } - - private function add_alias_csv(Database $database, string $csv) { - $csv = str_replace("\r", "\n", $csv); - foreach(explode("\n", $csv) as $line) { - $parts = str_getcsv($line); - if(count($parts) == 2) { - try { - $aae = new AddAliasEvent($parts[0], $parts[1]); - send_event($aae); - } - catch(AddAliasException $ex) { - $this->theme->display_error(500, "Error adding alias", $ex->getMessage()); - } - } - } - } - - /** - * Get the priority for this extension. - * - * Add alias *after* mass tag editing, else the MTE will - * search for the images and be redirected to the alias, - * missing out the images tagged with the old tag. - */ - public function get_priority(): int {return 60;} +class AddAliasException extends SCoreException +{ } +class AliasEditor extends Extension +{ + public function onPageRequest(PageRequestEvent $event) + { + global $config, $database, $page, $user; + + if ($event->page_matches("alias")) { + if ($event->get_arg(0) == "add") { + if ($user->can("manage_alias_list")) { + if (isset($_POST['oldtag']) && isset($_POST['newtag'])) { + try { + $aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); + send_event($aae); + $page->set_mode("redirect"); + $page->set_redirect(make_link("alias/list")); + } catch (AddAliasException $ex) { + $this->theme->display_error(500, "Error adding alias", $ex->getMessage()); + } + } + } + } elseif ($event->get_arg(0) == "remove") { + if ($user->can("manage_alias_list")) { + if (isset($_POST['oldtag'])) { + $database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", ["oldtag" => $_POST['oldtag']]); + log_info("alias_editor", "Deleted alias for ".$_POST['oldtag'], "Deleted alias"); + + $page->set_mode("redirect"); + $page->set_redirect(make_link("alias/list")); + } + } + } elseif ($event->get_arg(0) == "list") { + $page_number = $event->get_arg(1); + if (is_null($page_number) || !is_numeric($page_number)) { + $page_number = 0; + } elseif ($page_number <= 0) { + $page_number = 0; + } else { + $page_number--; + } + + $alias_per_page = $config->get_int('alias_items_per_page', 30); + + $query = "SELECT oldtag, newtag FROM aliases ORDER BY newtag ASC LIMIT :limit OFFSET :offset"; + $alias = $database->get_pairs( + $query, + ["limit"=>$alias_per_page, "offset"=>$page_number * $alias_per_page] + ); + + $total_pages = ceil($database->get_one("SELECT COUNT(*) FROM aliases") / $alias_per_page); + + $this->theme->display_aliases($alias, $page_number + 1, $total_pages); + } elseif ($event->get_arg(0) == "export") { + $page->set_mode("data"); + $page->set_type("text/csv"); + $page->set_filename("aliases.csv"); + $page->set_data($this->get_alias_csv($database)); + } elseif ($event->get_arg(0) == "import") { + if ($user->can("manage_alias_list")) { + if (count($_FILES) > 0) { + $tmp = $_FILES['alias_file']['tmp_name']; + $contents = file_get_contents($tmp); + $this->add_alias_csv($database, $contents); + log_info("alias_editor", "Imported aliases from file", "Imported aliases"); # FIXME: how many? + $page->set_mode("redirect"); + $page->set_redirect(make_link("alias/list")); + } else { + $this->theme->display_error(400, "No File Specified", "You have to upload a file"); + } + } else { + $this->theme->display_error(401, "Admins Only", "Only admins can edit the alias list"); + } + } + } + } + + public function onAddAlias(AddAliasEvent $event) + { + global $database; + $pair = ["oldtag" => $event->oldtag, "newtag" => $event->newtag]; + if ($database->get_row("SELECT * FROM aliases WHERE oldtag=:oldtag AND lower(newtag)=lower(:newtag)", $pair)) { + throw new AddAliasException("That alias already exists"); + } elseif ($database->get_row("SELECT * FROM aliases WHERE oldtag=:newtag", ["newtag" => $event->newtag])) { + throw new AddAliasException("{$event->newtag} is itself an alias"); + } else { + $database->execute("INSERT INTO aliases(oldtag, newtag) VALUES(:oldtag, :newtag)", $pair); + log_info("alias_editor", "Added alias for {$event->oldtag} -> {$event->newtag}", "Added alias"); + } + } + + public function onUserBlockBuilding(UserBlockBuildingEvent $event) + { + global $user; + if ($user->can("manage_alias_list")) { + $event->add_link("Alias Editor", make_link("alias/list")); + } + } + + private function get_alias_csv(Database $database): string + { + $csv = ""; + $aliases = $database->get_pairs("SELECT oldtag, newtag FROM aliases ORDER BY newtag"); + foreach ($aliases as $old => $new) { + $csv .= "\"$old\",\"$new\"\n"; + } + return $csv; + } + + private function add_alias_csv(Database $database, string $csv) + { + $csv = str_replace("\r", "\n", $csv); + foreach (explode("\n", $csv) as $line) { + $parts = str_getcsv($line); + if (count($parts) == 2) { + try { + $aae = new AddAliasEvent($parts[0], $parts[1]); + send_event($aae); + } catch (AddAliasException $ex) { + $this->theme->display_error(500, "Error adding alias", $ex->getMessage()); + } + } + } + } + + /** + * Get the priority for this extension. + * + * Add alias *after* mass tag editing, else the MTE will + * search for the images and be redirected to the alias, + * missing out the images tagged with the old tag. + */ + public function get_priority(): int + { + return 60; + } +} diff --git a/ext/alias_editor/test.php b/ext/alias_editor/test.php index 0b8e4512..b2bbe00c 100644 --- a/ext/alias_editor/test.php +++ b/ext/alias_editor/test.php @@ -1,104 +1,107 @@ get_page('alias/list'); - $this->assert_response(200); - $this->assert_title("Alias List"); - } +class AliasEditorTest extends ShimmiePHPUnitTestCase +{ + public function testAliasList() + { + $this->get_page('alias/list'); + $this->assert_response(200); + $this->assert_title("Alias List"); + } - public function testAliasListReadOnly() { - // Check that normal users can't add aliases. - $this->log_in_as_user(); - $this->get_page('alias/list'); - $this->assert_title("Alias List"); - $this->assert_no_text("Add"); - } + public function testAliasListReadOnly() + { + // Check that normal users can't add aliases. + $this->log_in_as_user(); + $this->get_page('alias/list'); + $this->assert_title("Alias List"); + $this->assert_no_text("Add"); + } - public function testAliasEditor() { - /* - ********************************************************************** - * FIXME: TODO: - * For some reason the alias tests always fail when they are running - * inside the TravisCI VM environment. I have tried to determine - * the exact cause of this, but have been unable to pin it down. - * - * For now, I am commenting them out until I have more time to - * dig into this and determine exactly what is happening. - * - ********************************************************************* - */ - $this->markTestIncomplete(); + public function testAliasEditor() + { + /* + ********************************************************************** + * FIXME: TODO: + * For some reason the alias tests always fail when they are running + * inside the TravisCI VM environment. I have tried to determine + * the exact cause of this, but have been unable to pin it down. + * + * For now, I am commenting them out until I have more time to + * dig into this and determine exactly what is happening. + * + ********************************************************************* + */ + $this->markTestIncomplete(); - $this->log_in_as_admin(); + $this->log_in_as_admin(); - # test one to one - $this->get_page('alias/list'); - $this->assert_title("Alias List"); - $this->set_field('oldtag', "test1"); - $this->set_field('newtag', "test2"); - $this->clickSubmit('Add'); - $this->assert_no_text("Error adding alias"); + # test one to one + $this->get_page('alias/list'); + $this->assert_title("Alias List"); + $this->set_field('oldtag', "test1"); + $this->set_field('newtag', "test2"); + $this->clickSubmit('Add'); + $this->assert_no_text("Error adding alias"); - $this->get_page('alias/list'); - $this->assert_text("test1"); + $this->get_page('alias/list'); + $this->assert_text("test1"); - $this->get_page("alias/export/aliases.csv"); - $this->assert_text("test1,test2"); + $this->get_page("alias/export/aliases.csv"); + $this->assert_text("test1,test2"); - $image_id = $this->post_image("tests/pbx_screenshot.jpg", "test1"); - $this->get_page("post/view/$image_id"); # check that the tag has been replaced - $this->assert_title("Image $image_id: test2"); - $this->get_page("post/list/test1/1"); # searching for an alias should find the master tag - $this->assert_title("Image $image_id: test2"); - $this->get_page("post/list/test2/1"); # check that searching for the main tag still works - $this->assert_title("Image $image_id: test2"); - $this->delete_image($image_id); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "test1"); + $this->get_page("post/view/$image_id"); # check that the tag has been replaced + $this->assert_title("Image $image_id: test2"); + $this->get_page("post/list/test1/1"); # searching for an alias should find the master tag + $this->assert_title("Image $image_id: test2"); + $this->get_page("post/list/test2/1"); # check that searching for the main tag still works + $this->assert_title("Image $image_id: test2"); + $this->delete_image($image_id); - $this->get_page('alias/list'); - $this->click("Remove"); - $this->get_page('alias/list'); - $this->assert_title("Alias List"); - $this->assert_no_text("test1"); + $this->get_page('alias/list'); + $this->click("Remove"); + $this->get_page('alias/list'); + $this->assert_title("Alias List"); + $this->assert_no_text("test1"); - # test one to many - $this->get_page('alias/list'); - $this->assert_title("Alias List"); - $this->set_field('oldtag', "onetag"); - $this->set_field('newtag', "multi tag"); - $this->click("Add"); - $this->get_page('alias/list'); - $this->assert_text("multi"); - $this->assert_text("tag"); + # test one to many + $this->get_page('alias/list'); + $this->assert_title("Alias List"); + $this->set_field('oldtag', "onetag"); + $this->set_field('newtag', "multi tag"); + $this->click("Add"); + $this->get_page('alias/list'); + $this->assert_text("multi"); + $this->assert_text("tag"); - $this->get_page("alias/export/aliases.csv"); - $this->assert_text("onetag,multi tag"); + $this->get_page("alias/export/aliases.csv"); + $this->assert_text("onetag,multi tag"); - $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "onetag"); - $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "onetag"); - // FIXME: known broken - //$this->get_page("post/list/onetag/1"); # searching for an aliased tag should find its aliases - //$this->assert_title("onetag"); - //$this->assert_no_text("No Images Found"); - $this->get_page("post/list/multi/1"); - $this->assert_title("multi"); - $this->assert_no_text("No Images Found"); - $this->get_page("post/list/multi%20tag/1"); - $this->assert_title("multi tag"); - $this->assert_no_text("No Images Found"); - $this->delete_image($image_id_1); - $this->delete_image($image_id_2); + $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "onetag"); + $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "onetag"); + // FIXME: known broken + //$this->get_page("post/list/onetag/1"); # searching for an aliased tag should find its aliases + //$this->assert_title("onetag"); + //$this->assert_no_text("No Images Found"); + $this->get_page("post/list/multi/1"); + $this->assert_title("multi"); + $this->assert_no_text("No Images Found"); + $this->get_page("post/list/multi%20tag/1"); + $this->assert_title("multi tag"); + $this->assert_no_text("No Images Found"); + $this->delete_image($image_id_1); + $this->delete_image($image_id_2); - $this->get_page('alias/list'); - $this->click("Remove"); - $this->get_page('alias/list'); - $this->assert_title("Alias List"); - $this->assert_no_text("test1"); + $this->get_page('alias/list'); + $this->click("Remove"); + $this->get_page('alias/list'); + $this->assert_title("Alias List"); + $this->assert_no_text("test1"); - $this->log_out(); + $this->log_out(); - $this->get_page('alias/list'); - $this->assert_title("Alias List"); - $this->assert_no_text("Add"); - } + $this->get_page('alias/list'); + $this->assert_title("Alias List"); + $this->assert_no_text("Add"); + } } - diff --git a/ext/alias_editor/theme.php b/ext/alias_editor/theme.php index 51e65f2b..ec12348e 100644 --- a/ext/alias_editor/theme.php +++ b/ext/alias_editor/theme.php @@ -1,18 +1,20 @@ can("manage_alias_list"); - if($can_manage) { - $h_action = "Action "; - $h_add = " + $can_manage = $user->can("manage_alias_list"); + if ($can_manage) { + $h_action = "Action "; + $h_add = "".make_form(make_link("alias/add"))." "; - } - else { - $h_action = ""; - $h_add = ""; - } + } else { + $h_action = ""; + $h_add = ""; + } - $h_aliases = ""; - foreach($aliases as $old => $new) { - $h_old = html_escape($old); - $h_new = "".html_escape($new).""; + $h_aliases = ""; + foreach ($aliases as $old => $new) { + $h_old = html_escape($old); + $h_new = "".html_escape($new).""; - $h_aliases .= "@@ -21,20 +23,19 @@ class AliasEditorTheme extends Themelet { $h_old $h_new "; - if($can_manage) { - $h_aliases .= " + $h_aliases .= ""; - } - $html = " + } + $h_aliases .= ""; + } + $html = " $h_old $h_new "; + if ($can_manage) { + $h_aliases .= "".make_form(make_link("alias/remove"))." @@ -42,10 +43,10 @@ class AliasEditorTheme extends Themelet { "; - } - $h_aliases .= ""; + } - $html .= ""; + $html .= ""; - $page->add_block(new Block(null, $html, "main", 1, 'note_system')); - } + $page->add_block(new Block(null, $html, "main", 1, 'note_system')); + } - public function display_note_list($images, $pageNumber, $totalPages) { - global $page; - $pool_images = ''; - foreach($images as $pair) { - $image = $pair[0]; + public function display_note_list($images, $pageNumber, $totalPages) + { + global $page; + $pool_images = ''; + foreach ($images as $pair) { + $image = $pair[0]; - $thumb_html = $this->build_thumb_html($image); + $thumb_html = $this->build_thumb_html($image); - $pool_images .= ''. - ' '.$thumb_html.''. - ''; + $pool_images .= ''. + ' '.$thumb_html.''. + ''; + } + $this->display_paginator($page, "note/list", null, $pageNumber, $totalPages); + $page->set_title("Notes"); + $page->set_heading("Notes"); + $page->add_block(new Block("Notes", $pool_images, "main", 20)); + } - } - $this->display_paginator($page, "note/list", null, $pageNumber, $totalPages); + public function display_note_requests($images, $pageNumber, $totalPages) + { + global $page; - $page->set_title("Notes"); - $page->set_heading("Notes"); - $page->add_block(new Block("Notes", $pool_images, "main", 20)); - } + $pool_images = ''; + foreach ($images as $pair) { + $image = $pair[0]; - public function display_note_requests($images, $pageNumber, $totalPages) { - global $page; + $thumb_html = $this->build_thumb_html($image); - $pool_images = ''; - foreach($images as $pair) { - $image = $pair[0]; + $pool_images .= ''. + ' '.$thumb_html.''. + ''; + } + $this->display_paginator($page, "requests/list", null, $pageNumber, $totalPages); - $thumb_html = $this->build_thumb_html($image); + $page->set_title("Note Requests"); + $page->set_heading("Note Requests"); + $page->add_block(new Block("Note Requests", $pool_images, "main", 20)); + } - $pool_images .= ''. - ' '.$thumb_html.''. - ''; + private function get_history($histories) + { + global $user; + $html = "
$h_aliases @@ -54,22 +55,21 @@ class AliasEditorTheme extends Themelet { "; - $bulk_html = " + $bulk_html = " ".make_form(make_link("alias/import"), 'post', true)." "; - $page->set_title("Alias List"); - $page->set_heading("Alias List"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Aliases", $html)); - if($can_manage) { - $page->add_block(new Block("Bulk Upload", $bulk_html, "main", 51)); - } + $page->set_title("Alias List"); + $page->set_heading("Alias List"); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Aliases", $html)); + if ($can_manage) { + $page->add_block(new Block("Bulk Upload", $bulk_html, "main", 51)); + } - $this->display_paginator($page, "alias/list", null, $pageNumber, $totalPages); - } + $this->display_paginator($page, "alias/list", null, $pageNumber, $totalPages); + } } - diff --git a/ext/amazon_s3/main.php b/ext/amazon_s3/main.php index a0fda3a4..c2f4514f 100644 --- a/ext/amazon_s3/main.php +++ b/ext/amazon_s3/main.php @@ -9,67 +9,71 @@ require_once "ext/amazon_s3/lib/S3.php"; -class UploadS3 extends Extension { - public function onInitExt(InitExtEvent $event) { - global $config; - $config->set_default_string("amazon_s3_access", ""); - $config->set_default_string("amazon_s3_secret", ""); - $config->set_default_string("amazon_s3_bucket", ""); - } +class UploadS3 extends Extension +{ + public function onInitExt(InitExtEvent $event) + { + global $config; + $config->set_default_string("amazon_s3_access", ""); + $config->set_default_string("amazon_s3_secret", ""); + $config->set_default_string("amazon_s3_bucket", ""); + } - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Amazon S3"); - $sb->add_text_option("amazon_s3_access", "Access key: "); - $sb->add_text_option("amazon_s3_secret", " From To $h_action
Secret key: "); - $sb->add_text_option("amazon_s3_bucket", "
Bucket: "); - $event->panel->add_block($sb); - } + public function onSetupBuilding(SetupBuildingEvent $event) + { + $sb = new SetupBlock("Amazon S3"); + $sb->add_text_option("amazon_s3_access", "Access key: "); + $sb->add_text_option("amazon_s3_secret", "
Secret key: "); + $sb->add_text_option("amazon_s3_bucket", "
Bucket: "); + $event->panel->add_block($sb); + } - public function onImageAddition(ImageAdditionEvent $event) { - global $config; - $access = $config->get_string("amazon_s3_access"); - $secret = $config->get_string("amazon_s3_secret"); - $bucket = $config->get_string("amazon_s3_bucket"); - if(!empty($bucket)) { - log_debug("amazon_s3", "Mirroring Image #".$event->image->id." to S3 #$bucket"); - $s3 = new S3($access, $secret); - $s3->putBucket($bucket, S3::ACL_PUBLIC_READ); - $s3->putObjectFile( - warehouse_path("thumbs", $event->image->hash), - $bucket, - 'thumbs/'.$event->image->hash, - S3::ACL_PUBLIC_READ, - array(), - array( - "Content-Type" => "image/jpeg", - "Content-Disposition" => "inline; filename=image-" . $event->image->id . ".jpg", - ) - ); - $s3->putObjectFile( - warehouse_path("images", $event->image->hash), - $bucket, - 'images/'.$event->image->hash, - S3::ACL_PUBLIC_READ, - array(), - array( - "Content-Type" => $event->image->get_mime_type(), - "Content-Disposition" => "inline; filename=image-" . $event->image->id . "." . $event->image->ext, - ) - ); - } - } + public function onImageAddition(ImageAdditionEvent $event) + { + global $config; + $access = $config->get_string("amazon_s3_access"); + $secret = $config->get_string("amazon_s3_secret"); + $bucket = $config->get_string("amazon_s3_bucket"); + if (!empty($bucket)) { + log_debug("amazon_s3", "Mirroring Image #".$event->image->id." to S3 #$bucket"); + $s3 = new S3($access, $secret); + $s3->putBucket($bucket, S3::ACL_PUBLIC_READ); + $s3->putObjectFile( + warehouse_path("thumbs", $event->image->hash), + $bucket, + 'thumbs/'.$event->image->hash, + S3::ACL_PUBLIC_READ, + [], + [ + "Content-Type" => "image/jpeg", + "Content-Disposition" => "inline; filename=image-" . $event->image->id . ".jpg", + ] + ); + $s3->putObjectFile( + warehouse_path("images", $event->image->hash), + $bucket, + 'images/'.$event->image->hash, + S3::ACL_PUBLIC_READ, + [], + [ + "Content-Type" => $event->image->get_mime_type(), + "Content-Disposition" => "inline; filename=image-" . $event->image->id . "." . $event->image->ext, + ] + ); + } + } - public function onImageDeletion(ImageDeletionEvent $event) { - global $config; - $access = $config->get_string("amazon_s3_access"); - $secret = $config->get_string("amazon_s3_secret"); - $bucket = $config->get_string("amazon_s3_bucket"); - if(!empty($bucket)) { - log_debug("amazon_s3", "Deleting Image #".$event->image->id." from S3"); - $s3 = new S3($access, $secret); - $s3->deleteObject($bucket, "images/" . $event->image->hash); - $s3->deleteObject($bucket, "thumbs/" . $event->image->hash); - } - } + public function onImageDeletion(ImageDeletionEvent $event) + { + global $config; + $access = $config->get_string("amazon_s3_access"); + $secret = $config->get_string("amazon_s3_secret"); + $bucket = $config->get_string("amazon_s3_bucket"); + if (!empty($bucket)) { + log_debug("amazon_s3", "Deleting Image #".$event->image->id." from S3"); + $s3 = new S3($access, $secret); + $s3->deleteObject($bucket, "images/" . $event->image->hash); + $s3->deleteObject($bucket, "thumbs/" . $event->image->hash); + } + } } - diff --git a/ext/arrowkey_navigation/main.php b/ext/arrowkey_navigation/main.php index 01a504f7..209fbf04 100644 --- a/ext/arrowkey_navigation/main.php +++ b/ext/arrowkey_navigation/main.php @@ -8,35 +8,39 @@ * Documentation: * Simply enable this extention in the extention manager to enable arrow key navigation. */ -class ArrowkeyNavigation extends Extension { - /** - * Adds functionality for post/view on images. - */ - public function onDisplayingImage(DisplayingImageEvent $event) { - $prev_url = make_http(make_link("post/prev/".$event->image->id)); - $next_url = make_http(make_link("post/next/".$event->image->id)); - $this->add_arrowkeys_code($prev_url, $next_url); - } +class ArrowkeyNavigation extends Extension +{ + /** + * Adds functionality for post/view on images. + */ + public function onDisplayingImage(DisplayingImageEvent $event) + { + $prev_url = make_http(make_link("post/prev/".$event->image->id)); + $next_url = make_http(make_link("post/next/".$event->image->id)); + $this->add_arrowkeys_code($prev_url, $next_url); + } - /** - * Adds functionality for post/list. - */ - public function onPageRequest(PageRequestEvent $event) { - if($event->page_matches("post/list")) { - $pageinfo = $this->get_list_pageinfo($event); - $prev_url = make_http(make_link("post/list/".$pageinfo["prev"])); - $next_url = make_http(make_link("post/list/".$pageinfo["next"])); - $this->add_arrowkeys_code($prev_url, $next_url); - } - } + /** + * Adds functionality for post/list. + */ + public function onPageRequest(PageRequestEvent $event) + { + if ($event->page_matches("post/list")) { + $pageinfo = $this->get_list_pageinfo($event); + $prev_url = make_http(make_link("post/list/".$pageinfo["prev"])); + $next_url = make_http(make_link("post/list/".$pageinfo["next"])); + $this->add_arrowkeys_code($prev_url, $next_url); + } + } - /** - * Adds the javascript to the page with the given urls. - */ - private function add_arrowkeys_code(string $prev_url, string $next_url) { - global $page; + /** + * Adds the javascript to the page with the given urls. + */ + private function add_arrowkeys_code(string $prev_url, string $next_url) + { + global $page; - $page->add_html_header("", 60); - } + } - /** - * Returns info about the current page number. - */ - private function get_list_pageinfo(PageRequestEvent $event): array { - global $config, $database; + /** + * Returns info about the current page number. + */ + private function get_list_pageinfo(PageRequestEvent $event): array + { + global $config, $database; - // get the amount of images per page - $images_per_page = $config->get_int('index_images'); + // get the amount of images per page + $images_per_page = $config->get_int('index_images'); - // if there are no tags, use default - if (is_null($event->get_arg(1))){ - $prefix = ""; - $page_number = int_escape($event->get_arg(0)); - $total_pages = ceil($database->get_one( - "SELECT COUNT(*) FROM images") / $images_per_page); - } - else { // if there are tags, use pages with tags - $prefix = url_escape($event->get_arg(0)) . "/"; - $page_number = int_escape($event->get_arg(1)); - $total_pages = ceil($database->get_one( - "SELECT count FROM tags WHERE tag=:tag", - array("tag"=>$event->get_arg(0))) / $images_per_page); - } + // if there are no tags, use default + if (is_null($event->get_arg(1))) { + $prefix = ""; + $page_number = int_escape($event->get_arg(0)); + $total_pages = ceil($database->get_one( + "SELECT COUNT(*) FROM images" + ) / $images_per_page); + } else { // if there are tags, use pages with tags + $prefix = url_escape($event->get_arg(0)) . "/"; + $page_number = int_escape($event->get_arg(1)); + $total_pages = ceil($database->get_one( + "SELECT count FROM tags WHERE tag=:tag", + ["tag"=>$event->get_arg(0)] + ) / $images_per_page); + } - // creates previous & next values - // When previous first page, go to last page - if ($page_number <= 1) $prev = $total_pages; - else $prev = $page_number-1; - if ($page_number >= $total_pages) $next = 1; - else $next = $page_number+1; + // creates previous & next values + // When previous first page, go to last page + if ($page_number <= 1) { + $prev = $total_pages; + } else { + $prev = $page_number-1; + } + if ($page_number >= $total_pages) { + $next = 1; + } else { + $next = $page_number+1; + } - // Create return array - $pageinfo = array( - "prev" => $prefix.$prev, - "next" => $prefix.$next, - ); + // Create return array + $pageinfo = [ + "prev" => $prefix.$prev, + "next" => $prefix.$next, + ]; - return $pageinfo; - } + return $pageinfo; + } } - diff --git a/ext/artists/main.php b/ext/artists/main.php index c2f0da73..bb1343d3 100644 --- a/ext/artists/main.php +++ b/ext/artists/main.php @@ -8,49 +8,56 @@ * Documentation: * */ -class AuthorSetEvent extends Event { - /** @var \Image */ - public $image; - /** @var \User */ - public $user; - /** @var string */ - public $author; +class AuthorSetEvent extends Event +{ + /** @var \Image */ + public $image; + /** @var \User */ + public $user; + /** @var string */ + public $author; - public function __construct(Image $image, User $user, string $author) { + public function __construct(Image $image, User $user, string $author) + { $this->image = $image; $this->user = $user; $this->author = $author; } } -class Artists extends Extension { - public function onImageInfoSet(ImageInfoSetEvent $event) { +class Artists extends Extension +{ + public function onImageInfoSet(ImageInfoSetEvent $event) + { global $user; - if (isset($_POST["tag_edit__author"])) { - send_event(new AuthorSetEvent($event->image, $user, $_POST["tag_edit__author"])); - } - } + if (isset($_POST["tag_edit__author"])) { + send_event(new AuthorSetEvent($event->image, $user, $_POST["tag_edit__author"])); + } + } - public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event) { + public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event) + { global $user; $artistName = $this->get_artistName_by_imageID($event->image->id); - if(!$user->is_anonymous()) { + if (!$user->is_anonymous()) { $event->add_part($this->theme->get_author_editor_html($artistName), 42); } - } + } - public function onSearchTermParse(SearchTermParseEvent $event) { - $matches = array(); - if(preg_match("/^author[=|:](.*)$/i", $event->term, $matches)) { - $char = $matches[1]; - $event->add_querylet(new Querylet("Author = :author_char", array("author_char"=>$char))); - } - } + public function onSearchTermParse(SearchTermParseEvent $event) + { + $matches = []; + if (preg_match("/^author[=|:](.*)$/i", $event->term, $matches)) { + $char = $matches[1]; + $event->add_querylet(new Querylet("Author = :author_char", ["author_char"=>$char])); + } + } - public function onInitExt(InitExtEvent $event) { - global $config, $database; + public function onInitExt(InitExtEvent $event) + { + global $config, $database; - if ($config->get_int("ext_artists_version") < 1) { + if ($config->get_int("ext_artists_version") < 1) { $database->create_table("artists", " id SCORE_AIPK, user_id INTEGER NOT NULL, @@ -60,7 +67,7 @@ class Artists extends Extension { notes TEXT, FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE "); - + $database->create_table("artist_members", " id SCORE_AIPK, artist_id INTEGER NOT NULL, @@ -100,47 +107,53 @@ class Artists extends Extension { } } - public function onAuthorSet(AuthorSetEvent $event) { + public function onAuthorSet(AuthorSetEvent $event) + { global $database; $author = strtolower($event->author); - if (strlen($author) === 0 || strpos($author, " ")) - return; + if (strlen($author) === 0 || strpos($author, " ")) { + return; + } $paddedAuthor = str_replace(" ", "_", $author); - $artistID = NULL; - if ($this->artist_exists($author)) + $artistID = null; + if ($this->artist_exists($author)) { $artistID = $this->get_artist_id($author); + } - if (is_null($artistID) && $this->alias_exists_by_name($paddedAuthor)) + if (is_null($artistID) && $this->alias_exists_by_name($paddedAuthor)) { $artistID = $this->get_artistID_by_aliasName($paddedAuthor); + } - if (is_null($artistID) && $this->member_exists_by_name($paddedAuthor)) + if (is_null($artistID) && $this->member_exists_by_name($paddedAuthor)) { $artistID = $this->get_artistID_by_memberName($paddedAuthor); + } - if (is_null($artistID) && $this->url_exists_by_url($author)) + if (is_null($artistID) && $this->url_exists_by_url($author)) { $artistID = $this->get_artistID_by_url($author); + } if (!is_null($artistID)) { $artistName = $this->get_artistName_by_artistID($artistID); - } - else { + } else { $this->save_new_artist($author, ""); $artistName = $author; } $database->execute( "UPDATE images SET author = ? WHERE id = ?", - array($artistName, $event->image->id) + [$artistName, $event->image->id] ); } - public function onPageRequest(PageRequestEvent $event) { + public function onPageRequest(PageRequestEvent $event) + { global $page, $user; - if($event->page_matches("artist")) { - switch($event->get_arg(0)) { + if ($event->page_matches("artist")) { + switch ($event->get_arg(0)) { //*************ARTIST SECTION************** case "list": { @@ -150,10 +163,9 @@ class Artists extends Extension { } case "new": { - if(!$user->is_anonymous()) { - $this->theme->new_artist_composer(); - } - else { + if (!$user->is_anonymous()) { + $this->theme->new_artist_composer(); + } else { $this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist."); } break; @@ -166,17 +178,15 @@ class Artists extends Extension { } case "create": { - if(!$user->is_anonymous()) { + if (!$user->is_anonymous()) { $newArtistID = $this->add_artist(); if ($newArtistID == -1) { $this->theme->display_error(400, "Error", "Error when entering artist data."); - } - else { + } else { $page->set_mode("redirect"); $page->set_redirect(make_link("artist/view/".$newArtistID)); } - } - else { + } else { $this->theme->display_error(401, "Error", "You must be registered and logged in to create a new artist."); } break; @@ -192,7 +202,7 @@ class Artists extends Extension { $userIsLogged = !$user->is_anonymous(); $userIsAdmin = $user->is_admin(); - + $images = Image::find_images(0, 4, Tag::explode($artist['name'])); $this->theme->show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin); @@ -201,9 +211,9 @@ class Artists extends Extension { //$this->theme->show_new_member_composer($artistID); //$this->theme->show_new_url_composer($artistID); } - + $this->theme->sidebar_options("editor", $artistID, $userIsAdmin); - + break; } @@ -214,14 +224,13 @@ class Artists extends Extension { $aliases = $this->get_alias($artistID); $members = $this->get_members($artistID); $urls = $this->get_urls($artistID); - - if(!$user->is_anonymous()) { - $this->theme->show_artist_editor($artist, $aliases, $members, $urls); - + + if (!$user->is_anonymous()) { + $this->theme->show_artist_editor($artist, $aliases, $members, $urls); + $userIsAdmin = $user->is_admin(); $this->theme->sidebar_options("editor", $artistID, $userIsAdmin); - } - else { + } else { $this->theme->display_error(401, "Error", "You must be registered and logged in to edit an artist."); } break; @@ -277,8 +286,7 @@ class Artists extends Extension { //***********ALIAS SECTION *********************** case "alias": { - switch ($event->get_arg(1)) - { + switch ($event->get_arg(1)) { case "add": { $artistID = $_POST['artistID']; @@ -319,8 +327,7 @@ class Artists extends Extension { //**************** URLS SECTION ********************** case "url": { - switch ($event->get_arg(1)) - { + switch ($event->get_arg(1)) { case "add": { $artistID = $_POST['artistID']; @@ -360,8 +367,7 @@ class Artists extends Extension { //******************* MEMBERS SECTION ********************* case "member": { - switch ($event->get_arg(1)) - { + switch ($event->get_arg(1)) { case "add": { $artistID = $_POST['artistID']; @@ -402,116 +408,134 @@ class Artists extends Extension { } } - private function get_artistName_by_imageID(int $imageID): string { + private function get_artistName_by_imageID(int $imageID): string + { global $database; - $result = $database->get_row("SELECT author FROM images WHERE id = ?", array($imageID)); + $result = $database->get_row("SELECT author FROM images WHERE id = ?", [$imageID]); return stripslashes($result['author']); } - private function url_exists_by_url(string $url): bool { + private function url_exists_by_url(string $url): bool + { global $database; - $result = $database->get_one("SELECT COUNT(1) FROM artist_urls WHERE url = ?", array($url)); + $result = $database->get_one("SELECT COUNT(1) FROM artist_urls WHERE url = ?", [$url]); return ($result != 0); } - private function member_exists_by_name(string $member): bool { + private function member_exists_by_name(string $member): bool + { global $database; - $result = $database->get_one("SELECT COUNT(1) FROM artist_members WHERE name = ?", array($member)); + $result = $database->get_one("SELECT COUNT(1) FROM artist_members WHERE name = ?", [$member]); return ($result != 0); } - private function alias_exists_by_name(string $alias): bool { + private function alias_exists_by_name(string $alias): bool + { global $database; - $result = $database->get_one("SELECT COUNT(1) FROM artist_alias WHERE alias = ?", array($alias)); + $result = $database->get_one("SELECT COUNT(1) FROM artist_alias WHERE alias = ?", [$alias]); return ($result != 0); } - private function alias_exists(int $artistID, string $alias): bool { + private function alias_exists(int $artistID, string $alias): bool + { global $database; $result = $database->get_one( "SELECT COUNT(1) FROM artist_alias WHERE artist_id = ? AND alias = ?", - array($artistID, $alias) + [$artistID, $alias] ); return ($result != 0); } - private function get_artistID_by_url(string $url): int { + private function get_artistID_by_url(string $url): int + { global $database; - return $database->get_one("SELECT artist_id FROM artist_urls WHERE url = ?", array($url)); + return $database->get_one("SELECT artist_id FROM artist_urls WHERE url = ?", [$url]); } - private function get_artistID_by_memberName(string $member): int { + private function get_artistID_by_memberName(string $member): int + { global $database; - return $database->get_one("SELECT artist_id FROM artist_members WHERE name = ?", array($member)); + return $database->get_one("SELECT artist_id FROM artist_members WHERE name = ?", [$member]); } - private function get_artistName_by_artistID(int $artistID): string { + private function get_artistName_by_artistID(int $artistID): string + { global $database; - return $database->get_one("SELECT name FROM artists WHERE id = ?", array($artistID)); + return $database->get_one("SELECT name FROM artists WHERE id = ?", [$artistID]); } - private function get_artistID_by_aliasID(int $aliasID): int { + private function get_artistID_by_aliasID(int $aliasID): int + { global $database; - return $database->get_one("SELECT artist_id FROM artist_alias WHERE id = ?", array($aliasID)); + return $database->get_one("SELECT artist_id FROM artist_alias WHERE id = ?", [$aliasID]); } - private function get_artistID_by_memberID(int $memberID): int { + private function get_artistID_by_memberID(int $memberID): int + { global $database; - return $database->get_one("SELECT artist_id FROM artist_members WHERE id = ?", array($memberID)); + return $database->get_one("SELECT artist_id FROM artist_members WHERE id = ?", [$memberID]); } - private function get_artistID_by_urlID(int $urlID): int { + private function get_artistID_by_urlID(int $urlID): int + { global $database; - return $database->get_one("SELECT artist_id FROM artist_urls WHERE id = ?", array($urlID)); + return $database->get_one("SELECT artist_id FROM artist_urls WHERE id = ?", [$urlID]); } - private function delete_alias(int $aliasID) { + private function delete_alias(int $aliasID) + { global $database; - $database->execute("DELETE FROM artist_alias WHERE id = ?", array($aliasID)); + $database->execute("DELETE FROM artist_alias WHERE id = ?", [$aliasID]); } - private function delete_url(int $urlID) { + private function delete_url(int $urlID) + { global $database; - $database->execute("DELETE FROM artist_urls WHERE id = ?", array($urlID)); + $database->execute("DELETE FROM artist_urls WHERE id = ?", [$urlID]); } - private function delete_member(int $memberID) { + private function delete_member(int $memberID) + { global $database; - $database->execute("DELETE FROM artist_members WHERE id = ?", array($memberID)); + $database->execute("DELETE FROM artist_members WHERE id = ?", [$memberID]); } - private function get_alias_by_id(int $aliasID): array { + private function get_alias_by_id(int $aliasID): array + { global $database; - $result = $database->get_row("SELECT * FROM artist_alias WHERE id = ?", array($aliasID)); + $result = $database->get_row("SELECT * FROM artist_alias WHERE id = ?", [$aliasID]); $result["alias"] = stripslashes($result["alias"]); return $result; } - private function get_url_by_id(int $urlID): array { + private function get_url_by_id(int $urlID): array + { global $database; - $result = $database->get_row("SELECT * FROM artist_urls WHERE id = ?", array($urlID)); + $result = $database->get_row("SELECT * FROM artist_urls WHERE id = ?", [$urlID]); $result["url"] = stripslashes($result["url"]); return $result; } - private function get_member_by_id(int $memberID): array { + private function get_member_by_id(int $memberID): array + { global $database; - $result = $database->get_row("SELECT * FROM artist_members WHERE id = ?", array($memberID)); + $result = $database->get_row("SELECT * FROM artist_members WHERE id = ?", [$memberID]); $result["name"] = stripslashes($result["name"]); return $result; } - private function update_artist() { + private function update_artist() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ 'id' => 'int', 'name' => 'string,lower', 'notes' => 'string,trim,nullify', 'aliases' => 'string,trim,nullify', 'aliasesIDs' => 'string,trim,nullify', 'members' => 'string,trim,nullify', - )); + ]); $artistID = $inputs['id']; $name = $inputs['name']; $notes = $inputs['notes']; @@ -526,66 +550,67 @@ class Artists extends Extension { $urlsAsString = $inputs["urls"]; $urlsIDsAsString = $inputs["urlsIDs"]; - if(strpos($name, " ")) + if (strpos($name, " ")) { return; + } global $database; $database->execute( "UPDATE artists SET name = ?, notes = ?, updated = now(), user_id = ? WHERE id = ? ", - array($name, $notes, $userID, $artistID) + [$name, $notes, $userID, $artistID] ); // ALIAS MATCHING SECTION $i = 0; - $aliasesAsArray = is_null($aliasesAsString) ? array() : explode(" ", $aliasesAsString); - $aliasesIDsAsArray = is_null($aliasesIDsAsString) ? array() : explode(" ", $aliasesIDsAsString); - while ($i < count($aliasesAsArray)) - { + $aliasesAsArray = is_null($aliasesAsString) ? [] : explode(" ", $aliasesAsString); + $aliasesIDsAsArray = is_null($aliasesIDsAsString) ? [] : explode(" ", $aliasesIDsAsString); + while ($i < count($aliasesAsArray)) { // if an alias was updated - if ($i < count($aliasesIDsAsArray)) + if ($i < count($aliasesIDsAsArray)) { $this->save_existing_alias($aliasesIDsAsArray[$i], $aliasesAsArray[$i], $userID); - else + } else { // if we already updated all, save new ones $this->save_new_alias($artistID, $aliasesAsArray[$i], $userID); + } $i++; } // if we have more ids than alias, then some alias have been deleted -- delete them from db - while ($i < count($aliasesIDsAsArray)) + while ($i < count($aliasesIDsAsArray)) { $this->delete_alias($aliasesIDsAsArray[$i++]); + } // MEMBERS MATCHING SECTION $i = 0; - $membersAsArray = is_null($membersAsString) ? array() : explode(" ", $membersAsString); - $membersIDsAsArray = is_null($membersIDsAsString) ? array() : explode(" ", $membersIDsAsString); - while ($i < count($membersAsArray)) - { + $membersAsArray = is_null($membersAsString) ? [] : explode(" ", $membersAsString); + $membersIDsAsArray = is_null($membersIDsAsString) ? [] : explode(" ", $membersIDsAsString); + while ($i < count($membersAsArray)) { // if a member was updated - if ($i < count($membersIDsAsArray)) + if ($i < count($membersIDsAsArray)) { $this->save_existing_member($membersIDsAsArray[$i], $membersAsArray[$i], $userID); - else + } else { // if we already updated all, save new ones $this->save_new_member($artistID, $membersAsArray[$i], $userID); + } $i++; } // if we have more ids than members, then some members have been deleted -- delete them from db - while ($i < count($membersIDsAsArray)) + while ($i < count($membersIDsAsArray)) { $this->delete_member($membersIDsAsArray[$i++]); + } // URLS MATCHING SECTION $i = 0; $urlsAsString = str_replace("\r\n", "\n", $urlsAsString); $urlsAsString = str_replace("\n\r", "\n", $urlsAsString); - $urlsAsArray = is_null($urlsAsString) ? array() : explode("\n", $urlsAsString); - $urlsIDsAsArray = is_null($urlsIDsAsString) ? array() : explode(" ", $urlsIDsAsString); - while ($i < count($urlsAsArray)) - { + $urlsAsArray = is_null($urlsAsString) ? [] : explode("\n", $urlsAsString); + $urlsIDsAsArray = is_null($urlsIDsAsString) ? [] : explode(" ", $urlsIDsAsString); + while ($i < count($urlsAsArray)) { // if an URL was updated if ($i < count($urlsIDsAsArray)) { $this->save_existing_url($urlsIDsAsArray[$i], $urlsAsArray[$i], $userID); - } - else { + } else { $this->save_new_url($artistID, $urlsAsArray[$i], $userID); } @@ -593,74 +618,83 @@ class Artists extends Extension { } // if we have more ids than urls, then some urls have been deleted -- delete them from db - while ($i < count($urlsIDsAsArray)) + while ($i < count($urlsIDsAsArray)) { $this->delete_url($urlsIDsAsArray[$i++]); + } } - private function update_alias() { + private function update_alias() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ "aliasID" => "int", "alias" => "string,lower", - )); + ]); $this->save_existing_alias($inputs['aliasID'], $inputs['alias'], $user->id); } - private function save_existing_alias(int $aliasID, string $alias, int $userID) { + private function save_existing_alias(int $aliasID, string $alias, int $userID) + { global $database; $database->execute( "UPDATE artist_alias SET alias = ?, updated = now(), user_id = ? WHERE id = ? ", - array($alias, $userID, $aliasID) + [$alias, $userID, $aliasID] ); } - private function update_url() { + private function update_url() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ "urlID" => "int", "url" => "string", - )); + ]); $this->save_existing_url($inputs['urlID'], $inputs['url'], $user->id); } - private function save_existing_url(int $urlID, string $url, int $userID) { + private function save_existing_url(int $urlID, string $url, int $userID) + { global $database; $database->execute( "UPDATE artist_urls SET url = ?, updated = now(), user_id = ? WHERE id = ?", - array($url, $userID, $urlID) + [$url, $userID, $urlID] ); } - private function update_member() { + private function update_member() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ "memberID" => "int", "name" => "string,lower", - )); + ]); $this->save_existing_member($inputs['memberID'], $inputs['name'], $user->id); } - private function save_existing_member(int $memberID, string $memberName, int $userID) { + private function save_existing_member(int $memberID, string $memberName, int $userID) + { global $database; $database->execute( "UPDATE artist_members SET name = ?, updated = now(), user_id = ? WHERE id = ?", - array($memberName, $userID, $memberID) + [$memberName, $userID, $memberID] ); } - private function add_artist(){ + private function add_artist() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ "name" => "string,lower", "notes" => "string,optional", "aliases" => "string,lower,optional", "members" => "string,lower,optional", "urls" => "string,optional" - )); + ]); $name = $inputs["name"]; - if(strpos($name, " ")) + if (strpos($name, " ")) { return -1; + } $notes = $inputs["notes"]; @@ -672,26 +706,29 @@ class Artists extends Extension { //$artistID = ""; //// WE CHECK IF THE ARTIST ALREADY EXISTS ON DATABASE; IF NOT WE CREATE - if(!$this->artist_exists($name)) { + if (!$this->artist_exists($name)) { $artistID = $this->save_new_artist($name, $notes); log_info("artists", "Artist {$artistID} created by {$user->name}"); - } - else { + } else { $artistID = $this->get_artist_id($name); } if (!is_null($aliases)) { $aliasArray = explode(" ", $aliases); - foreach($aliasArray as $alias) - if (!$this->alias_exists($artistID, $alias)) + foreach ($aliasArray as $alias) { + if (!$this->alias_exists($artistID, $alias)) { $this->save_new_alias($artistID, $alias, $userID); + } + } } if (!is_null($members)) { $membersArray = explode(" ", $members); - foreach ($membersArray as $member) - if (!$this->member_exists($artistID, $member)) + foreach ($membersArray as $member) { + if (!$this->member_exists($artistID, $member)) { $this->save_new_member($artistID, $member, $userID); + } + } } if (!is_null($urls)) { @@ -700,36 +737,41 @@ class Artists extends Extension { $urls = str_replace("\n\r", "\n", $urls); $urlsArray = explode("\n", $urls); - foreach ($urlsArray as $url) - if (!$this->url_exists($artistID, $url)) + foreach ($urlsArray as $url) { + if (!$this->url_exists($artistID, $url)) { $this->save_new_url($artistID, $url, $userID); + } + } } return $artistID; } - private function save_new_artist(string $name, string $notes): int { + private function save_new_artist(string $name, string $notes): int + { global $database, $user; $database->execute(" INSERT INTO artists (user_id, name, notes, created, updated) VALUES (?, ?, ?, now(), now()) - ", array($user->id, $name, $notes)); + ", [$user->id, $name, $notes]); return $database->get_last_insert_id('artists_id_seq'); } - private function artist_exists(string $name): bool { + private function artist_exists(string $name): bool + { global $database; $result = $database->get_one( "SELECT COUNT(1) FROM artists WHERE name = ?", - array($name) + [$name] ); return ($result != 0); } - private function get_artist(int $artistID): array { + private function get_artist(int $artistID): array + { global $database; $result = $database->get_row( "SELECT * FROM artists WHERE id = ?", - array($artistID) + [$artistID] ); $result["name"] = stripslashes($result["name"]); @@ -738,14 +780,15 @@ class Artists extends Extension { return $result; } - private function get_members(int $artistID): array { + private function get_members(int $artistID): array + { global $database; $result = $database->get_all( "SELECT * FROM artist_members WHERE artist_id = ?", - array($artistID) + [$artistID] ); - - $num = count($result); + + $num = count($result); for ($i = 0 ; $i < $num ; $i++) { $result[$i]["name"] = stripslashes($result[$i]["name"]); } @@ -753,14 +796,15 @@ class Artists extends Extension { return $result; } - private function get_urls(int $artistID): array { + private function get_urls(int $artistID): array + { global $database; $result = $database->get_all( "SELECT id, url FROM artist_urls WHERE artist_id = ?", - array($artistID) + [$artistID] ); - - $num = count($result); + + $num = count($result); for ($i = 0 ; $i < $num ; $i++) { $result[$i]["url"] = stripslashes($result[$i]["url"]); } @@ -768,43 +812,46 @@ class Artists extends Extension { return $result; } - private function get_artist_id(string $name): int { - global $database; - return (int)$database->get_one( + private function get_artist_id(string $name): int + { + global $database; + return (int)$database->get_one( "SELECT id FROM artists WHERE name = ?", - array($name) + [$name] ); - } + } - private function get_artistID_by_aliasName(string $alias): int { + private function get_artistID_by_aliasName(string $alias): int + { global $database; return (int)$database->get_one( "SELECT artist_id FROM artist_alias WHERE alias = ?", - array($alias) + [$alias] ); } - private function delete_artist(int $artistID) { + private function delete_artist(int $artistID) + { global $database; $database->execute( "DELETE FROM artists WHERE id = ? ", - array($artistID) + [$artistID] ); - } - - /* - * HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION - */ - private function get_listing(Page $page, PageRequestEvent $event) - { - global $config, $database; + } + + /* + * HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION + */ + private function get_listing(Page $page, PageRequestEvent $event) + { + global $config, $database; - $pageNumber = clamp($event->get_arg(1), 1, null) - 1; - $artistsPerPage = $config->get_int("artistsPerPage"); + $pageNumber = clamp($event->get_arg(1), 1, null) - 1; + $artistsPerPage = $config->get_int("artistsPerPage"); - $listing = $database->get_all( - " + $listing = $database->get_all( + " ( SELECT a.id, a.user_id, a.name, u.name AS user_name, COALESCE(t.count, 0) AS posts , 'artist' as type, a.id AS artist_id, a.name AS artist_name, a.updated @@ -850,21 +897,22 @@ class Artists extends Extension { ) ORDER BY updated DESC LIMIT ?, ? - ", array( + ", + [ $pageNumber * $artistsPerPage , $artistsPerPage - )); - - $number_of_listings = count($listing); + ] + ); + + $number_of_listings = count($listing); - for ($i = 0 ; $i < $number_of_listings ; $i++) - { - $listing[$i]["name"] = stripslashes($listing[$i]["name"]); - $listing[$i]["user_name"] = stripslashes($listing[$i]["user_name"]); - $listing[$i]["artist_name"] = stripslashes($listing[$i]["artist_name"]); - } + for ($i = 0 ; $i < $number_of_listings ; $i++) { + $listing[$i]["name"] = stripslashes($listing[$i]["name"]); + $listing[$i]["user_name"] = stripslashes($listing[$i]["user_name"]); + $listing[$i]["artist_name"] = stripslashes($listing[$i]["artist_name"]); + } - $count = $database->get_one(" + $count = $database->get_one(" SELECT COUNT(1) FROM artists AS a LEFT OUTER JOIN artist_members AS am @@ -873,107 +921,122 @@ class Artists extends Extension { ON a.id = aa.artist_id "); - $totalPages = ceil ($count / $artistsPerPage); + $totalPages = ceil($count / $artistsPerPage); - $this->theme->list_artists($listing, $pageNumber + 1, $totalPages); - } - - /* - * HERE WE ADD AN ALIAS - */ - private function add_urls() { + $this->theme->list_artists($listing, $pageNumber + 1, $totalPages); + } + + /* + * HERE WE ADD AN ALIAS + */ + private function add_urls() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ "artistID" => "int", "urls" => "string", - )); + ]); $artistID = $inputs["artistID"]; $urls = explode("\n", $inputs["urls"]); - foreach ($urls as $url) - if (!$this->url_exists($artistID, $url)) + foreach ($urls as $url) { + if (!$this->url_exists($artistID, $url)) { $this->save_new_url($artistID, $url, $user->id); + } + } } - private function save_new_url(int $artistID, string $url, int $userID) { + private function save_new_url(int $artistID, string $url, int $userID) + { global $database; $database->execute( "INSERT INTO artist_urls (artist_id, created, updated, url, user_id) VALUES (?, now(), now(), ?, ?)", - array($artistID, $url, $userID) + [$artistID, $url, $userID] ); } - private function add_alias() { + private function add_alias() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ "artistID" => "int", "aliases" => "string,lower", - )); + ]); $artistID = $inputs["artistID"]; $aliases = explode(" ", $inputs["aliases"]); - foreach ($aliases as $alias) - if (!$this->alias_exists($artistID, $alias)) + foreach ($aliases as $alias) { + if (!$this->alias_exists($artistID, $alias)) { $this->save_new_alias($artistID, $alias, $user->id); + } + } } - private function save_new_alias(int $artistID, string $alias, int $userID) { + private function save_new_alias(int $artistID, string $alias, int $userID) + { global $database; $database->execute( "INSERT INTO artist_alias (artist_id, created, updated, alias, user_id) VALUES (?, now(), now(), ?, ?)", - array($artistID, $alias, $userID) + [$artistID, $alias, $userID] ); } - private function add_members() { + private function add_members() + { global $user; - $inputs = validate_input(array( + $inputs = validate_input([ "artistID" => "int", "members" => "string,lower", - )); + ]); $artistID = $inputs["artistID"]; $members = explode(" ", $inputs["members"]); - foreach ($members as $member) - if (!$this->member_exists($artistID, $member)) + foreach ($members as $member) { + if (!$this->member_exists($artistID, $member)) { $this->save_new_member($artistID, $member, $user->id); + } + } } - private function save_new_member(int $artistID, string $member, int $userID) { + private function save_new_member(int $artistID, string $member, int $userID) + { global $database; $database->execute( "INSERT INTO artist_members (artist_id, name, created, updated, user_id) VALUES (?, ?, now(), now(), ?)", - array($artistID, $member, $userID) + [$artistID, $member, $userID] ); } - private function member_exists(int $artistID, string $member): bool { + private function member_exists(int $artistID, string $member): bool + { global $database; $result = $database->get_one( "SELECT COUNT(1) FROM artist_members WHERE artist_id = ? AND name = ?", - array($artistID, $member) + [$artistID, $member] ); return ($result != 0); } - private function url_exists(int $artistID, string $url): bool { + private function url_exists(int $artistID, string $url): bool + { global $database; $result = $database->get_one( "SELECT COUNT(1) FROM artist_urls WHERE artist_id = ? AND url = ?", - array($artistID, $url) + [$artistID, $url] ); return ($result != 0); } - /** - * HERE WE GET THE INFO OF THE ALIAS - */ - private function get_alias(int $artistID): array { + /** + * HERE WE GET THE INFO OF THE ALIAS + */ + private function get_alias(int $artistID): array + { global $database; $result = $database->get_all(" @@ -981,11 +1044,11 @@ class Artists extends Extension { FROM artist_alias WHERE artist_id = ? ORDER BY alias ASC - ", array($artistID)); + ", [$artistID]); for ($i = 0 ; $i < count($result) ; $i++) { $result[$i]["alias_name"] = stripslashes($result[$i]["alias_name"]); } return $result; - } + } } diff --git a/ext/artists/test.php b/ext/artists/test.php index 9cbfdf5e..23ee4cfb 100644 --- a/ext/artists/test.php +++ b/ext/artists/test.php @@ -1,9 +1,10 @@ get_page("post/list/author=bob/1"); - #$this->assert_response(200); - } +class ArtistTest extends ShimmiePHPUnitTestCase +{ + public function testSearch() + { + # FIXME: check that the results are there + $this->get_page("post/list/author=bob/1"); + #$this->assert_response(200); + } } - diff --git a/ext/artists/theme.php b/ext/artists/theme.php index 750209f4..f9ebb745 100644 --- a/ext/artists/theme.php +++ b/ext/artists/theme.php @@ -1,8 +1,10 @@Author @@ -11,22 +13,23 @@ class ArtistsTheme extends Themelet { "; - } + } - public function sidebar_options(string $mode, ?int $artistID=NULL, $is_admin=FALSE): bool { - global $page, $user; + public function sidebar_options(string $mode, ?int $artistID=null, $is_admin=false): bool + { + global $page, $user; - $html = ""; + $html = ""; - if($mode == "neutral"){ - $html = ""; - } - - if($mode == "editor"){ - $html = " @@ -36,16 +39,16 @@ class ArtistsTheme extends Themelet { "; - - if($is_admin){ - $html .= ""; - } - - $html .= ""; - } + } - if($html) $page->add_block(new Block("Manage Artists", $html, "left", 10)); - } + if ($html) { + $page->add_block(new Block("Manage Artists", $html, "left", 10)); + } + } - public function show_artist_editor($artist, $aliases, $members, $urls) { - global $user; + public function show_artist_editor($artist, $aliases, $members, $urls) + { + global $user; - $artistName = $artist['name']; - $artistNotes = $artist['notes']; - $artistID = $artist['id']; + $artistName = $artist['name']; + $artistNotes = $artist['notes']; + $artistID = $artist['id']; - // aliases - $aliasesString = ""; - $aliasesIDsString = ""; - foreach ($aliases as $alias) { - $aliasesString .= $alias["alias_name"]." "; - $aliasesIDsString .= $alias["alias_id"]." "; - } - $aliasesString = rtrim($aliasesString); - $aliasesIDsString = rtrim($aliasesIDsString); + // aliases + $aliasesString = ""; + $aliasesIDsString = ""; + foreach ($aliases as $alias) { + $aliasesString .= $alias["alias_name"]." "; + $aliasesIDsString .= $alias["alias_id"]." "; + } + $aliasesString = rtrim($aliasesString); + $aliasesIDsString = rtrim($aliasesIDsString); - // members - $membersString = ""; - $membersIDsString = ""; - foreach ($members as $member) { - $membersString .= $member["name"]." "; - $membersIDsString .= $member["id"]." "; - } - $membersString = rtrim($membersString); - $membersIDsString = rtrim($membersIDsString); + // members + $membersString = ""; + $membersIDsString = ""; + foreach ($members as $member) { + $membersString .= $member["name"]." "; + $membersIDsString .= $member["id"]." "; + } + $membersString = rtrim($membersString); + $membersIDsString = rtrim($membersIDsString); - // urls - $urlsString = ""; - $urlsIDsString = ""; - foreach ($urls as $url) { - $urlsString .= $url["url"]."\n"; - $urlsIDsString .= $url["id"]." "; - } - $urlsString = substr($urlsString, 0, strlen($urlsString) -1); - $urlsIDsString = rtrim($urlsIDsString); + // urls + $urlsString = ""; + $urlsIDsString = ""; + foreach ($urls as $url) { + $urlsString .= $url["url"]."\n"; + $urlsIDsString .= $url["id"]." "; + } + $urlsString = substr($urlsString, 0, strlen($urlsString) -1); + $urlsIDsString = rtrim($urlsIDsString); - $html = ' + $html = ' "; - if($adminOptions) - $html .= " + if ($adminOptions) { + $html .= " ".make_form(make_link("note/delete_note"))." @@ -124,119 +131,120 @@ class NotesTheme extends Themelet {". + "
"; + $this->display_paginator($page, "note/updated", null, $pageNumber, $totalPages); + } - return $html; - } + public function display_history($histories, $pageNumber, $totalPages) + { + global $page; - public function display_histories($histories, $pageNumber, $totalPages) { - global $page; + $html = $this->get_history($histories); - $html = $this->get_history($histories); + $page->set_title("Note History"); + $page->set_heading("Note History"); + $page->add_block(new Block("Note History", $html, "main", 10)); - $page->set_title("Note Updates"); - $page->set_heading("Note Updates"); - $page->add_block(new Block("Note Updates", $html, "main", 10)); - - $this->display_paginator($page, "note/updated", null, $pageNumber, $totalPages); - } - - public function display_history($histories, $pageNumber, $totalPages) { - global $page; - - $html = $this->get_history($histories); - - $page->set_title("Note History"); - $page->set_heading("Note History"); - $page->add_block(new Block("Note History", $html, "main", 10)); - - $this->display_paginator($page, "note/updated", null, $pageNumber, $totalPages); - } + $this->display_paginator($page, "note/updated", null, $pageNumber, $totalPages); + } } diff --git a/ext/numeric_score/main.php b/ext/numeric_score/main.php index 649ab0c0..f15a9d37 100644 --- a/ext/numeric_score/main.php +++ b/ext/numeric_score/main.php @@ -10,186 +10,206 @@ * image's score is the sum of all votes. */ -class NumericScoreSetEvent extends Event { - public $image_id, $user, $score; +class NumericScoreSetEvent extends Event +{ + public $image_id; + public $user; + public $score; - public function __construct(int $image_id, User $user, int $score) { - $this->image_id = $image_id; - $this->user = $user; - $this->score = $score; - } + public function __construct(int $image_id, User $user, int $score) + { + $this->image_id = $image_id; + $this->user = $user; + $this->score = $score; + } } -class NumericScore extends Extension { - public function onInitExt(InitExtEvent $event) { - global $config; - if($config->get_int("ext_numeric_score_version", 0) < 1) { - $this->install(); - } - } +class NumericScore extends Extension +{ + public function onInitExt(InitExtEvent $event) + { + global $config; + if ($config->get_int("ext_numeric_score_version", 0) < 1) { + $this->install(); + } + } - public function onDisplayingImage(DisplayingImageEvent $event) { - global $user; - if(!$user->is_anonymous()) { - $this->theme->get_voter($event->image); - } - } + public function onDisplayingImage(DisplayingImageEvent $event) + { + global $user; + if (!$user->is_anonymous()) { + $this->theme->get_voter($event->image); + } + } - public function onUserPageBuilding(UserPageBuildingEvent $event) { - global $user; - if($user->can("edit_other_vote")) { - $this->theme->get_nuller($event->display_user); - } + public function onUserPageBuilding(UserPageBuildingEvent $event) + { + global $user; + if ($user->can("edit_other_vote")) { + $this->theme->get_nuller($event->display_user); + } - $u_id = url_escape($event->display_user->id); - $n_up = Image::count_images(array("upvoted_by_id={$event->display_user->id}")); - $link_up = make_link("post/list/upvoted_by_id=$u_id/1"); - $n_down = Image::count_images(array("downvoted_by_id={$event->display_user->id}")); - $link_down = make_link("post/list/downvoted_by_id=$u_id/1"); - $event->add_stats("$n_up Upvotes / $n_down Downvotes"); - } + $u_id = url_escape($event->display_user->id); + $n_up = Image::count_images(["upvoted_by_id={$event->display_user->id}"]); + $link_up = make_link("post/list/upvoted_by_id=$u_id/1"); + $n_down = Image::count_images(["downvoted_by_id={$event->display_user->id}"]); + $link_down = make_link("post/list/downvoted_by_id=$u_id/1"); + $event->add_stats("$n_up Upvotes / $n_down Downvotes"); + } - public function onPageRequest(PageRequestEvent $event) { - global $config, $database, $user, $page; + public function onPageRequest(PageRequestEvent $event) + { + global $config, $database, $user, $page; - if($event->page_matches("numeric_score_votes")) { - $image_id = int_escape($event->get_arg(0)); - $x = $database->get_all( - "SELECT users.name as username, user_id, score + if ($event->page_matches("numeric_score_votes")) { + $image_id = int_escape($event->get_arg(0)); + $x = $database->get_all( + "SELECT users.name as username, user_id, score FROM numeric_score_votes JOIN users ON numeric_score_votes.user_id=users.id WHERE image_id=?", - array($image_id)); - $html = "". + " ". + ""; - private function get_history($histories) { - global $user; + foreach ($histories as $history) { + $image_link = "".$history['image_id'].""; + $history_link = "".$history['note_id'].".".$history['review_id'].""; + $user_link = "".$history['user_name'].""; + $revert_link = "Revert"; - $html = "Image ". + "Note ". + "Body ". + "Updater ". + "Date "; - } - $this->display_paginator($page, "requests/list", null, $pageNumber, $totalPages); + if (!$user->is_anonymous()) { + $html .= "Action "; + } - $page->set_title("Note Requests"); - $page->set_heading("Note Requests"); - $page->add_block(new Block("Note Requests", $pool_images, "main", 20)); - } + $html .= "". - "
"; - foreach($histories as $history) { - $image_link = "".$history['image_id'].""; - $history_link = "".$history['note_id'].".".$history['review_id'].""; - $user_link = "".$history['user_name'].""; - $revert_link = "Revert"; + return $html; + } - $html .= "". - " Image ". - "Note ". - "Body ". - "Updater ". - "Date "; + $html .= "". + " ". - ""; + $html .= "".$image_link." ". + "".$history_link." ". + "".$history['note']." ". + "".$user_link." ". + "".autodate($history['date'])." "; - if(!$user->is_anonymous()){ - $html .= "Action "; - } + if (!$user->is_anonymous()) { + $html .= "".$revert_link." "; + } + } - $html .= "". - " ".$image_link." ". - "".$history_link." ". - "".$history['note']." ". - "".$user_link." ". - "".autodate($history['date'])." "; + public function display_histories($histories, $pageNumber, $totalPages) + { + global $page; - if(!$user->is_anonymous()){ - $html .= "".$revert_link." "; - } + $html = $this->get_history($histories); - } + $page->set_title("Note Updates"); + $page->set_heading("Note Updates"); + $page->add_block(new Block("Note Updates", $html, "main", 10)); - $html .= ""; - foreach($x as $vote) { - $html .= "
EOD; - $page->add_block(new Block("Write a PM", $html, "main", 50)); - } + $page->add_block(new Block("Write a PM", $html, "main", 50)); + } - public function display_message(Page $page, User $from, User $to, PM $pm) { - $this->display_composer($page, $to, $from, "Re: ".$pm->subject); - $page->set_title("Private Message"); - $page->set_heading(html_escape($pm->subject)); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Message from {$from->name}", format_text($pm->message), "main", 10)); - } + public function display_message(Page $page, User $from, User $to, PM $pm) + { + $this->display_composer($page, $to, $from, "Re: ".$pm->subject); + $page->set_title("Private Message"); + $page->set_heading(html_escape($pm->subject)); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Message from {$from->name}", format_text($pm->message), "main", 10)); + } } - diff --git a/ext/pm_triggers/main.php b/ext/pm_triggers/main.php index 7cb80013..40f6f87d 100644 --- a/ext/pm_triggers/main.php +++ b/ext/pm_triggers/main.php @@ -6,24 +6,26 @@ * Description: Send PMs in response to certain events (eg image deletion) */ -class PMTrigger extends Extension { - public function onImageDeletion(ImageDeletionEvent $event) { - $this->send( - $event->image->owner_id, - "[System] An image you uploaded has been deleted", - "Image le gone~ (#{$event->image->id}, {$event->image->get_tag_list()})" - ); - } +class PMTrigger extends Extension +{ + public function onImageDeletion(ImageDeletionEvent $event) + { + $this->send( + $event->image->owner_id, + "[System] An image you uploaded has been deleted", + "Image le gone~ (#{$event->image->id}, {$event->image->get_tag_list()})" + ); + } - private function send($to_id, $subject, $body) { - global $user; - send_event(new SendPMEvent(new PM( - $user->id, - $_SERVER["REMOTE_ADDR"], - $to_id, - $subject, - $body - ))); - } + private function send($to_id, $subject, $body) + { + global $user; + send_event(new SendPMEvent(new PM( + $user->id, + $_SERVER["REMOTE_ADDR"], + $to_id, + $subject, + $body + ))); + } } - diff --git a/ext/pools/main.php b/ext/pools/main.php index 5cc78db2..6fd35b9e 100644 --- a/ext/pools/main.php +++ b/ext/pools/main.php @@ -12,33 +12,36 @@ /** * This class is just a wrapper around SCoreException. */ -class PoolCreationException extends SCoreException { - /** @var string */ - public $error; +class PoolCreationException extends SCoreException +{ + /** @var string */ + public $error; - public function __construct(string $error) { - $this->error = $error; - } + public function __construct(string $error) + { + $this->error = $error; + } } -class Pools extends Extension { +class Pools extends Extension +{ + public function onInitExt(InitExtEvent $event) + { + global $config, $database; - public function onInitExt(InitExtEvent $event) { - global $config, $database; + // Set the defaults for the pools extension + $config->set_default_int("poolsMaxImportResults", 1000); + $config->set_default_int("poolsImagesPerPage", 20); + $config->set_default_int("poolsListsPerPage", 20); + $config->set_default_int("poolsUpdatedPerPage", 20); + $config->set_default_bool("poolsInfoOnViewImage", false); + $config->set_default_bool("poolsAdderOnViewImage", false); + $config->set_default_bool("poolsShowNavLinks", false); + $config->set_default_bool("poolsAutoIncrementOrder", false); - // Set the defaults for the pools extension - $config->set_default_int("poolsMaxImportResults", 1000); - $config->set_default_int("poolsImagesPerPage", 20); - $config->set_default_int("poolsListsPerPage", 20); - $config->set_default_int("poolsUpdatedPerPage", 20); - $config->set_default_bool("poolsInfoOnViewImage", false); - $config->set_default_bool("poolsAdderOnViewImage", false); - $config->set_default_bool("poolsShowNavLinks", false); - $config->set_default_bool("poolsAutoIncrementOrder", false); - - // Create the database tables - if ($config->get_int("ext_pools_version") < 1){ - $database->create_table("pools", " + // Create the database tables + if ($config->get_int("ext_pools_version") < 1) { + $database->create_table("pools", " id SCORE_AIPK, user_id INTEGER NOT NULL, public SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N, @@ -48,14 +51,14 @@ class Pools extends Extension { posts INTEGER NOT NULL DEFAULT 0, FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE "); - $database->create_table("pool_images", " + $database->create_table("pool_images", " pool_id INTEGER NOT NULL, image_id INTEGER NOT NULL, image_order INTEGER NOT NULL DEFAULT 0, FOREIGN KEY (pool_id) REFERENCES pools(id) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (image_id) REFERENCES images(id) ON UPDATE CASCADE ON DELETE CASCADE "); - $database->create_table("pool_history", " + $database->create_table("pool_history", " id SCORE_AIPK, pool_id INTEGER NOT NULL, user_id INTEGER NOT NULL, @@ -66,323 +69,330 @@ class Pools extends Extension { FOREIGN KEY (pool_id) REFERENCES pools(id) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE "); - $config->set_int("ext_pools_version", 3); + $config->set_int("ext_pools_version", 3); - log_info("pools", "extension installed"); - } + log_info("pools", "extension installed"); + } - if ($config->get_int("ext_pools_version") < 2){ - $database->Execute("ALTER TABLE pools ADD UNIQUE INDEX (title);"); - $database->Execute("ALTER TABLE pools ADD lastupdated TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;"); + if ($config->get_int("ext_pools_version") < 2) { + $database->Execute("ALTER TABLE pools ADD UNIQUE INDEX (title);"); + $database->Execute("ALTER TABLE pools ADD lastupdated TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;"); - $config->set_int("ext_pools_version", 3); // skip 2 - } - } + $config->set_int("ext_pools_version", 3); // skip 2 + } + } - // Add a block to the Board Config / Setup - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Pools"); - $sb->add_int_option("poolsMaxImportResults", "Max results on import: "); - $sb->add_int_option("poolsImagesPerPage", ""; - } - die($html); - } - else if($event->page_matches("numeric_score_vote") && $user->check_auth_token()) { - if(!$user->is_anonymous()) { - $image_id = int_escape($_POST['image_id']); - $char = $_POST['vote']; - $score = null; - if($char == "up") $score = 1; - else if($char == "null") $score = 0; - else if($char == "down") $score = -1; - if(!is_null($score) && $image_id>0) send_event(new NumericScoreSetEvent($image_id, $user, $score)); - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/view/$image_id")); - } - } - else if($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) { - if($user->can("edit_other_vote")) { - $image_id = int_escape($_POST['image_id']); - $database->execute( - "DELETE FROM numeric_score_votes WHERE image_id=?", - array($image_id)); - $database->execute( - "UPDATE images SET numeric_score=0 WHERE id=?", - array($image_id)); - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/view/$image_id")); - } - } - else if($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) { - if($user->can("edit_other_vote")) { - $this->delete_votes_by(int_escape($_POST['user_id'])); - $page->set_mode("redirect"); - $page->set_redirect(make_link()); - } - } - else if($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) { - //FIXME: popular_by isn't linked from anywhere - list($day, $month, $year) = array(date("d"), date("m"), date("Y")); + [$image_id] + ); + $html = " "; - $html .= "{$vote['username']}"; - $html .= " "; - $html .= $vote['score']; - $html .= " "; + foreach ($x as $vote) { + $html .= "
"; - $page->add_block(new Block("Private Messages", $html, "main", 40, "private-messages")); - } + $page->add_block(new Block("Private Messages", $html, "main", 40, "private-messages")); + } - public function display_composer(Page $page, User $from, User $to, $subject="") { - global $user; - $post_url = make_link("pm/send"); - $h_subject = html_escape($subject); - $to_id = $to->id; - $auth = $user->get_auth_html(); - $html = <<"; + } + die($html); + } elseif ($event->page_matches("numeric_score_vote") && $user->check_auth_token()) { + if (!$user->is_anonymous()) { + $image_id = int_escape($_POST['image_id']); + $char = $_POST['vote']; + $score = null; + if ($char == "up") { + $score = 1; + } elseif ($char == "null") { + $score = 0; + } elseif ($char == "down") { + $score = -1; + } + if (!is_null($score) && $image_id>0) { + send_event(new NumericScoreSetEvent($image_id, $user, $score)); + } + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/view/$image_id")); + } + } elseif ($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) { + if ($user->can("edit_other_vote")) { + $image_id = int_escape($_POST['image_id']); + $database->execute( + "DELETE FROM numeric_score_votes WHERE image_id=?", + [$image_id] + ); + $database->execute( + "UPDATE images SET numeric_score=0 WHERE id=?", + [$image_id] + ); + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/view/$image_id")); + } + } elseif ($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) { + if ($user->can("edit_other_vote")) { + $this->delete_votes_by(int_escape($_POST['user_id'])); + $page->set_mode("redirect"); + $page->set_redirect(make_link()); + } + } elseif ($event->page_matches("popular_by_day") || $event->page_matches("popular_by_month") || $event->page_matches("popular_by_year")) { + //FIXME: popular_by isn't linked from anywhere + list($day, $month, $year) = [date("d"), date("m"), date("Y")]; - if(!empty($_GET['day'])){ - $D = (int) $_GET['day']; - $day = clamp($D, 1, 31); - } - if(!empty($_GET['month'])){ - $M = (int) $_GET['month']; - $month = clamp($M, 1 ,12); - } - if(!empty($_GET['year'])){ - $Y = (int) $_GET['year']; - $year = clamp($Y, 1970, 2100); - } + if (!empty($_GET['day'])) { + $D = (int) $_GET['day']; + $day = clamp($D, 1, 31); + } + if (!empty($_GET['month'])) { + $M = (int) $_GET['month']; + $month = clamp($M, 1, 12); + } + if (!empty($_GET['year'])) { + $Y = (int) $_GET['year']; + $year = clamp($Y, 1970, 2100); + } - $totaldate = $year."/".$month."/".$day; + $totaldate = $year."/".$month."/".$day; - $sql = "SELECT id FROM images + $sql = "SELECT id FROM images WHERE EXTRACT(YEAR FROM posted) = :year "; - $args = array("limit" => $config->get_int("index_images"), "year" => $year); + $args = ["limit" => $config->get_int("index_images"), "year" => $year]; - if($event->page_matches("popular_by_day")){ - $sql .= - "AND EXTRACT(MONTH FROM posted) = :month + if ($event->page_matches("popular_by_day")) { + $sql .= + "AND EXTRACT(MONTH FROM posted) = :month AND EXTRACT(DAY FROM posted) = :day"; - $args = array_merge($args, array("month" => $month, "day" => $day)); - $dte = array($totaldate, date("F jS, Y", (strtotime($totaldate))), "\\y\\e\\a\\r\\=Y\\&\\m\\o\\n\\t\\h\\=m\\&\\d\\a\\y\\=d", "day"); - } - else if($event->page_matches("popular_by_month")){ - $sql .= "AND EXTRACT(MONTH FROM posted) = :month"; + $args = array_merge($args, ["month" => $month, "day" => $day]); + $dte = [$totaldate, date("F jS, Y", (strtotime($totaldate))), "\\y\\e\\a\\r\\=Y\\&\\m\\o\\n\\t\\h\\=m\\&\\d\\a\\y\\=d", "day"]; + } elseif ($event->page_matches("popular_by_month")) { + $sql .= "AND EXTRACT(MONTH FROM posted) = :month"; - $args = array_merge($args, array("month" => $month)); - $dte = array($totaldate, date("F Y", (strtotime($totaldate))), "\\y\\e\\a\\r\\=Y\\&\\m\\o\\n\\t\\h\\=m", "month"); - } - else if($event->page_matches("popular_by_year")){ - $dte = array($totaldate, $year, "\\y\\e\\a\\r\=Y", "year"); - } - else { - // this should never happen due to the fact that the page event is already matched against earlier. - throw new UnexpectedValueException("Error: Invalid page event."); - } - $sql .= " AND NOT numeric_score=0 ORDER BY numeric_score DESC LIMIT :limit OFFSET 0"; + $args = array_merge($args, ["month" => $month]); + $dte = [$totaldate, date("F Y", (strtotime($totaldate))), "\\y\\e\\a\\r\\=Y\\&\\m\\o\\n\\t\\h\\=m", "month"]; + } elseif ($event->page_matches("popular_by_year")) { + $dte = [$totaldate, $year, "\\y\\e\\a\\r\=Y", "year"]; + } else { + // this should never happen due to the fact that the page event is already matched against earlier. + throw new UnexpectedValueException("Error: Invalid page event."); + } + $sql .= " AND NOT numeric_score=0 ORDER BY numeric_score DESC LIMIT :limit OFFSET 0"; - //filter images by score != 0 + date > limit to max images on one page > order from highest to lowest score + //filter images by score != 0 + date > limit to max images on one page > order from highest to lowest score - $result = $database->get_col($sql, $args); - $images = array(); - foreach($result as $id) { $images[] = Image::by_id($id); } + $result = $database->get_col($sql, $args); + $images = []; + foreach ($result as $id) { + $images[] = Image::by_id($id); + } - $this->theme->view_popular($images, $dte); - } - } + $this->theme->view_popular($images, $dte); + } + } - public function onNumericScoreSet(NumericScoreSetEvent $event) { - global $user; - log_debug("numeric_score", "Rated Image #{$event->image_id} as {$event->score}", "Rated Image", array("image_id"=>$event->image_id)); - $this->add_vote($event->image_id, $user->id, $event->score); - } + public function onNumericScoreSet(NumericScoreSetEvent $event) + { + global $user; + log_debug("numeric_score", "Rated Image #{$event->image_id} as {$event->score}", "Rated Image", ["image_id"=>$event->image_id]); + $this->add_vote($event->image_id, $user->id, $event->score); + } - public function onImageDeletion(ImageDeletionEvent $event) { - global $database; - $database->execute("DELETE FROM numeric_score_votes WHERE image_id=:id", array("id" => $event->image->id)); - } + public function onImageDeletion(ImageDeletionEvent $event) + { + global $database; + $database->execute("DELETE FROM numeric_score_votes WHERE image_id=:id", ["id" => $event->image->id]); + } - public function onUserDeletion(UserDeletionEvent $event) { - $this->delete_votes_by($event->id); - } + public function onUserDeletion(UserDeletionEvent $event) + { + $this->delete_votes_by($event->id); + } - public function delete_votes_by(int $user_id) { - global $database; + public function delete_votes_by(int $user_id) + { + global $database; - $image_ids = $database->get_col("SELECT image_id FROM numeric_score_votes WHERE user_id=?", array($user_id)); + $image_ids = $database->get_col("SELECT image_id FROM numeric_score_votes WHERE user_id=?", [$user_id]); - if(count($image_ids) == 0) return; + if (count($image_ids) == 0) { + return; + } - // vote recounting is pretty heavy, and often hits statement timeouts - // if you try to recount all the images in one go - foreach(array_chunk($image_ids, 20) as $chunk) { - $id_list = implode(",", $chunk); - $database->execute( - "DELETE FROM numeric_score_votes WHERE user_id=? AND image_id IN (".$id_list.")", - array($user_id)); - $database->execute(" + // vote recounting is pretty heavy, and often hits statement timeouts + // if you try to recount all the images in one go + foreach (array_chunk($image_ids, 20) as $chunk) { + $id_list = implode(",", $chunk); + $database->execute( + "DELETE FROM numeric_score_votes WHERE user_id=? AND image_id IN (".$id_list.")", + [$user_id] + ); + $database->execute(" UPDATE images SET numeric_score=COALESCE( ( @@ -200,82 +220,89 @@ class NumericScore extends Extension { 0 ) WHERE images.id IN (".$id_list.")"); - } - } + } + } - public function onParseLinkTemplate(ParseLinkTemplateEvent $event) { - $event->replace('$score', $event->image->numeric_score); - } + public function onParseLinkTemplate(ParseLinkTemplateEvent $event) + { + $event->replace('$score', $event->image->numeric_score); + } - public function onSearchTermParse(SearchTermParseEvent $event) { - $matches = array(); - if(preg_match("/^score([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(-?\d+)$/i", $event->term, $matches)) { - $cmp = ltrim($matches[1], ":") ?: "="; - $score = $matches[2]; - $event->add_querylet(new Querylet("numeric_score $cmp $score")); - } - else if(preg_match("/^upvoted_by[=|:](.*)$/i", $event->term, $matches)) { - $duser = User::by_name($matches[1]); - if(is_null($duser)) { - throw new SearchTermParseException( - "Can't find the user named ".html_escape($matches[1])); - } - $event->add_querylet(new Querylet( - "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=1)", - array("ns_user_id"=>$duser->id))); - } - else if(preg_match("/^downvoted_by[=|:](.*)$/i", $event->term, $matches)) { - $duser = User::by_name($matches[1]); - if(is_null($duser)) { - throw new SearchTermParseException( - "Can't find the user named ".html_escape($matches[1])); - } - $event->add_querylet(new Querylet( - "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=-1)", - array("ns_user_id"=>$duser->id))); - } - else if(preg_match("/^upvoted_by_id[=|:](\d+)$/i", $event->term, $matches)) { - $iid = int_escape($matches[1]); - $event->add_querylet(new Querylet( - "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=1)", - array("ns_user_id"=>$iid))); - } - else if(preg_match("/^downvoted_by_id[=|:](\d+)$/i", $event->term, $matches)) { - $iid = int_escape($matches[1]); - $event->add_querylet(new Querylet( - "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=-1)", - array("ns_user_id"=>$iid))); - } - else if(preg_match("/^order[=|:](?:numeric_)?(score)(?:_(desc|asc))?$/i", $event->term, $matches)){ - $default_order_for_column = "DESC"; - $sort = isset($matches[2]) ? strtoupper($matches[2]) : $default_order_for_column; - Image::$order_sql = "images.numeric_score $sort"; - $event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag - } - } + public function onSearchTermParse(SearchTermParseEvent $event) + { + $matches = []; + if (preg_match("/^score([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(-?\d+)$/i", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; + $score = $matches[2]; + $event->add_querylet(new Querylet("numeric_score $cmp $score")); + } elseif (preg_match("/^upvoted_by[=|:](.*)$/i", $event->term, $matches)) { + $duser = User::by_name($matches[1]); + if (is_null($duser)) { + throw new SearchTermParseException( + "Can't find the user named ".html_escape($matches[1]) + ); + } + $event->add_querylet(new Querylet( + "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=1)", + ["ns_user_id"=>$duser->id] + )); + } elseif (preg_match("/^downvoted_by[=|:](.*)$/i", $event->term, $matches)) { + $duser = User::by_name($matches[1]); + if (is_null($duser)) { + throw new SearchTermParseException( + "Can't find the user named ".html_escape($matches[1]) + ); + } + $event->add_querylet(new Querylet( + "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=-1)", + ["ns_user_id"=>$duser->id] + )); + } elseif (preg_match("/^upvoted_by_id[=|:](\d+)$/i", $event->term, $matches)) { + $iid = int_escape($matches[1]); + $event->add_querylet(new Querylet( + "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=1)", + ["ns_user_id"=>$iid] + )); + } elseif (preg_match("/^downvoted_by_id[=|:](\d+)$/i", $event->term, $matches)) { + $iid = int_escape($matches[1]); + $event->add_querylet(new Querylet( + "images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=-1)", + ["ns_user_id"=>$iid] + )); + } elseif (preg_match("/^order[=|:](?:numeric_)?(score)(?:_(desc|asc))?$/i", $event->term, $matches)) { + $default_order_for_column = "DESC"; + $sort = isset($matches[2]) ? strtoupper($matches[2]) : $default_order_for_column; + Image::$order_sql = "images.numeric_score $sort"; + $event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag + } + } - public function onTagTermParse(TagTermParseEvent $event) { - $matches = array(); + public function onTagTermParse(TagTermParseEvent $event) + { + $matches = []; - if(preg_match("/^vote[=|:](up|down|remove)$/", $event->term, $matches) && $event->parse) { - global $user; - $score = ($matches[1] == "up" ? 1 : ($matches[1] == "down" ? -1 : 0)); - if(!$user->is_anonymous()) { - send_event(new NumericScoreSetEvent($event->id, $user, $score)); - } - } + if (preg_match("/^vote[=|:](up|down|remove)$/", $event->term, $matches) && $event->parse) { + global $user; + $score = ($matches[1] == "up" ? 1 : ($matches[1] == "down" ? -1 : 0)); + if (!$user->is_anonymous()) { + send_event(new NumericScoreSetEvent($event->id, $user, $score)); + } + } - if(!empty($matches)) $event->metatag = true; - } + if (!empty($matches)) { + $event->metatag = true; + } + } - private function install() { - global $database; - global $config; + private function install() + { + global $database; + global $config; - if($config->get_int("ext_numeric_score_version") < 1) { - $database->execute("ALTER TABLE images ADD COLUMN numeric_score INTEGER NOT NULL DEFAULT 0"); - $database->execute("CREATE INDEX images__numeric_score ON images(numeric_score)"); - $database->create_table("numeric_score_votes", " + if ($config->get_int("ext_numeric_score_version") < 1) { + $database->execute("ALTER TABLE images ADD COLUMN numeric_score INTEGER NOT NULL DEFAULT 0"); + $database->execute("CREATE INDEX images__numeric_score ON images(numeric_score)"); + $database->create_table("numeric_score_votes", " image_id INTEGER NOT NULL, user_id INTEGER NOT NULL, score INTEGER NOT NULL, @@ -283,33 +310,36 @@ class NumericScore extends Extension { FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE "); - $database->execute("CREATE INDEX numeric_score_votes_image_id_idx ON numeric_score_votes(image_id)", array()); - $config->set_int("ext_numeric_score_version", 1); - } - if($config->get_int("ext_numeric_score_version") < 2) { - $database->execute("CREATE INDEX numeric_score_votes__user_votes ON numeric_score_votes(user_id, score)"); - $config->set_int("ext_numeric_score_version", 2); - } - } + $database->execute("CREATE INDEX numeric_score_votes_image_id_idx ON numeric_score_votes(image_id)", []); + $config->set_int("ext_numeric_score_version", 1); + } + if ($config->get_int("ext_numeric_score_version") < 2) { + $database->execute("CREATE INDEX numeric_score_votes__user_votes ON numeric_score_votes(user_id, score)"); + $config->set_int("ext_numeric_score_version", 2); + } + } - private function add_vote(int $image_id, int $user_id, int $score) { - global $database; - $database->execute( - "DELETE FROM numeric_score_votes WHERE image_id=:imageid AND user_id=:userid", - array("imageid" => $image_id, "userid" => $user_id)); - if($score != 0) { - $database->execute( - "INSERT INTO numeric_score_votes(image_id, user_id, score) VALUES(:imageid, :userid, :score)", - array("imageid" => $image_id, "userid" => $user_id, "score" => $score)); - } - $database->Execute( - "UPDATE images SET numeric_score=( + private function add_vote(int $image_id, int $user_id, int $score) + { + global $database; + $database->execute( + "DELETE FROM numeric_score_votes WHERE image_id=:imageid AND user_id=:userid", + ["imageid" => $image_id, "userid" => $user_id] + ); + if ($score != 0) { + $database->execute( + "INSERT INTO numeric_score_votes(image_id, user_id, score) VALUES(:imageid, :userid, :score)", + ["imageid" => $image_id, "userid" => $user_id, "score" => $score] + ); + } + $database->Execute( + "UPDATE images SET numeric_score=( COALESCE( (SELECT SUM(score) FROM numeric_score_votes WHERE image_id=:imageid), 0 ) ) WHERE id=:id", - array("imageid" => $image_id, "id" => $image_id)); - } + ["imageid" => $image_id, "id" => $image_id] + ); + } } - diff --git a/ext/numeric_score/test.php b/ext/numeric_score/test.php index f492acdb..3fa7a5d5 100644 --- a/ext/numeric_score/test.php +++ b/ext/numeric_score/test.php @@ -1,60 +1,61 @@ log_in_as_user(); - $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); - $this->get_page("post/view/$image_id"); +class NumericScoreTest extends ShimmiePHPUnitTestCase +{ + public function testNumericScore() + { + $this->log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); + $this->get_page("post/view/$image_id"); - $this->markTestIncomplete(); + $this->markTestIncomplete(); - $this->assert_text("Current Score: 0"); - $this->click("Vote Down"); - $this->assert_text("Current Score: -1"); - $this->click("Vote Up"); - $this->assert_text("Current Score: 1"); - # FIXME: "remove vote" button? - # FIXME: test that up and down are hidden if already voted up or down + $this->assert_text("Current Score: 0"); + $this->click("Vote Down"); + $this->assert_text("Current Score: -1"); + $this->click("Vote Up"); + $this->assert_text("Current Score: 1"); + # FIXME: "remove vote" button? + # FIXME: test that up and down are hidden if already voted up or down - # test search by score - $this->get_page("post/list/score=1/1"); - $this->assert_title("Image $image_id: pbx"); + # test search by score + $this->get_page("post/list/score=1/1"); + $this->assert_title("Image $image_id: pbx"); - $this->get_page("post/list/score>0/1"); - $this->assert_title("Image $image_id: pbx"); + $this->get_page("post/list/score>0/1"); + $this->assert_title("Image $image_id: pbx"); - $this->get_page("post/list/score>-5/1"); - $this->assert_title("Image $image_id: pbx"); + $this->get_page("post/list/score>-5/1"); + $this->assert_title("Image $image_id: pbx"); - $this->get_page("post/list/-score>5/1"); - $this->assert_title("Image $image_id: pbx"); + $this->get_page("post/list/-score>5/1"); + $this->assert_title("Image $image_id: pbx"); - $this->get_page("post/list/-score<-5/1"); - $this->assert_title("Image $image_id: pbx"); + $this->get_page("post/list/-score<-5/1"); + $this->assert_title("Image $image_id: pbx"); - # test search by vote - $this->get_page("post/list/upvoted_by=test/1"); - $this->assert_title("Image $image_id: pbx"); - $this->assert_no_text("No Images Found"); + # test search by vote + $this->get_page("post/list/upvoted_by=test/1"); + $this->assert_title("Image $image_id: pbx"); + $this->assert_no_text("No Images Found"); - # and downvote - $this->get_page("post/list/downvoted_by=test/1"); - $this->assert_text("No Images Found"); + # and downvote + $this->get_page("post/list/downvoted_by=test/1"); + $this->assert_text("No Images Found"); - # test errors - $this->get_page("post/list/upvoted_by=asdfasdf/1"); - $this->assert_text("No Images Found"); - $this->get_page("post/list/downvoted_by=asdfasdf/1"); - $this->assert_text("No Images Found"); - $this->get_page("post/list/upvoted_by_id=0/1"); - $this->assert_text("No Images Found"); - $this->get_page("post/list/downvoted_by_id=0/1"); - $this->assert_text("No Images Found"); + # test errors + $this->get_page("post/list/upvoted_by=asdfasdf/1"); + $this->assert_text("No Images Found"); + $this->get_page("post/list/downvoted_by=asdfasdf/1"); + $this->assert_text("No Images Found"); + $this->get_page("post/list/upvoted_by_id=0/1"); + $this->assert_text("No Images Found"); + $this->get_page("post/list/downvoted_by_id=0/1"); + $this->assert_text("No Images Found"); - $this->log_out(); + $this->log_out(); - $this->log_in_as_admin(); - $this->delete_image($image_id); - $this->log_out(); - } + $this->log_in_as_admin(); + $this->delete_image($image_id); + $this->log_out(); + } } - diff --git a/ext/numeric_score/theme.php b/ext/numeric_score/theme.php index d1a9f38b..c2dc31c7 100644 --- a/ext/numeric_score/theme.php +++ b/ext/numeric_score/theme.php @@ -1,12 +1,14 @@ id); - $i_score = int_escape($image->numeric_score); +class NumericScoreTheme extends Themelet +{ + public function get_voter(Image $image) + { + global $user, $page; + $i_image_id = int_escape($image->id); + $i_score = int_escape($image->numeric_score); - $html = " + $html = " Current Score: $i_score "; + $html .= "{$vote['username']}"; + $html .= " "; + $html .= $vote['score']; + $html .= " @@ -30,8 +32,8 @@ class NumericScoreTheme extends Themelet { "; - if($user->can("edit_other_vote")) { - $html .= " + if ($user->can("edit_other_vote")) { + $html .= "".$user->get_auth_html()." @@ -45,48 +47,48 @@ class NumericScoreTheme extends Themelet { >See All Votes "; - } - $page->add_block(new Block("Image Score", $html, "left", 20)); - } + } + $page->add_block(new Block("Image Score", $html, "left", 20)); + } - public function get_nuller(User $duser) { - global $user, $page; - $html = " + public function get_nuller(User $duser) + { + global $user, $page; + $html = " ".$user->get_auth_html()." "; - $page->add_block(new Block("Votes", $html, "main", 80)); - } + $page->add_block(new Block("Votes", $html, "main", 80)); + } - public function view_popular($images, $dte) { - global $page, $config; + public function view_popular($images, $dte) + { + global $page, $config; - $pop_images = ""; - foreach($images as $image) { - $pop_images .= $this->build_thumb_html($image)."\n"; - } + $pop_images = ""; + foreach ($images as $image) { + $pop_images .= $this->build_thumb_html($image)."\n"; + } - $b_dte = make_link("popular_by_".$dte[3]."?".date($dte[2], (strtotime('-1 '.$dte[3], strtotime($dte[0]))))); - $f_dte = make_link("popular_by_".$dte[3]."?".date($dte[2], (strtotime('+1 '.$dte[3], strtotime($dte[0]))))); + $b_dte = make_link("popular_by_".$dte[3]."?".date($dte[2], (strtotime('-1 '.$dte[3], strtotime($dte[0]))))); + $f_dte = make_link("popular_by_".$dte[3]."?".date($dte[2], (strtotime('+1 '.$dte[3], strtotime($dte[0]))))); - $html = "\n". - "\n". - " \n". - "\n". - " « {$dte[1]} »\n". - "
\n". - "
\n".$pop_images; + $html = "\n". + "\n". + " \n". + "\n". + " « {$dte[1]} »\n". + "
\n". + "
\n".$pop_images; - $nav_html = "Index"; + $nav_html = "Index"; - $page->set_heading($config->get_string('title')); - $page->add_block(new Block("Navigation", $nav_html, "left", 10)); - $page->add_block(new Block(null, $html, "main", 30)); - } + $page->set_heading($config->get_string('title')); + $page->add_block(new Block("Navigation", $nav_html, "left", 10)); + $page->add_block(new Block(null, $html, "main", 30)); + } } - - diff --git a/ext/oekaki/main.php b/ext/oekaki/main.php index c26c1019..f18383e9 100644 --- a/ext/oekaki/main.php +++ b/ext/oekaki/main.php @@ -5,86 +5,87 @@ * Description: ChibiPaint-based Oekaki uploader */ -class Oekaki extends Extension { - public function onPageRequest(PageRequestEvent $event) { - global $user, $page; +class Oekaki extends Extension +{ + public function onPageRequest(PageRequestEvent $event) + { + global $user, $page; - if($event->page_matches("oekaki")) { - if($user->can("create_image")) { - if($event->get_arg(0) == "create") { - $this->theme->display_page(); - $this->theme->display_block(); - } - if($event->get_arg(0) == "claim") { - // FIXME: move .chi to data/oekaki/$ha/$hash mirroring images and thumbs - // FIXME: .chi viewer? - // FIXME: clean out old unclaimed images? - $pattern = data_path('oekaki_unclaimed/' . $_SERVER['REMOTE_ADDR'] . ".*.png"); - foreach(glob($pattern) as $tmpname) { - assert(file_exists($tmpname)); + if ($event->page_matches("oekaki")) { + if ($user->can("create_image")) { + if ($event->get_arg(0) == "create") { + $this->theme->display_page(); + $this->theme->display_block(); + } + if ($event->get_arg(0) == "claim") { + // FIXME: move .chi to data/oekaki/$ha/$hash mirroring images and thumbs + // FIXME: .chi viewer? + // FIXME: clean out old unclaimed images? + $pattern = data_path('oekaki_unclaimed/' . $_SERVER['REMOTE_ADDR'] . ".*.png"); + foreach (glob($pattern) as $tmpname) { + assert(file_exists($tmpname)); - $pathinfo = pathinfo($tmpname); - if(!array_key_exists('extension', $pathinfo)) { - throw new UploadException("File has no extension"); - } - log_info("oekaki", "Processing file [{$pathinfo['filename']}]"); - $metadata = array(); - $metadata['filename'] = 'oekaki.png'; - $metadata['extension'] = $pathinfo['extension']; - $metadata['tags'] = Tag::explode('oekaki tagme'); - $metadata['source'] = null; - $duev = new DataUploadEvent($tmpname, $metadata); - send_event($duev); - if($duev->image_id == -1) { - throw new UploadException("File type not recognised"); - } - else { - unlink($tmpname); - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/view/".$duev->image_id)); - } - } - } - } - if($event->get_arg(0) == "upload") { - // FIXME: this allows anyone to upload anything to /data ... - // hardcoding the ext to .png should stop the obvious exploit, - // but more checking may be wise - if(isset($_FILES["picture"])) { - header('Content-type: text/plain'); + $pathinfo = pathinfo($tmpname); + if (!array_key_exists('extension', $pathinfo)) { + throw new UploadException("File has no extension"); + } + log_info("oekaki", "Processing file [{$pathinfo['filename']}]"); + $metadata = []; + $metadata['filename'] = 'oekaki.png'; + $metadata['extension'] = $pathinfo['extension']; + $metadata['tags'] = Tag::explode('oekaki tagme'); + $metadata['source'] = null; + $duev = new DataUploadEvent($tmpname, $metadata); + send_event($duev); + if ($duev->image_id == -1) { + throw new UploadException("File type not recognised"); + } else { + unlink($tmpname); + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/view/".$duev->image_id)); + } + } + } + } + if ($event->get_arg(0) == "upload") { + // FIXME: this allows anyone to upload anything to /data ... + // hardcoding the ext to .png should stop the obvious exploit, + // but more checking may be wise + if (isset($_FILES["picture"])) { + header('Content-type: text/plain'); - $file = $_FILES['picture']['name']; - //$ext = (strpos($file, '.') === FALSE) ? '' : substr($file, strrpos($file, '.')); - $uploadname = $_SERVER['REMOTE_ADDR'] . "." . time(); - $uploadfile = data_path('oekaki_unclaimed/'.$uploadname); + $file = $_FILES['picture']['name']; + //$ext = (strpos($file, '.') === FALSE) ? '' : substr($file, strrpos($file, '.')); + $uploadname = $_SERVER['REMOTE_ADDR'] . "." . time(); + $uploadfile = data_path('oekaki_unclaimed/'.$uploadname); - log_info("oekaki", "Uploading file [$uploadname]"); + log_info("oekaki", "Uploading file [$uploadname]"); - $success = TRUE; - if (isset($_FILES["chibifile"])) - $success = $success && move_uploaded_file($_FILES['chibifile']['tmp_name'], $uploadfile . ".chi"); + $success = true; + if (isset($_FILES["chibifile"])) { + $success = $success && move_uploaded_file($_FILES['chibifile']['tmp_name'], $uploadfile . ".chi"); + } - // hardcode the ext, so nobody can upload "foo.php" - $success = $success && move_uploaded_file($_FILES['picture']['tmp_name'], $uploadfile . ".png"); # $ext); - if ($success) { - echo "CHIBIOK\n"; - } else { - echo "CHIBIERROR\n"; - } - } - else { - echo "CHIBIERROR No Data\n"; - } - } - } - } + // hardcode the ext, so nobody can upload "foo.php" + $success = $success && move_uploaded_file($_FILES['picture']['tmp_name'], $uploadfile . ".png"); # $ext); + if ($success) { + echo "CHIBIOK\n"; + } else { + echo "CHIBIERROR\n"; + } + } else { + echo "CHIBIERROR No Data\n"; + } + } + } + } - // FIXME: "edit this image" button on existing images? - function onPostListBuilding(PostListBuildingEvent $event) { - global $user; - if($user->can("create_image")) { - $this->theme->display_block(); - } - } + // FIXME: "edit this image" button on existing images? + public function onPostListBuilding(PostListBuildingEvent $event) + { + global $user; + if ($user->can("create_image")) { + $this->theme->display_block(); + } + } } - diff --git a/ext/oekaki/test.php b/ext/oekaki/test.php index 1061595c..c094bce3 100644 --- a/ext/oekaki/test.php +++ b/ext/oekaki/test.php @@ -1,7 +1,9 @@ log_in_as_user(); - $this->get_page("oekaki/create"); - } +class OekakiTest extends ShimmiePHPUnitTestCase +{ + public function testLog() + { + $this->log_in_as_user(); + $this->get_page("oekaki/create"); + } } diff --git a/ext/oekaki/theme.php b/ext/oekaki/theme.php index 8a0ee9b9..ae29a6ac 100644 --- a/ext/oekaki/theme.php +++ b/ext/oekaki/theme.php @@ -2,22 +2,24 @@ // FIXME: Move all the stuff that handles size input to main.php // FIXME: Move default canvas size to config file; changeable in board config // While we're here, add maximum and minimum image sizes in config -// Maybe allow the resolution limiter extension to have a say in this +// Maybe allow the resolution limiter extension to have a say in this -class OekakiTheme extends Themelet { - public function display_page() { - global $config, $page; +class OekakiTheme extends Themelet +{ + public function display_page() + { + global $config, $page; - $base_href = get_base_href(); + $base_href = get_base_href(); - $oekW = $config->get_int("oekaki_width", 400); - $oekH = $config->get_int("oekaki_height", 400); - if(isset($_POST['oekW']) && isset($_POST['oekH'])) { - $oekW = int_escape($_POST['oekW']); - $oekH = int_escape($_POST['oekH']); - } + $oekW = $config->get_int("oekaki_width", 400); + $oekH = $config->get_int("oekaki_height", 400); + if (isset($_POST['oekW']) && isset($_POST['oekH'])) { + $oekW = int_escape($_POST['oekW']); + $oekH = int_escape($_POST['oekH']); + } - $html = " + $html = " "; -# -# - // FIXME: prevent oekaki block from collapsing on click in cerctain themes. This causes canvas reset - $page->set_title("Oekaki"); - $page->set_heading("Oekaki"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Oekaki", $html, "main", 20)); - } + # + # + // FIXME: prevent oekaki block from collapsing on click in cerctain themes. This causes canvas reset + $page->set_title("Oekaki"); + $page->set_heading("Oekaki"); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Oekaki", $html, "main", 20)); + } - public function display_block() { - global $config, $page; - //FIXME: input field alignment could be done more elegantly, without inline styling - //FIXME: autocomplete='off' seems to be an invalid HTML tag + public function display_block() + { + global $config, $page; + //FIXME: input field alignment could be done more elegantly, without inline styling + //FIXME: autocomplete='off' seems to be an invalid HTML tag - $oekW = $config->get_int("oekaki_width", 400); - $oekH = $config->get_int("oekaki_height", 400); - if(isset($_POST['oekW']) && isset($_POST['oekH'])) { - $oekW = int_escape($_POST['oekW']); - $oekH = int_escape($_POST['oekH']); - } + $oekW = $config->get_int("oekaki_width", 400); + $oekH = $config->get_int("oekaki_height", 400); + if (isset($_POST['oekW']) && isset($_POST['oekH'])) { + $oekW = int_escape($_POST['oekW']); + $oekH = int_escape($_POST['oekH']); + } - $page->add_block(new Block("Oekaki", - " + $page->add_block(new Block( + "Oekaki", + "". - "x". - "". - " + "x". + "". + " - " - , "left", 21)); // upload is 20 - } + ", + "left", + 21 + )); // upload is 20 + } } - diff --git a/ext/ouroboros_api/main.php b/ext/ouroboros_api/main.php index fd3623b8..54a68d35 100644 --- a/ext/ouroboros_api/main.php +++ b/ext/ouroboros_api/main.php @@ -209,7 +209,7 @@ class _SafeOuroborosImage // meta $this->change = intval($img->id); //DaFug is this even supposed to do? ChangeID? // Should be JSON specific, just strip this when converting to XML - $this->created_at = array('n' => 123456789, 's' => strtotime($img->posted), 'json_class' => 'Time'); + $this->created_at = ['n' => 123456789, 's' => strtotime($img->posted), 'json_class' => 'Time']; $this->id = intval($img->id); $this->parent_id = null; if (defined('ENABLED_EXTS')) { @@ -248,7 +248,7 @@ class OuroborosPost extends _SafeOuroborosImage * Multipart File * @var array */ - public $file = array(); + public $file = []; /** * Create with rating locked @@ -416,7 +416,6 @@ class OuroborosAPI extends Extension } else { $this->sendResponse(403, 'You cannot create new posts'); } - } elseif ($this->match('update')) { // Update //@todo add post update @@ -432,7 +431,7 @@ class OuroborosAPI extends Extension $p = !empty($_REQUEST['page']) ? intval( filter_var($_REQUEST['page'], FILTER_SANITIZE_NUMBER_INT) ) : 1; - $tags = !empty($_REQUEST['tags']) ? filter_var($_REQUEST['tags'], FILTER_SANITIZE_STRING) : array(); + $tags = !empty($_REQUEST['tags']) ? filter_var($_REQUEST['tags'], FILTER_SANITIZE_STRING) : []; if (!empty($tags)) { $tags = Tag::explode($tags); } @@ -470,7 +469,6 @@ class OuroborosAPI extends Extension $page->display(); die(); } - } /** @@ -491,7 +489,7 @@ class OuroborosAPI extends Extension return; } } - $meta = array(); + $meta = []; $meta['tags'] = is_array($post->tags) ? $post->tags : Tag::explode($post->tags); $meta['source'] = $post->source; if (defined('ENABLED_EXTS')) { @@ -501,8 +499,8 @@ class OuroborosAPI extends Extension } // Check where we should try for the file if (empty($post->file) && !empty($post->file_url) && filter_var( - $post->file_url, - FILTER_VALIDATE_URL + $post->file_url, + FILTER_VALIDATE_URL ) !== false ) { // Transload from source @@ -527,19 +525,18 @@ class OuroborosAPI extends Extension $img = Image::by_hash($meta['hash']); if (!is_null($img)) { $handler = $config->get_string("upload_collision_handler"); - if($handler == "merge") { + if ($handler == "merge") { $postTags = is_array($post->tags) ? $post->tags : Tag::explode($post->tags); $merged = array_merge($postTags, $img->get_tag_array()); send_event(new TagSetEvent($img, $merged)); // This is really the only thing besides tags we should care - if(isset($meta['source'])){ + if (isset($meta['source'])) { send_event(new SourceSetEvent($img, $meta['source'])); } $this->sendResponse(200, self::OK_POST_CREATE_UPDATE . ' ID: ' . $img->id); return; - } - else { + } else { $this->sendResponse(420, self::ERROR_POST_CREATE_DUPE); return; } @@ -586,7 +583,7 @@ class OuroborosAPI extends Extension { $start = ($page - 1) * $limit; $results = Image::find_images(max($start, 0), min($limit, 100), $tags); - $posts = array(); + $posts = []; foreach ($results as $img) { if (!is_object($img)) { continue; @@ -604,7 +601,7 @@ class OuroborosAPI extends Extension { global $database, $config; $start = ($page - 1) * $limit; - $tag_data = array(); + $tag_data = []; switch ($order) { case 'name': $tag_data = $database->get_col( @@ -617,7 +614,7 @@ class OuroborosAPI extends Extension ORDER BY SCORE_STRNORM(substr(tag, 1, 1)) LIMIT :start, :max_items " ), - array('tags_min' => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit) + ['tags_min' => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit] ); break; case 'count': @@ -628,7 +625,7 @@ class OuroborosAPI extends Extension WHERE count >= :tags_min ORDER BY count DESC, tag ASC LIMIT :start, :max_items ", - array('tags_min' => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit) + ['tags_min' => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit] ); break; case 'date': @@ -639,11 +636,11 @@ class OuroborosAPI extends Extension WHERE count >= :tags_min ORDER BY count DESC, tag ASC LIMIT :start, :max_items ", - array('tags_min' => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit) + ['tags_min' => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit] ); break; } - $tags = array(); + $tags = []; foreach ($tag_data as $tag) { if (!is_array($tag)) { continue; @@ -686,7 +683,7 @@ class OuroborosAPI extends Extension } header("{$proto} {$code} {$header}", true); } - $response = array('success' => $success, 'reason' => $reason); + $response = ['success' => $success, 'reason' => $reason]; if ($this->type == 'json') { if ($location !== false) { $response['location'] = $response['reason']; @@ -713,7 +710,7 @@ class OuroborosAPI extends Extension $page->set_data($response); } - private function sendData(string $type = '', array $data = array(), int $offset = 0) + private function sendData(string $type = '', array $data = [], int $offset = 0) { global $page; $response = ''; diff --git a/ext/pm/main.php b/ext/pm/main.php index a5fc3e8f..2cf8d0a7 100644 --- a/ext/pm/main.php +++ b/ext/pm/main.php @@ -10,49 +10,61 @@ * profile page and a box will be shown. */ -class SendPMEvent extends Event { - public $pm; +class SendPMEvent extends Event +{ + public $pm; - public function __construct(PM $pm) { - $this->pm = $pm; - } + public function __construct(PM $pm) + { + $this->pm = $pm; + } } -class PM { - public $id, $from_id, $from_ip, $to_id, $sent_date, $subject, $message, $is_read; +class PM +{ + public $id; + public $from_id; + public $from_ip; + public $to_id; + public $sent_date; + public $subject; + public $message; + public $is_read; - public function __construct($from_id=0, string $from_ip="0.0.0.0", int $to_id=0, string $subject="A Message", string $message="Some Text", bool $read=False) { - # PHP: the P stands for "really", the H stands for "awful" and the other P stands for "language" - if(is_array($from_id)) { - $a = $from_id; - $this->id = $a["id"]; - $this->from_id = $a["from_id"]; - $this->from_ip = $a["from_ip"]; - $this->to_id = $a["to_id"]; - $this->sent_date = $a["sent_date"]; - $this->subject = $a["subject"]; - $this->message = $a["message"]; - $this->is_read = bool_escape($a["is_read"]); - } - else { - $this->id = -1; - $this->from_id = $from_id; - $this->from_ip = $from_ip; - $this->to_id = $to_id; - $this->subject = $subject; - $this->message = $message; - $this->is_read = $read; - } - } + public function __construct($from_id=0, string $from_ip="0.0.0.0", int $to_id=0, string $subject="A Message", string $message="Some Text", bool $read=false) + { + # PHP: the P stands for "really", the H stands for "awful" and the other P stands for "language" + if (is_array($from_id)) { + $a = $from_id; + $this->id = $a["id"]; + $this->from_id = $a["from_id"]; + $this->from_ip = $a["from_ip"]; + $this->to_id = $a["to_id"]; + $this->sent_date = $a["sent_date"]; + $this->subject = $a["subject"]; + $this->message = $a["message"]; + $this->is_read = bool_escape($a["is_read"]); + } else { + $this->id = -1; + $this->from_id = $from_id; + $this->from_ip = $from_ip; + $this->to_id = $to_id; + $this->subject = $subject; + $this->message = $message; + $this->is_read = $read; + } + } } -class PrivMsg extends Extension { - public function onInitExt(InitExtEvent $event) { - global $config, $database; +class PrivMsg extends Extension +{ + public function onInitExt(InitExtEvent $event) + { + global $config, $database; - // shortcut to latest - if($config->get_int("pm_version") < 1) { - $database->create_table("private_message", " + // shortcut to latest + if ($config->get_int("pm_version") < 1) { + $database->create_table("private_message", " id SCORE_AIPK, from_id INTEGER NOT NULL, from_ip SCORE_INET NOT NULL, @@ -64,150 +76,155 @@ class PrivMsg extends Extension { FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE, FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE "); - $database->execute("CREATE INDEX private_message__to_id ON private_message(to_id)"); - $config->set_int("pm_version", 2); - log_info("pm", "extension installed"); - } + $database->execute("CREATE INDEX private_message__to_id ON private_message(to_id)"); + $config->set_int("pm_version", 2); + log_info("pm", "extension installed"); + } - if($config->get_int("pm_version") < 2) { - log_info("pm", "Adding foreign keys to private messages"); - $database->Execute("delete from private_message where to_id not in (select id from users);"); - $database->Execute("delete from private_message where from_id not in (select id from users);"); - $database->Execute("ALTER TABLE private_message + if ($config->get_int("pm_version") < 2) { + log_info("pm", "Adding foreign keys to private messages"); + $database->Execute("delete from private_message where to_id not in (select id from users);"); + $database->Execute("delete from private_message where from_id not in (select id from users);"); + $database->Execute("ALTER TABLE private_message ADD FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE, ADD FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE;"); - $config->set_int("pm_version", 2); - log_info("pm", "extension installed"); - } - } + $config->set_int("pm_version", 2); + log_info("pm", "extension installed"); + } + } - public function onUserBlockBuilding(UserBlockBuildingEvent $event) { - global $user; - if(!$user->is_anonymous()) { - $count = $this->count_pms($user); - $h_count = $count > 0 ? " ($count)" : ""; - $event->add_link("Private Messages$h_count", make_link("user#private-messages")); - } - } + public function onUserBlockBuilding(UserBlockBuildingEvent $event) + { + global $user; + if (!$user->is_anonymous()) { + $count = $this->count_pms($user); + $h_count = $count > 0 ? " ($count)" : ""; + $event->add_link("Private Messages$h_count", make_link("user#private-messages")); + } + } - public function onUserPageBuilding(UserPageBuildingEvent $event) { - global $page, $user; - $duser = $event->display_user; - if(!$user->is_anonymous() && !$duser->is_anonymous()) { - if(($user->id == $duser->id) || $user->can("view_other_pms")) { - $this->theme->display_pms($page, $this->get_pms($duser)); - } - if($user->id != $duser->id) { - $this->theme->display_composer($page, $user, $duser); - } - } - } + public function onUserPageBuilding(UserPageBuildingEvent $event) + { + global $page, $user; + $duser = $event->display_user; + if (!$user->is_anonymous() && !$duser->is_anonymous()) { + if (($user->id == $duser->id) || $user->can("view_other_pms")) { + $this->theme->display_pms($page, $this->get_pms($duser)); + } + if ($user->id != $duser->id) { + $this->theme->display_composer($page, $user, $duser); + } + } + } - public function onPageRequest(PageRequestEvent $event) { - global $database, $page, $user; - if($event->page_matches("pm")) { - if(!$user->is_anonymous()) { - switch($event->get_arg(0)) { - case "read": - $pm_id = int_escape($event->get_arg(1)); - $pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", array("id" => $pm_id)); - if(is_null($pm)) { - $this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); - } - else if(($pm["to_id"] == $user->id) || $user->can("view_other_pms")) { - $from_user = User::by_id(int_escape($pm["from_id"])); - if($pm["to_id"] == $user->id) { - $database->execute("UPDATE private_message SET is_read='Y' WHERE id = :id", array("id" => $pm_id)); - $database->cache->delete("pm-count-{$user->id}"); - } - $this->theme->display_message($page, $from_user, $user, new PM($pm)); - } - else { - // permission denied - } - break; - case "delete": - if($user->check_auth_token()) { - $pm_id = int_escape($_POST["pm_id"]); - $pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", array("id" => $pm_id)); - if(is_null($pm)) { - $this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); - } - else if(($pm["to_id"] == $user->id) || $user->can("view_other_pms")) { - $database->execute("DELETE FROM private_message WHERE id = :id", array("id" => $pm_id)); - $database->cache->delete("pm-count-{$user->id}"); - log_info("pm", "Deleted PM #$pm_id", "PM deleted"); - $page->set_mode("redirect"); - $page->set_redirect($_SERVER["HTTP_REFERER"]); - } - } - break; - case "send": - if($user->check_auth_token()) { - $to_id = int_escape($_POST["to_id"]); - $from_id = $user->id; - $subject = $_POST["subject"]; - $message = $_POST["message"]; - send_event(new SendPMEvent(new PM($from_id, $_SERVER["REMOTE_ADDR"], $to_id, $subject, $message))); - flash_message("PM sent"); - $page->set_mode("redirect"); - $page->set_redirect($_SERVER["HTTP_REFERER"]); - } - break; - default: - $this->theme->display_error(400, "Invalid action", "That's not something you can do with a PM"); - break; - } - } - } - } + public function onPageRequest(PageRequestEvent $event) + { + global $database, $page, $user; + if ($event->page_matches("pm")) { + if (!$user->is_anonymous()) { + switch ($event->get_arg(0)) { + case "read": + $pm_id = int_escape($event->get_arg(1)); + $pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", ["id" => $pm_id]); + if (is_null($pm)) { + $this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); + } elseif (($pm["to_id"] == $user->id) || $user->can("view_other_pms")) { + $from_user = User::by_id(int_escape($pm["from_id"])); + if ($pm["to_id"] == $user->id) { + $database->execute("UPDATE private_message SET is_read='Y' WHERE id = :id", ["id" => $pm_id]); + $database->cache->delete("pm-count-{$user->id}"); + } + $this->theme->display_message($page, $from_user, $user, new PM($pm)); + } else { + // permission denied + } + break; + case "delete": + if ($user->check_auth_token()) { + $pm_id = int_escape($_POST["pm_id"]); + $pm = $database->get_row("SELECT * FROM private_message WHERE id = :id", ["id" => $pm_id]); + if (is_null($pm)) { + $this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); + } elseif (($pm["to_id"] == $user->id) || $user->can("view_other_pms")) { + $database->execute("DELETE FROM private_message WHERE id = :id", ["id" => $pm_id]); + $database->cache->delete("pm-count-{$user->id}"); + log_info("pm", "Deleted PM #$pm_id", "PM deleted"); + $page->set_mode("redirect"); + $page->set_redirect($_SERVER["HTTP_REFERER"]); + } + } + break; + case "send": + if ($user->check_auth_token()) { + $to_id = int_escape($_POST["to_id"]); + $from_id = $user->id; + $subject = $_POST["subject"]; + $message = $_POST["message"]; + send_event(new SendPMEvent(new PM($from_id, $_SERVER["REMOTE_ADDR"], $to_id, $subject, $message))); + flash_message("PM sent"); + $page->set_mode("redirect"); + $page->set_redirect($_SERVER["HTTP_REFERER"]); + } + break; + default: + $this->theme->display_error(400, "Invalid action", "That's not something you can do with a PM"); + break; + } + } + } + } - public function onSendPM(SendPMEvent $event) { - global $database; - $database->execute(" + public function onSendPM(SendPMEvent $event) + { + global $database; + $database->execute( + " INSERT INTO private_message( from_id, from_ip, to_id, sent_date, subject, message) VALUES(:fromid, :fromip, :toid, now(), :subject, :message)", - array("fromid" => $event->pm->from_id, "fromip" => $event->pm->from_ip, - "toid" => $event->pm->to_id, "subject" => $event->pm->subject, "message" => $event->pm->message) - ); - $database->cache->delete("pm-count-{$event->pm->to_id}"); - log_info("pm", "Sent PM to User #{$event->pm->to_id}"); - } + ["fromid" => $event->pm->from_id, "fromip" => $event->pm->from_ip, + "toid" => $event->pm->to_id, "subject" => $event->pm->subject, "message" => $event->pm->message] + ); + $database->cache->delete("pm-count-{$event->pm->to_id}"); + log_info("pm", "Sent PM to User #{$event->pm->to_id}"); + } - private function get_pms(User $user) { - global $database; + private function get_pms(User $user) + { + global $database; - $arr = $database->get_all(" + $arr = $database->get_all( + " SELECT private_message.*,user_from.name AS from_name FROM private_message JOIN users AS user_from ON user_from.id=from_id WHERE to_id = :toid ORDER BY sent_date DESC", - array("toid" => $user->id)); - $pms = array(); - foreach($arr as $pm) { - $pms[] = new PM($pm); - } - return $pms; - } + ["toid" => $user->id] + ); + $pms = []; + foreach ($arr as $pm) { + $pms[] = new PM($pm); + } + return $pms; + } - private function count_pms(User $user) { - global $database; + private function count_pms(User $user) + { + global $database; - $count = $database->cache->get("pm-count:{$user->id}"); - if(is_null($count) || $count === false) { - $count = $database->get_one(" + $count = $database->cache->get("pm-count:{$user->id}"); + if (is_null($count) || $count === false) { + $count = $database->get_one(" SELECT count(*) FROM private_message WHERE to_id = :to_id AND is_read = :is_read - ", array("to_id" => $user->id, "is_read" => "N")); - $database->cache->set("pm-count:{$user->id}", $count, 600); - } - return $count; - } + ", ["to_id" => $user->id, "is_read" => "N"]); + $database->cache->set("pm-count:{$user->id}", $count, 600); + } + return $count; + } } - diff --git a/ext/pm/test.php b/ext/pm/test.php index df065139..ea19e722 100644 --- a/ext/pm/test.php +++ b/ext/pm/test.php @@ -1,59 +1,61 @@ log_in_as_admin(); - $this->get_page("user/test"); +class PrivMsgTest extends ShimmiePHPUnitTestCase +{ + public function testPM() + { + $this->log_in_as_admin(); + $this->get_page("user/test"); - $this->markTestIncomplete(); + $this->markTestIncomplete(); - $this->set_field('subject', "message demo to test"); - $this->set_field('message', "message contents"); - $this->click("Send"); - $this->log_out(); + $this->set_field('subject', "message demo to test"); + $this->set_field('message', "message contents"); + $this->click("Send"); + $this->log_out(); - $this->log_in_as_user(); - $this->get_page("user"); - $this->assert_text("message demo to test"); - $this->click("message demo to test"); - $this->assert_text("message contents"); - $this->back(); - $this->click("Delete"); - $this->assert_no_text("message demo to test"); + $this->log_in_as_user(); + $this->get_page("user"); + $this->assert_text("message demo to test"); + $this->click("message demo to test"); + $this->assert_text("message contents"); + $this->back(); + $this->click("Delete"); + $this->assert_no_text("message demo to test"); - $this->get_page("pm/read/0"); - $this->assert_text("No such PM"); - // GET doesn't work due to auth token check - //$this->get_page("pm/delete/0"); - //$this->assert_text("No such PM"); - $this->get_page("pm/waffle/0"); - $this->assert_text("Invalid action"); + $this->get_page("pm/read/0"); + $this->assert_text("No such PM"); + // GET doesn't work due to auth token check + //$this->get_page("pm/delete/0"); + //$this->assert_text("No such PM"); + $this->get_page("pm/waffle/0"); + $this->assert_text("Invalid action"); - $this->log_out(); - } + $this->log_out(); + } - public function testAdminAccess() { - $this->log_in_as_admin(); - $this->get_page("user/test"); + public function testAdminAccess() + { + $this->log_in_as_admin(); + $this->get_page("user/test"); - $this->markTestIncomplete(); + $this->markTestIncomplete(); - $this->set_field('subject', "message demo to test"); - $this->set_field('message', "message contents"); - $this->click("Send"); + $this->set_field('subject', "message demo to test"); + $this->set_field('message', "message contents"); + $this->click("Send"); - $this->get_page("user/test"); - $this->assert_text("message demo to test"); - $this->click("message demo to test"); - $this->assert_text("message contents"); - $this->back(); - $this->click("Delete"); + $this->get_page("user/test"); + $this->assert_text("message demo to test"); + $this->click("message demo to test"); + $this->assert_text("message contents"); + $this->back(); + $this->click("Delete"); - # simpletest bug? - redirect(referrer) works in opera, not in - # webtestcase, so we end up at the wrong page... - $this->get_page("user/test"); - $this->assert_title("test's Page"); - $this->assert_no_text("message demo to test"); - $this->log_out(); - } + # simpletest bug? - redirect(referrer) works in opera, not in + # webtestcase, so we end up at the wrong page... + $this->get_page("user/test"); + $this->assert_title("test's Page"); + $this->assert_no_text("message demo to test"); + $this->log_out(); + } } - diff --git a/ext/pm/theme.php b/ext/pm/theme.php index 81242c9c..bb9a0f49 100644 --- a/ext/pm/theme.php +++ b/ext/pm/theme.php @@ -1,30 +1,34 @@"; - foreach($pms as $pm) { - $h_subject = html_escape($pm->subject); - if(strlen(trim($h_subject)) == 0) $h_subject = "(No subject)"; - $from = User::by_id($pm->from_id); - $from_name = $from->name; - $h_from = html_escape($from_name); - $from_url = make_link("user/".url_escape($from_name)); - $pm_url = make_link("pm/read/".$pm->id); - $del_url = make_link("pm/delete"); - $h_date = html_escape($pm->sent_date); - $readYN = "Y"; - if(!$pm->is_read) { - $h_subject = "$h_subject"; - $readYN = "N"; - } - $hb = $from->can("hellbanned") ? "hb" : ""; - $html .= " R? Subject From Date Action + foreach ($pms as $pm) { + $h_subject = html_escape($pm->subject); + if (strlen(trim($h_subject)) == 0) { + $h_subject = "(No subject)"; + } + $from = User::by_id($pm->from_id); + $from_name = $from->name; + $h_from = html_escape($from_name); + $from_url = make_link("user/".url_escape($from_name)); + $pm_url = make_link("pm/read/".$pm->id); + $del_url = make_link("pm/delete"); + $h_date = html_escape($pm->sent_date); + $readYN = "Y"; + if (!$pm->is_read) { + $h_subject = "$h_subject"; + $readYN = "N"; + } + $hb = $from->can("hellbanned") ? "hb" : ""; + $html .= " "; - } - $html .= " + } + $html .= " $readYN $h_subject $h_from $h_date @@ -34,21 +38,22 @@ class PrivMsgTheme extends Themelet {id; + $auth = $user->get_auth_html(); + $html = << $auth @@ -59,15 +64,15 @@ $auth
Images per page: "); - $sb->add_int_option("poolsListsPerPage", "
Index list items per page: "); - $sb->add_int_option("poolsUpdatedPerPage", "
Updated list items per page: "); - $sb->add_bool_option("poolsInfoOnViewImage", "
Show pool info on image: "); - $sb->add_bool_option("poolsShowNavLinks", "
Show 'Prev' & 'Next' links when viewing pool images: "); - $sb->add_bool_option("poolsAutoIncrementOrder", "
Autoincrement order when post is added to pool:"); - //$sb->add_bool_option("poolsAdderOnViewImage", "
Show pool adder on image: "); + // Add a block to the Board Config / Setup + public function onSetupBuilding(SetupBuildingEvent $event) + { + $sb = new SetupBlock("Pools"); + $sb->add_int_option("poolsMaxImportResults", "Max results on import: "); + $sb->add_int_option("poolsImagesPerPage", "
Images per page: "); + $sb->add_int_option("poolsListsPerPage", "
Index list items per page: "); + $sb->add_int_option("poolsUpdatedPerPage", "
Updated list items per page: "); + $sb->add_bool_option("poolsInfoOnViewImage", "
Show pool info on image: "); + $sb->add_bool_option("poolsShowNavLinks", "
Show 'Prev' & 'Next' links when viewing pool images: "); + $sb->add_bool_option("poolsAutoIncrementOrder", "
Autoincrement order when post is added to pool:"); + //$sb->add_bool_option("poolsAdderOnViewImage", "
Show pool adder on image: "); - $event->panel->add_block($sb); - } + $event->panel->add_block($sb); + } - public function onPageRequest(PageRequestEvent $event) { - global $page, $user; - - if ($event->page_matches("pool")) { - $pool_id = 0; - $pool = array(); + public function onPageRequest(PageRequestEvent $event) + { + global $page, $user; + + if ($event->page_matches("pool")) { + $pool_id = 0; + $pool = []; - // Check if we have pool id, since this is most often the case. - if (isset($_POST["pool_id"])) { - $pool_id = int_escape($_POST["pool_id"]); - $pool = $this->get_single_pool($pool_id); - } - - // What action are we trying to perform? - switch($event->get_arg(0)) { - case "list": //index - $this->list_pools($page, int_escape($event->get_arg(1))); - break; + // Check if we have pool id, since this is most often the case. + if (isset($_POST["pool_id"])) { + $pool_id = int_escape($_POST["pool_id"]); + $pool = $this->get_single_pool($pool_id); + } + + // What action are we trying to perform? + switch ($event->get_arg(0)) { + case "list": //index + $this->list_pools($page, int_escape($event->get_arg(1))); + break; - case "new": // Show form for new pools - if(!$user->is_anonymous()){ - $this->theme->new_pool_composer($page); - } else { - $errMessage = "You must be registered and logged in to create a new pool."; - $this->theme->display_error(401, "Error", $errMessage); - } - break; + case "new": // Show form for new pools + if (!$user->is_anonymous()) { + $this->theme->new_pool_composer($page); + } else { + $errMessage = "You must be registered and logged in to create a new pool."; + $this->theme->display_error(401, "Error", $errMessage); + } + break; - case "create": // ADD _POST - try { - $newPoolID = $this->add_pool(); - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/view/".$newPoolID)); - } - catch(PoolCreationException $e) { - $this->theme->display_error(400, "Error", $e->error); - } - break; + case "create": // ADD _POST + try { + $newPoolID = $this->add_pool(); + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/view/".$newPoolID)); + } catch (PoolCreationException $e) { + $this->theme->display_error(400, "Error", $e->error); + } + break; - case "view": - $poolID = int_escape($event->get_arg(1)); - $this->get_posts($event, $poolID); - break; + case "view": + $poolID = int_escape($event->get_arg(1)); + $this->get_posts($event, $poolID); + break; - case "updated": - $this->get_history(int_escape($event->get_arg(1))); - break; + case "updated": + $this->get_history(int_escape($event->get_arg(1))); + break; - case "revert": - if(!$user->is_anonymous()) { - $historyID = int_escape($event->get_arg(1)); - $this->revert_history($historyID); - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/updated")); - } - break; + case "revert": + if (!$user->is_anonymous()) { + $historyID = int_escape($event->get_arg(1)); + $this->revert_history($historyID); + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/updated")); + } + break; - case "edit": // Edit the pool (remove images) - if ($this->have_permission($user, $pool)) { - $this->theme->edit_pool($page, $this->get_pool($pool_id), $this->edit_posts($pool_id)); - } else { - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/view/".$pool_id)); - } - break; + case "edit": // Edit the pool (remove images) + if ($this->have_permission($user, $pool)) { + $this->theme->edit_pool($page, $this->get_pool($pool_id), $this->edit_posts($pool_id)); + } else { + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/view/".$pool_id)); + } + break; - case "order": // Order the pool (view and change the order of images within the pool) - if (isset($_POST["order_view"])) { - if ($this->have_permission($user, $pool)) { - $this->theme->edit_order($page, $this->get_pool($pool_id), $this->edit_order($pool_id)); - } else { - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/view/".$pool_id)); - } - } - else { - if ($this->have_permission($user, $pool)) { - $this->order_posts(); - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/view/".$pool_id)); - } else { - $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); - } - } - break; + case "order": // Order the pool (view and change the order of images within the pool) + if (isset($_POST["order_view"])) { + if ($this->have_permission($user, $pool)) { + $this->theme->edit_order($page, $this->get_pool($pool_id), $this->edit_order($pool_id)); + } else { + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/view/".$pool_id)); + } + } else { + if ($this->have_permission($user, $pool)) { + $this->order_posts(); + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/view/".$pool_id)); + } else { + $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); + } + } + break; - case "import": - if ($this->have_permission($user, $pool)) { - $this->import_posts($pool_id); - } else { - $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); - } - break; + case "import": + if ($this->have_permission($user, $pool)) { + $this->import_posts($pool_id); + } else { + $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); + } + break; - case "add_posts": - if ($this->have_permission($user, $pool)) { - $this->add_posts(); - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/view/".$pool_id)); - } else { - $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); - } - break; + case "add_posts": + if ($this->have_permission($user, $pool)) { + $this->add_posts(); + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/view/".$pool_id)); + } else { + $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); + } + break; - case "remove_posts": - if ($this->have_permission($user, $pool)) { - $this->remove_posts(); - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/view/".$pool_id)); - } else { - $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); - } + case "remove_posts": + if ($this->have_permission($user, $pool)) { + $this->remove_posts(); + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/view/".$pool_id)); + } else { + $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); + } - break; + break; - case "edit_description": - if ($this->have_permission($user, $pool)) { - $this->edit_description(); - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/view/".$pool_id)); - } else { - $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); - } + case "edit_description": + if ($this->have_permission($user, $pool)) { + $this->edit_description(); + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/view/".$pool_id)); + } else { + $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); + } - break; + break; - case "nuke": - // Completely remove the given pool. - // -> Only admins and owners may do this - if($user->is_admin() || $user->id == $pool['user_id']) { - $this->nuke_pool($pool_id); - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/list")); - } else { - $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); - } - break; + case "nuke": + // Completely remove the given pool. + // -> Only admins and owners may do this + if ($user->is_admin() || $user->id == $pool['user_id']) { + $this->nuke_pool($pool_id); + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/list")); + } else { + $this->theme->display_error(403, "Permission Denied", "You do not have permission to access this page"); + } + break; - default: - $page->set_mode("redirect"); - $page->set_redirect(make_link("pool/list")); - break; - } - } - } + default: + $page->set_mode("redirect"); + $page->set_redirect(make_link("pool/list")); + break; + } + } + } - public function onUserBlockBuilding(UserBlockBuildingEvent $event) { - $event->add_link("Pools", make_link("pool/list")); - } + public function onUserBlockBuilding(UserBlockBuildingEvent $event) + { + $event->add_link("Pools", make_link("pool/list")); + } - /** - * When displaying an image, optionally list all the pools that the - * image is currently a member of on a side panel, as well as a link - * to the Next image in the pool. - * - * @var DisplayingImageEvent $event - */ - public function onDisplayingImage(DisplayingImageEvent $event) { - global $config; + /** + * When displaying an image, optionally list all the pools that the + * image is currently a member of on a side panel, as well as a link + * to the Next image in the pool. + * + * @var DisplayingImageEvent $event + */ + public function onDisplayingImage(DisplayingImageEvent $event) + { + global $config; - if($config->get_bool("poolsInfoOnViewImage")) { - $imageID = $event->image->id; - $poolsIDs = $this->get_pool_ids($imageID); + if ($config->get_bool("poolsInfoOnViewImage")) { + $imageID = $event->image->id; + $poolsIDs = $this->get_pool_ids($imageID); - $show_nav = $config->get_bool("poolsShowNavLinks", false); + $show_nav = $config->get_bool("poolsShowNavLinks", false); - $navInfo = array(); - foreach($poolsIDs as $poolID) { - $pool = $this->get_single_pool($poolID); + $navInfo = []; + foreach ($poolsIDs as $poolID) { + $pool = $this->get_single_pool($poolID); - $navInfo[$pool['id']] = array(); - $navInfo[$pool['id']]['info'] = $pool; + $navInfo[$pool['id']] = []; + $navInfo[$pool['id']]['info'] = $pool; - // Optionally show a link the Prev/Next image in the Pool. - if ($show_nav) { - $navInfo[$pool['id']]['nav'] = $this->get_nav_posts($pool, $imageID); - } - } - $this->theme->pool_info($navInfo); - } - } + // Optionally show a link the Prev/Next image in the Pool. + if ($show_nav) { + $navInfo[$pool['id']]['nav'] = $this->get_nav_posts($pool, $imageID); + } + } + $this->theme->pool_info($navInfo); + } + } - public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { - global $config, $database, $user; - if($config->get_bool("poolsAdderOnViewImage") && !$user->is_anonymous()) { - if($user->is_admin()) { - $pools = $database->get_all("SELECT * FROM pools"); - } - else { - $pools = $database->get_all("SELECT * FROM pools WHERE user_id=:id", array("id"=>$user->id)); - } - if(count($pools) > 0) { - $event->add_part($this->theme->get_adder_html($event->image, $pools)); - } - } - } + public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) + { + global $config, $database, $user; + if ($config->get_bool("poolsAdderOnViewImage") && !$user->is_anonymous()) { + if ($user->is_admin()) { + $pools = $database->get_all("SELECT * FROM pools"); + } else { + $pools = $database->get_all("SELECT * FROM pools WHERE user_id=:id", ["id"=>$user->id]); + } + if (count($pools) > 0) { + $event->add_part($this->theme->get_adder_html($event->image, $pools)); + } + } + } - public function onSearchTermParse(SearchTermParseEvent $event) { - $matches = array(); - if(preg_match("/^pool[=|:]([0-9]+|any|none)$/i", $event->term, $matches)) { - $poolID = $matches[1]; + public function onSearchTermParse(SearchTermParseEvent $event) + { + $matches = []; + if (preg_match("/^pool[=|:]([0-9]+|any|none)$/i", $event->term, $matches)) { + $poolID = $matches[1]; - if(preg_match("/^(any|none)$/", $poolID)){ - $not = ($poolID == "none" ? "NOT" : ""); - $event->add_querylet(new Querylet("images.id $not IN (SELECT DISTINCT image_id FROM pool_images)")); - }else{ - $event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM pool_images WHERE pool_id = $poolID)")); - } - } - else if(preg_match("/^pool_by_name[=|:](.*)$/i", $event->term, $matches)) { - $poolTitle = str_replace("_", " ", $matches[1]); + if (preg_match("/^(any|none)$/", $poolID)) { + $not = ($poolID == "none" ? "NOT" : ""); + $event->add_querylet(new Querylet("images.id $not IN (SELECT DISTINCT image_id FROM pool_images)")); + } else { + $event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM pool_images WHERE pool_id = $poolID)")); + } + } elseif (preg_match("/^pool_by_name[=|:](.*)$/i", $event->term, $matches)) { + $poolTitle = str_replace("_", " ", $matches[1]); - $pool = $this->get_single_pool_from_title($poolTitle); - $poolID = 0; - if ($pool){ $poolID = $pool['id']; } - $event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM pool_images WHERE pool_id = $poolID)")); - } - } + $pool = $this->get_single_pool_from_title($poolTitle); + $poolID = 0; + if ($pool) { + $poolID = $pool['id']; + } + $event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM pool_images WHERE pool_id = $poolID)")); + } + } - public function onTagTermParse(TagTermParseEvent $event) { - $matches = array(); + public function onTagTermParse(TagTermParseEvent $event) + { + $matches = []; - if(preg_match("/^pool[=|:]([^:]*|lastcreated):?([0-9]*)$/i", $event->term, $matches)) { - global $user; - $poolTag = (string) str_replace("_", " ", $matches[1]); + if (preg_match("/^pool[=|:]([^:]*|lastcreated):?([0-9]*)$/i", $event->term, $matches)) { + global $user; + $poolTag = (string) str_replace("_", " ", $matches[1]); - $pool = null; - if($poolTag == 'lastcreated'){ - $pool = $this->get_last_userpool($user->id); - } - elseif(ctype_digit($poolTag)){ //If only digits, assume PoolID - $pool = $this->get_single_pool($poolTag); - }else{ //assume PoolTitle - $pool = $this->get_single_pool_from_title($poolTag); - } + $pool = null; + if ($poolTag == 'lastcreated') { + $pool = $this->get_last_userpool($user->id); + } elseif (ctype_digit($poolTag)) { //If only digits, assume PoolID + $pool = $this->get_single_pool($poolTag); + } else { //assume PoolTitle + $pool = $this->get_single_pool_from_title($poolTag); + } - if($pool ? $this->have_permission($user, $pool) : FALSE){ - $image_order = ($matches[2] ?: 0); - $this->add_post($pool['id'], $event->id, true, $image_order); - } - } + if ($pool ? $this->have_permission($user, $pool) : false) { + $image_order = ($matches[2] ?: 0); + $this->add_post($pool['id'], $event->id, true, $image_order); + } + } - if(!empty($matches)) $event->metatag = true; - } + if (!empty($matches)) { + $event->metatag = true; + } + } - /* ------------------------------------------------- */ - /* -------------- Private Functions -------------- */ - /* ------------------------------------------------- */ + /* ------------------------------------------------- */ + /* -------------- Private Functions -------------- */ + /* ------------------------------------------------- */ - /** - * Check if the given user has permission to edit/change the pool. - * - * TODO: Should the user variable be global? - */ - private function have_permission(User $user, array $pool): bool { - // If the pool is public and user is logged OR if the user is admin OR if the pool is owned by the user. - if ( (($pool['public'] == "Y" || $pool['public'] == "y") && !$user->is_anonymous()) || $user->is_admin() || $user->id == $pool['user_id']) - { - return true; - } else { - return false; - } - } + /** + * Check if the given user has permission to edit/change the pool. + * + * TODO: Should the user variable be global? + */ + private function have_permission(User $user, array $pool): bool + { + // If the pool is public and user is logged OR if the user is admin OR if the pool is owned by the user. + if ((($pool['public'] == "Y" || $pool['public'] == "y") && !$user->is_anonymous()) || $user->is_admin() || $user->id == $pool['user_id']) { + return true; + } else { + return false; + } + } - /** - * HERE WE GET THE LIST OF POOLS. - */ - private function list_pools(Page $page, int $pageNumber) { - global $config, $database; + /** + * HERE WE GET THE LIST OF POOLS. + */ + private function list_pools(Page $page, int $pageNumber) + { + global $config, $database; - $pageNumber = clamp($pageNumber, 1, null) - 1; + $pageNumber = clamp($pageNumber, 1, null) - 1; - $poolsPerPage = $config->get_int("poolsListsPerPage"); + $poolsPerPage = $config->get_int("poolsListsPerPage"); - $order_by = ""; - $order = $page->get_cookie("ui-order-pool"); - if($order == "created" || is_null($order)){ - $order_by = "ORDER BY p.date DESC"; - }elseif($order == "updated"){ - $order_by = "ORDER BY p.lastupdated DESC"; - }elseif($order == "name"){ - $order_by = "ORDER BY p.title ASC"; - }elseif($order == "count"){ - $order_by = "ORDER BY p.posts DESC"; - } + $order_by = ""; + $order = $page->get_cookie("ui-order-pool"); + if ($order == "created" || is_null($order)) { + $order_by = "ORDER BY p.date DESC"; + } elseif ($order == "updated") { + $order_by = "ORDER BY p.lastupdated DESC"; + } elseif ($order == "name") { + $order_by = "ORDER BY p.title ASC"; + } elseif ($order == "count") { + $order_by = "ORDER BY p.posts DESC"; + } - $pools = $database->get_all(" + $pools = $database->get_all(" SELECT p.id, p.user_id, p.public, p.title, p.description, p.posts, u.name as user_name FROM pools AS p @@ -390,209 +400,230 @@ class Pools extends Extension { ON p.user_id = u.id $order_by LIMIT :l OFFSET :o - ", array("l"=>$poolsPerPage, "o"=>$pageNumber * $poolsPerPage)); + ", ["l"=>$poolsPerPage, "o"=>$pageNumber * $poolsPerPage]); - $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pools") / $poolsPerPage); + $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pools") / $poolsPerPage); - $this->theme->list_pools($page, $pools, $pageNumber + 1, $totalPages); - } + $this->theme->list_pools($page, $pools, $pageNumber + 1, $totalPages); + } - /** - * HERE WE CREATE A NEW POOL - */ - private function add_pool(): int { - global $user, $database; + /** + * HERE WE CREATE A NEW POOL + */ + private function add_pool(): int + { + global $user, $database; - if($user->is_anonymous()) { - throw new PoolCreationException("You must be registered and logged in to add a image."); - } - if(empty($_POST["title"])) { - throw new PoolCreationException("Pool title is empty."); - } - if($this->get_single_pool_from_title($_POST["title"])) { - throw new PoolCreationException("A pool using this title already exists."); - } + if ($user->is_anonymous()) { + throw new PoolCreationException("You must be registered and logged in to add a image."); + } + if (empty($_POST["title"])) { + throw new PoolCreationException("Pool title is empty."); + } + if ($this->get_single_pool_from_title($_POST["title"])) { + throw new PoolCreationException("A pool using this title already exists."); + } - $public = $_POST["public"] === "Y" ? "Y" : "N"; - $database->execute(" + $public = $_POST["public"] === "Y" ? "Y" : "N"; + $database->execute( + " INSERT INTO pools (user_id, public, title, description, date) VALUES (:uid, :public, :title, :desc, now())", - array("uid"=>$user->id, "public"=>$public, "title"=>$_POST["title"], "desc"=>$_POST["description"])); + ["uid"=>$user->id, "public"=>$public, "title"=>$_POST["title"], "desc"=>$_POST["description"]] + ); - $poolID = $database->get_last_insert_id('pools_id_seq'); - log_info("pools", "Pool {$poolID} created by {$user->name}"); - return $poolID; - } + $poolID = $database->get_last_insert_id('pools_id_seq'); + log_info("pools", "Pool {$poolID} created by {$user->name}"); + return $poolID; + } - /** - * Retrieve information about pools given multiple pool IDs. - * - * TODO: What is the difference between this and get_single_pool() other than the db query? - */ - private function get_pool(int $poolID): array { - global $database; - return $database->get_all("SELECT * FROM pools WHERE id=:id", array("id"=>$poolID)); - } + /** + * Retrieve information about pools given multiple pool IDs. + * + * TODO: What is the difference between this and get_single_pool() other than the db query? + */ + private function get_pool(int $poolID): array + { + global $database; + return $database->get_all("SELECT * FROM pools WHERE id=:id", ["id"=>$poolID]); + } - /** - * Retrieve information about a pool given a pool ID. - */ - private function get_single_pool(int $poolID): array { - global $database; - return $database->get_row("SELECT * FROM pools WHERE id=:id", array("id"=>$poolID)); - } + /** + * Retrieve information about a pool given a pool ID. + */ + private function get_single_pool(int $poolID): array + { + global $database; + return $database->get_row("SELECT * FROM pools WHERE id=:id", ["id"=>$poolID]); + } - /** - * Retrieve information about a pool given a pool title. - */ - private function get_single_pool_from_title(string $poolTitle): array { - global $database; - return $database->get_row("SELECT * FROM pools WHERE title=:title", array("title"=>$poolTitle)); - } + /** + * Retrieve information about a pool given a pool title. + */ + private function get_single_pool_from_title(string $poolTitle): array + { + global $database; + return $database->get_row("SELECT * FROM pools WHERE title=:title", ["title"=>$poolTitle]); + } - /** - * Get all of the pool IDs that an image is in, given an image ID. - * #return int[] - */ - private function get_pool_ids(int $imageID): array { - global $database; - return $database->get_col("SELECT pool_id FROM pool_images WHERE image_id=:iid", array("iid"=>$imageID)); - } + /** + * Get all of the pool IDs that an image is in, given an image ID. + * #return int[] + */ + private function get_pool_ids(int $imageID): array + { + global $database; + return $database->get_col("SELECT pool_id FROM pool_images WHERE image_id=:iid", ["iid"=>$imageID]); + } - /** - * Retrieve information about the last pool the given userID created - */ - private function get_last_userpool(int $userID): array { - global $database; - return $database->get_row("SELECT * FROM pools WHERE user_id=:uid ORDER BY id DESC", array("uid"=>$userID)); - } + /** + * Retrieve information about the last pool the given userID created + */ + private function get_last_userpool(int $userID): array + { + global $database; + return $database->get_row("SELECT * FROM pools WHERE user_id=:uid ORDER BY id DESC", ["uid"=>$userID]); + } - /** - * HERE WE GET THE IMAGES FROM THE TAG ON IMPORT - */ - private function import_posts(int $pool_id) { - global $page, $config; + /** + * HERE WE GET THE IMAGES FROM THE TAG ON IMPORT + */ + private function import_posts(int $pool_id) + { + global $page, $config; - $poolsMaxResults = $config->get_int("poolsMaxImportResults", 1000); - - $images = $images = Image::find_images(0, $poolsMaxResults, Tag::explode($_POST["pool_tag"])); - $this->theme->pool_result($page, $images, $this->get_pool($pool_id)); - } + $poolsMaxResults = $config->get_int("poolsMaxImportResults", 1000); + + $images = $images = Image::find_images(0, $poolsMaxResults, Tag::explode($_POST["pool_tag"])); + $this->theme->pool_result($page, $images, $this->get_pool($pool_id)); + } - /** - * HERE WE ADD CHECKED IMAGES FROM POOL AND UPDATE THE HISTORY - * - * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. - */ - private function add_posts(): int { - global $database; + /** + * HERE WE ADD CHECKED IMAGES FROM POOL AND UPDATE THE HISTORY + * + * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. + */ + private function add_posts(): int + { + global $database; - $poolID = int_escape($_POST['pool_id']); - $images = ""; + $poolID = int_escape($_POST['pool_id']); + $images = ""; - foreach ($_POST['check'] as $imageID){ - if(!$this->check_post($poolID, $imageID)){ - $database->execute(" + foreach ($_POST['check'] as $imageID) { + if (!$this->check_post($poolID, $imageID)) { + $database->execute( + " INSERT INTO pool_images (pool_id, image_id) VALUES (:pid, :iid)", - array("pid"=>$poolID, "iid"=>$imageID)); + ["pid"=>$poolID, "iid"=>$imageID] + ); - $images .= " ".$imageID; - } - } + $images .= " ".$imageID; + } + } - if(!strlen($images) == 0) { - $count = int_escape($database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID))); - $this->add_history($poolID, 1, $images, $count); - } + if (!strlen($images) == 0) { + $count = int_escape($database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid"=>$poolID])); + $this->add_history($poolID, 1, $images, $count); + } - $database->Execute(" + $database->Execute( + " UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", - array("pid"=>$poolID) - ); - return $poolID; - } + ["pid"=>$poolID] + ); + return $poolID; + } - /** - * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. - */ - private function order_posts(): int { - global $database; + /** + * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. + */ + private function order_posts(): int + { + global $database; - $poolID = int_escape($_POST['pool_id']); + $poolID = int_escape($_POST['pool_id']); - foreach($_POST['imgs'] as $data) { - list($imageORDER, $imageID) = $data; - $database->Execute(" + foreach ($_POST['imgs'] as $data) { + list($imageORDER, $imageID) = $data; + $database->Execute( + " UPDATE pool_images SET image_order = :ord WHERE pool_id = :pid AND image_id = :iid", - array("ord"=>$imageORDER, "pid"=>$poolID, "iid"=>$imageID) - ); - } + ["ord"=>$imageORDER, "pid"=>$poolID, "iid"=>$imageID] + ); + } - return $poolID; - } + return $poolID; + } - /** - * HERE WE REMOVE CHECKED IMAGES FROM POOL AND UPDATE THE HISTORY - * - * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. - */ - private function remove_posts(): int { - global $database; + /** + * HERE WE REMOVE CHECKED IMAGES FROM POOL AND UPDATE THE HISTORY + * + * TODO: Fix this so that the pool ID and images are passed as Arguments to the function. + */ + private function remove_posts(): int + { + global $database; - $poolID = int_escape($_POST['pool_id']); - $images = ""; + $poolID = int_escape($_POST['pool_id']); + $images = ""; - foreach($_POST['check'] as $imageID) { - $database->execute("DELETE FROM pool_images WHERE pool_id = :pid AND image_id = :iid", array("pid"=>$poolID, "iid"=>$imageID)); - $images .= " ".$imageID; - } + foreach ($_POST['check'] as $imageID) { + $database->execute("DELETE FROM pool_images WHERE pool_id = :pid AND image_id = :iid", ["pid"=>$poolID, "iid"=>$imageID]); + $images .= " ".$imageID; + } - $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID)); - $this->add_history($poolID, 0, $images, $count); - return $poolID; - } + $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid"=>$poolID]); + $this->add_history($poolID, 0, $images, $count); + return $poolID; + } - /** - * Allows editing of pool description. - */ - private function edit_description(): int { - global $database; + /** + * Allows editing of pool description. + */ + private function edit_description(): int + { + global $database; - $poolID = int_escape($_POST['pool_id']); - $database->execute("UPDATE pools SET description=:dsc WHERE id=:pid", array("dsc"=>$_POST['description'], "pid"=>$poolID)); + $poolID = int_escape($_POST['pool_id']); + $database->execute("UPDATE pools SET description=:dsc WHERE id=:pid", ["dsc"=>$_POST['description'], "pid"=>$poolID]); - return $poolID; - } + return $poolID; + } - /** - * This function checks if a given image is contained within a given pool. - * Used by add_posts() - */ - private function check_post(int $poolID, int $imageID): bool { - global $database; - $result = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid AND image_id=:iid", array("pid"=>$poolID, "iid"=>$imageID)); - return ($result != 0); - } + /** + * This function checks if a given image is contained within a given pool. + * Used by add_posts() + */ + private function check_post(int $poolID, int $imageID): bool + { + global $database; + $result = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid AND image_id=:iid", ["pid"=>$poolID, "iid"=>$imageID]); + return ($result != 0); + } - /** - * Gets the previous and next successive images from a pool, given a pool ID and an image ID. - * - * #return int[] Array returning two elements (prev, next) in 1 dimension. Each returns ImageID or NULL if none. - */ - private function get_nav_posts(array $pool, int $imageID): array { - global $database; + /** + * Gets the previous and next successive images from a pool, given a pool ID and an image ID. + * + * #return int[] Array returning two elements (prev, next) in 1 dimension. Each returns ImageID or NULL if none. + */ + private function get_nav_posts(array $pool, int $imageID): array + { + global $database; - if (empty($pool) || empty($imageID)) - return null; - - $result = $database->get_row(" + if (empty($pool) || empty($imageID)) { + return null; + } + + $result = $database->get_row( + " SELECT ( SELECT image_id FROM pool_images @@ -621,172 +652,188 @@ class Pools extends Extension { ) AS next LIMIT 1", - array("pid"=>$pool['id'], "iid"=>$imageID) ); + ["pid"=>$pool['id'], "iid"=>$imageID] + ); - if (empty($result)) { - // assume that we are at the end of the pool - return null; - } else { - return $result; - } - } + if (empty($result)) { + // assume that we are at the end of the pool + return null; + } else { + return $result; + } + } - /** - * Retrieve all the images in a pool, given a pool ID. - */ - private function get_posts(PageRequestEvent $event, int $poolID) { - global $config, $user, $database; + /** + * Retrieve all the images in a pool, given a pool ID. + */ + private function get_posts(PageRequestEvent $event, int $poolID) + { + global $config, $user, $database; - $pageNumber = int_escape($event->get_arg(2)); - if(is_null($pageNumber) || !is_numeric($pageNumber)) - $pageNumber = 0; - else if ($pageNumber <= 0) - $pageNumber = 0; - else - $pageNumber--; + $pageNumber = int_escape($event->get_arg(2)); + if (is_null($pageNumber) || !is_numeric($pageNumber)) { + $pageNumber = 0; + } elseif ($pageNumber <= 0) { + $pageNumber = 0; + } else { + $pageNumber--; + } - $poolID = int_escape($poolID); - $pool = $this->get_pool($poolID); + $poolID = int_escape($poolID); + $pool = $this->get_pool($poolID); - $imagesPerPage = $config->get_int("poolsImagesPerPage"); + $imagesPerPage = $config->get_int("poolsImagesPerPage"); - // WE CHECK IF THE EXTENSION RATING IS INSTALLED, WHICH VERSION AND IF IT - // WORKS TO SHOW/HIDE SAFE, QUESTIONABLE, EXPLICIT AND UNRATED IMAGES FROM USER - if(ext_is_live("Ratings")) { - $rating = Ratings::privs_to_sql(Ratings::get_user_privs($user)); - } - if (isset($rating) && !empty($rating)) { - - $result = $database->get_all(" + // WE CHECK IF THE EXTENSION RATING IS INSTALLED, WHICH VERSION AND IF IT + // WORKS TO SHOW/HIDE SAFE, QUESTIONABLE, EXPLICIT AND UNRATED IMAGES FROM USER + if (ext_is_live("Ratings")) { + $rating = Ratings::privs_to_sql(Ratings::get_user_privs($user)); + } + if (isset($rating) && !empty($rating)) { + $result = $database->get_all( + " SELECT p.image_id FROM pool_images AS p INNER JOIN images AS i ON i.id = p.image_id WHERE p.pool_id = :pid AND i.rating IN ($rating) ORDER BY p.image_order ASC LIMIT :l OFFSET :o", - array("pid"=>$poolID, "l"=>$imagesPerPage, "o"=>$pageNumber * $imagesPerPage)); + ["pid"=>$poolID, "l"=>$imagesPerPage, "o"=>$pageNumber * $imagesPerPage] + ); - $totalPages = ceil($database->get_one(" + $totalPages = ceil($database->get_one( + " SELECT COUNT(*) FROM pool_images AS p INNER JOIN images AS i ON i.id = p.image_id WHERE pool_id=:pid AND i.rating IN ($rating)", - array("pid"=>$poolID)) / $imagesPerPage); - } else { - - $result = $database->get_all(" + ["pid"=>$poolID] + ) / $imagesPerPage); + } else { + $result = $database->get_all( + " SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC LIMIT :l OFFSET :o", - array("pid"=>$poolID, "l"=>$imagesPerPage, "o"=>$pageNumber * $imagesPerPage)); - - $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID)) / $imagesPerPage); - } + ["pid"=>$poolID, "l"=>$imagesPerPage, "o"=>$pageNumber * $imagesPerPage] + ); + + $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid"=>$poolID]) / $imagesPerPage); + } - $images = array(); - foreach($result as $singleResult) { - $images[] = Image::by_id($singleResult["image_id"]); - } + $images = []; + foreach ($result as $singleResult) { + $images[] = Image::by_id($singleResult["image_id"]); + } - $this->theme->view_pool($pool, $images, $pageNumber + 1, $totalPages); - } + $this->theme->view_pool($pool, $images, $pageNumber + 1, $totalPages); + } - /** - * This function gets the current order of images from a given pool. - * #return Image[] Array of image objects. - */ - private function edit_posts(int $poolID): array { - global $database; + /** + * This function gets the current order of images from a given pool. + * #return Image[] Array of image objects. + */ + private function edit_posts(int $poolID): array + { + global $database; - $result = $database->Execute("SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC", array("pid"=>$poolID)); - $images = array(); - - while($row = $result->fetch()) { - $image = Image::by_id($row["image_id"]); - $images[] = array($image); - } - - return $images; - } + $result = $database->Execute("SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC", ["pid"=>$poolID]); + $images = []; + + while ($row = $result->fetch()) { + $image = Image::by_id($row["image_id"]); + $images[] = [$image]; + } + + return $images; + } - /** - * WE GET THE ORDER OF THE IMAGES BUT HERE WE SEND KEYS ADDED IN ARRAY TO GET THE ORDER IN THE INPUT VALUE. - * - * #return Image[] - */ - private function edit_order(int $poolID): array { - global $database; + /** + * WE GET THE ORDER OF THE IMAGES BUT HERE WE SEND KEYS ADDED IN ARRAY TO GET THE ORDER IN THE INPUT VALUE. + * + * #return Image[] + */ + private function edit_order(int $poolID): array + { + global $database; - $result = $database->Execute("SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC", array("pid"=>$poolID)); - $images = array(); - - while($row = $result->fetch()) - { - $image = $database->get_row(" + $result = $database->Execute("SELECT image_id FROM pool_images WHERE pool_id=:pid ORDER BY image_order ASC", ["pid"=>$poolID]); + $images = []; + + while ($row = $result->fetch()) { + $image = $database->get_row( + " SELECT * FROM images AS i INNER JOIN pool_images AS p ON i.id = p.image_id WHERE pool_id=:pid AND i.id=:iid", - array("pid"=>$poolID, "iid"=>$row['image_id'])); - $image = ($image ? new Image($image) : null); - $images[] = array($image); - } - - return $images; - } + ["pid"=>$poolID, "iid"=>$row['image_id']] + ); + $image = ($image ? new Image($image) : null); + $images[] = [$image]; + } + + return $images; + } - /** - * HERE WE NUKE ENTIRE POOL. WE REMOVE POOLS AND POSTS FROM REMOVED POOL AND HISTORIES ENTRIES FROM REMOVED POOL. - */ - private function nuke_pool(int $poolID) { - global $user, $database; + /** + * HERE WE NUKE ENTIRE POOL. WE REMOVE POOLS AND POSTS FROM REMOVED POOL AND HISTORIES ENTRIES FROM REMOVED POOL. + */ + private function nuke_pool(int $poolID) + { + global $user, $database; - $p_id = $database->get_one("SELECT user_id FROM pools WHERE id = :pid", array("pid"=>$poolID)); - if($user->is_admin()) { - $database->execute("DELETE FROM pool_history WHERE pool_id = :pid", array("pid"=>$poolID)); - $database->execute("DELETE FROM pool_images WHERE pool_id = :pid", array("pid"=>$poolID)); - $database->execute("DELETE FROM pools WHERE id = :pid", array("pid"=>$poolID)); - } elseif($user->id == $p_id) { - $database->execute("DELETE FROM pool_history WHERE pool_id = :pid", array("pid"=>$poolID)); - $database->execute("DELETE FROM pool_images WHERE pool_id = :pid", array("pid"=>$poolID)); - $database->execute("DELETE FROM pools WHERE id = :pid AND user_id = :uid", array("pid"=>$poolID, "uid"=>$user->id)); - } - } + $p_id = $database->get_one("SELECT user_id FROM pools WHERE id = :pid", ["pid"=>$poolID]); + if ($user->is_admin()) { + $database->execute("DELETE FROM pool_history WHERE pool_id = :pid", ["pid"=>$poolID]); + $database->execute("DELETE FROM pool_images WHERE pool_id = :pid", ["pid"=>$poolID]); + $database->execute("DELETE FROM pools WHERE id = :pid", ["pid"=>$poolID]); + } elseif ($user->id == $p_id) { + $database->execute("DELETE FROM pool_history WHERE pool_id = :pid", ["pid"=>$poolID]); + $database->execute("DELETE FROM pool_images WHERE pool_id = :pid", ["pid"=>$poolID]); + $database->execute("DELETE FROM pools WHERE id = :pid AND user_id = :uid", ["pid"=>$poolID, "uid"=>$user->id]); + } + } - /** - * HERE WE ADD A HISTORY ENTRY. - * - * $action Action=1 (one) MEANS ADDED, Action=0 (zero) MEANS REMOVED - */ - private function add_history(int $poolID, int $action, string $images, int $count) { - global $user, $database; + /** + * HERE WE ADD A HISTORY ENTRY. + * + * $action Action=1 (one) MEANS ADDED, Action=0 (zero) MEANS REMOVED + */ + private function add_history(int $poolID, int $action, string $images, int $count) + { + global $user, $database; - $database->execute(" + $database->execute( + " INSERT INTO pool_history (pool_id, user_id, action, images, count, date) VALUES (:pid, :uid, :act, :img, :count, now())", - array("pid"=>$poolID, "uid"=>$user->id, "act"=>$action, "img"=>$images, "count"=>$count)); - } + ["pid"=>$poolID, "uid"=>$user->id, "act"=>$action, "img"=>$images, "count"=>$count] + ); + } - /** - * HERE WE GET THE HISTORY LIST. - */ - private function get_history(int $pageNumber) { - global $config, $database; + /** + * HERE WE GET THE HISTORY LIST. + */ + private function get_history(int $pageNumber) + { + global $config, $database; - if(is_null($pageNumber) || !is_numeric($pageNumber)) - $pageNumber = 0; - else if ($pageNumber <= 0) - $pageNumber = 0; - else - $pageNumber--; + if (is_null($pageNumber) || !is_numeric($pageNumber)) { + $pageNumber = 0; + } elseif ($pageNumber <= 0) { + $pageNumber = 0; + } else { + $pageNumber--; + } - $historiesPerPage = $config->get_int("poolsUpdatedPerPage"); + $historiesPerPage = $config->get_int("poolsUpdatedPerPage"); - $history = $database->get_all(" + $history = $database->get_all(" SELECT h.id, h.pool_id, h.user_id, h.action, h.images, h.count, h.date, u.name as user_name, p.title as title FROM pool_history AS h @@ -796,102 +843,106 @@ class Pools extends Extension { ON h.user_id = u.id ORDER BY h.date DESC LIMIT :l OFFSET :o - ", array("l"=>$historiesPerPage, "o"=>$pageNumber * $historiesPerPage)); + ", ["l"=>$historiesPerPage, "o"=>$pageNumber * $historiesPerPage]); - $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pool_history") / $historiesPerPage); + $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pool_history") / $historiesPerPage); - $this->theme->show_history($history, $pageNumber + 1, $totalPages); - } + $this->theme->show_history($history, $pageNumber + 1, $totalPages); + } - /** - * HERE GO BACK IN HISTORY AND ADD OR REMOVE POSTS TO POOL. - */ - private function revert_history(int $historyID) { - global $database; - $status = $database->get_all("SELECT * FROM pool_history WHERE id=:hid", array("hid"=>$historyID)); + /** + * HERE GO BACK IN HISTORY AND ADD OR REMOVE POSTS TO POOL. + */ + private function revert_history(int $historyID) + { + global $database; + $status = $database->get_all("SELECT * FROM pool_history WHERE id=:hid", ["hid"=>$historyID]); - foreach($status as $entry) { - $images = trim($entry['images']); - $images = explode(" ", $images); - $poolID = $entry['pool_id']; - $imageArray = ""; - $newAction = -1; + foreach ($status as $entry) { + $images = trim($entry['images']); + $images = explode(" ", $images); + $poolID = $entry['pool_id']; + $imageArray = ""; + $newAction = -1; - if($entry['action'] == 0) { - // READ ENTRIES - foreach($images as $image) { - $imageID = $image; - $this->add_post($poolID, $imageID); + if ($entry['action'] == 0) { + // READ ENTRIES + foreach ($images as $image) { + $imageID = $image; + $this->add_post($poolID, $imageID); - $imageArray .= " ".$imageID; - $newAction = 1; - } - } - else if($entry['action'] == 1) { - // DELETE ENTRIES - foreach($images as $image) { - $imageID = $image; - $this->delete_post($poolID, $imageID); + $imageArray .= " ".$imageID; + $newAction = 1; + } + } elseif ($entry['action'] == 1) { + // DELETE ENTRIES + foreach ($images as $image) { + $imageID = $image; + $this->delete_post($poolID, $imageID); - $imageArray .= " ".$imageID; - $newAction = 0; - } - } else { - // FIXME: should this throw an exception instead? - log_error("pools", "Invalid history action."); - continue; // go on to the next one. - } + $imageArray .= " ".$imageID; + $newAction = 0; + } + } else { + // FIXME: should this throw an exception instead? + log_error("pools", "Invalid history action."); + continue; // go on to the next one. + } - $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID)); - $this->add_history($poolID, $newAction, $imageArray, $count); - } - } + $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid"=>$poolID]); + $this->add_history($poolID, $newAction, $imageArray, $count); + } + } - /** - * HERE WE ADD A SIMPLE POST FROM POOL. - * USED WITH FOREACH IN revert_history() & onTagTermParse(). - */ - private function add_post(int $poolID, int $imageID, bool $history=false, int $imageOrder=0) { - global $database, $config; + /** + * HERE WE ADD A SIMPLE POST FROM POOL. + * USED WITH FOREACH IN revert_history() & onTagTermParse(). + */ + private function add_post(int $poolID, int $imageID, bool $history=false, int $imageOrder=0) + { + global $database, $config; - if(!$this->check_post($poolID, $imageID)) { - if($config->get_bool("poolsAutoIncrementOrder") && $imageOrder === 0){ - $imageOrder = $database->get_one(" + if (!$this->check_post($poolID, $imageID)) { + if ($config->get_bool("poolsAutoIncrementOrder") && $imageOrder === 0) { + $imageOrder = $database->get_one( + " SELECT CASE WHEN image_order IS NOT NULL THEN MAX(image_order) + 1 ELSE 0 END FROM pool_images WHERE pool_id = :pid", - array("pid"=>$poolID)); - } + ["pid"=>$poolID] + ); + } - $database->execute(" + $database->execute( + " INSERT INTO pool_images (pool_id, image_id, image_order) VALUES (:pid, :iid, :ord)", - array("pid"=>$poolID, "iid"=>$imageID, "ord"=>$imageOrder)); - } + ["pid"=>$poolID, "iid"=>$imageID, "ord"=>$imageOrder] + ); + } - $database->execute("UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", array("pid"=>$poolID)); + $database->execute("UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", ["pid"=>$poolID]); - if($history){ - $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID)); - $this->add_history($poolID, 1, $imageID, $count); - } - } + if ($history) { + $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid"=>$poolID]); + $this->add_history($poolID, 1, $imageID, $count); + } + } - /** - * HERE WE REMOVE A SIMPLE POST FROM POOL. - * USED WITH FOREACH IN revert_history() & onTagTermParse(). - */ - private function delete_post(int $poolID, int $imageID, bool $history=false) { - global $database; + /** + * HERE WE REMOVE A SIMPLE POST FROM POOL. + * USED WITH FOREACH IN revert_history() & onTagTermParse(). + */ + private function delete_post(int $poolID, int $imageID, bool $history=false) + { + global $database; - $database->execute("DELETE FROM pool_images WHERE pool_id = :pid AND image_id = :iid", array("pid"=>$poolID, "iid"=>$imageID)); - $database->execute("UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", array("pid"=>$poolID)); - - if($history){ - $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", array("pid"=>$poolID)); - $this->add_history($poolID, 0, $imageID, $count); - } - } + $database->execute("DELETE FROM pool_images WHERE pool_id = :pid AND image_id = :iid", ["pid"=>$poolID, "iid"=>$imageID]); + $database->execute("UPDATE pools SET posts=(SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid) WHERE id=:pid", ["pid"=>$poolID]); + if ($history) { + $count = $database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid"=>$poolID]); + $this->add_history($poolID, 0, $imageID, $count); + } + } } - diff --git a/ext/pools/test.php b/ext/pools/test.php index 0a3cc265..5f4fadd9 100644 --- a/ext/pools/test.php +++ b/ext/pools/test.php @@ -1,42 +1,43 @@ get_page('pool/list'); - $this->assert_title("Pools"); +class PoolsTest extends ShimmiePHPUnitTestCase +{ + public function testPools() + { + $this->get_page('pool/list'); + $this->assert_title("Pools"); - $this->get_page('pool/new'); - $this->assert_title("Error"); + $this->get_page('pool/new'); + $this->assert_title("Error"); - $this->log_in_as_user(); - $this->get_page('pool/list'); + $this->log_in_as_user(); + $this->get_page('pool/list'); - $this->markTestIncomplete(); + $this->markTestIncomplete(); - $this->click("Create Pool"); - $this->assert_title("Create Pool"); - $this->click("Create"); - $this->assert_title("Error"); + $this->click("Create Pool"); + $this->assert_title("Create Pool"); + $this->click("Create"); + $this->assert_title("Error"); - $this->get_page('pool/new'); - $this->assert_title("Create Pool"); - $this->set_field("title", "Test Pool Title"); - $this->set_field("description", "Test pool description"); - $this->click("Create"); - $this->assert_title("Pool: Test Pool Title"); + $this->get_page('pool/new'); + $this->assert_title("Create Pool"); + $this->set_field("title", "Test Pool Title"); + $this->set_field("description", "Test pool description"); + $this->click("Create"); + $this->assert_title("Pool: Test Pool Title"); - $this->log_out(); + $this->log_out(); - $this->log_in_as_admin(); + $this->log_in_as_admin(); - $this->get_page('pool/list'); - $this->click("Test Pool Title"); - $this->assert_title("Pool: Test Pool Title"); - $this->click("Delete Pool"); - $this->assert_title("Pools"); - $this->assert_no_text("Test Pool Title"); + $this->get_page('pool/list'); + $this->click("Test Pool Title"); + $this->assert_title("Pool: Test Pool Title"); + $this->click("Delete Pool"); + $this->assert_title("Pools"); + $this->assert_no_text("Test Pool Title"); - $this->log_out(); - } + $this->log_out(); + } } - diff --git a/ext/pools/theme.php b/ext/pools/theme.php index 38bd6b50..2dd12045 100644 --- a/ext/pools/theme.php +++ b/ext/pools/theme.php @@ -1,43 +1,46 @@ $pool){ - $linksPools[] = "".html_escape($pool['info']['title']).""; + $linksPools = []; + foreach ($navIDs as $poolID => $pool) { + $linksPools[] = "".html_escape($pool['info']['title']).""; - if (array_key_exists('nav', $pool)){ - $navlinks = ""; - if (!empty($pool['nav']['prev'])) { - $navlinks .= 'Prev'; - } - if (!empty($pool['nav']['next'])) { - $navlinks .= 'Next'; - } - if(!empty($navlinks)){ - $navlinks .= ""; - $linksPools[] = $navlinks; - } - } - } + if (array_key_exists('nav', $pool)) { + $navlinks = ""; + if (!empty($pool['nav']['prev'])) { + $navlinks .= 'Prev'; + } + if (!empty($pool['nav']['next'])) { + $navlinks .= 'Next'; + } + if (!empty($navlinks)) { + $navlinks .= ""; + $linksPools[] = $navlinks; + } + } + } - if(count($linksPools) > 0) { - $page->add_block(new Block("Pools", implode("
", $linksPools), "left")); - } - } + if (count($linksPools) > 0) { + $page->add_block(new Block("Pools", implode("
", $linksPools), "left")); + } + } - public function get_adder_html(Image $image, array $pools): string { - $h = ""; - foreach($pools as $pool) { - $h .= ""; - } - $editor = "\n".make_form(make_link("pool/add_post"))." + public function get_adder_html(Image $image, array $pools): string + { + $h = ""; + foreach ($pools as $pool) { + $h .= ""; + } + $editor = "\n".make_form(make_link("pool/add_post"))." @@ -45,14 +48,15 @@ class PoolsTheme extends Themelet { "; - return $editor; - } + return $editor; + } - /** - * HERE WE SHOWS THE LIST OF POOLS. - */ - public function list_pools(Page $page, array $pools, int $pageNumber, int $totalPages) { - $html = ' + /** + * HERE WE SHOWS THE LIST OF POOLS. + */ + public function list_pools(Page $page, array $pools, int $pageNumber, int $totalPages) + { + $html = '"; + $html .= ""; - $order_html = ''; + $order_html = ''; - $this->display_top(null, "Pools"); - $page->add_block(new Block("Order By", $order_html, "left", 15)); + $this->display_top(null, "Pools"); + $page->add_block(new Block("Order By", $order_html, "left", 15)); - $page->add_block(new Block("Pools", $html, "main", 10)); + $page->add_block(new Block("Pools", $html, "main", 10)); - $this->display_paginator($page, "pool/list", null, $pageNumber, $totalPages); - } + $this->display_paginator($page, "pool/list", null, $pageNumber, $totalPages); + } - /* - * HERE WE DISPLAY THE NEW POOL COMPOSER - */ - public function new_pool_composer(Page $page) { - $create_html = " + /* + * HERE WE DISPLAY THE NEW POOL COMPOSER + */ + public function new_pool_composer(Page $page) + { + $create_html = " ".make_form(make_link("pool/create"))."
'; - // Build up the list of pools. - foreach($pools as $pool) { - $pool_link = ''.html_escape($pool['title']).""; - $user_link = ''.html_escape($pool['user_name']).""; - $public = ($pool['public'] == "Y" ? "Yes" : "No"); + // Build up the list of pools. + foreach ($pools as $pool) { + $pool_link = ''.html_escape($pool['title']).""; + $user_link = ''.html_escape($pool['user_name']).""; + $public = ($pool['public'] == "Y" ? "Yes" : "No"); - $html .= " Name @@ -61,46 +65,47 @@ class PoolsTheme extends Themelet {Public ". - " "; - } + $html .= "".$pool_link." ". - "".$user_link." ". - "".$pool['posts']." ". - "".$public." ". - "". + " "; + } - $html .= "".$pool_link." ". + "".$user_link." ". + "".$pool['posts']." ". + "".$public." ". + ""; - $this->display_top(null, "Recent Changes"); - $page->add_block(new Block("Recent Changes", $html, "main", 10)); + $this->display_top(null, "Recent Changes"); + $page->add_block(new Block("Recent Changes", $html, "main", 10)); - $this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages); - } + $this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages); + } } - diff --git a/ext/qr_code/main.php b/ext/qr_code/main.php index 4fe864d8..6d21cc37 100644 --- a/ext/qr_code/main.php +++ b/ext/qr_code/main.php @@ -7,9 +7,10 @@ * Further modified by Shish to remove the 7MB local QR generator * and replace it with a link to google chart APIs */ -class QRImage extends Extension { - public function onDisplayingImage(DisplayingImageEvent $event) { - $this->theme->links_block(make_http(make_link('image/'.$event->image->id.'.jpg'))); - } +class QRImage extends Extension +{ + public function onDisplayingImage(DisplayingImageEvent $event) + { + $this->theme->links_block(make_http(make_link('image/'.$event->image->id.'.jpg'))); + } } - diff --git a/ext/qr_code/theme.php b/ext/qr_code/theme.php index b7449f01..24c112e7 100644 --- a/ext/qr_code/theme.php +++ b/ext/qr_code/theme.php @@ -1,10 +1,15 @@ add_block( new Block( - "QR Code","","left",50)); - } + $page->add_block(new Block( + "QR Code", + "", + "left", + 50 + )); + } } - diff --git a/ext/random_image/main.php b/ext/random_image/main.php index aaf07f0f..6630b8cb 100644 --- a/ext/random_image/main.php +++ b/ext/random_image/main.php @@ -20,60 +20,59 @@ *
@@ -111,85 +116,88 @@ class PoolsTheme extends Themelet { "; - $this->display_top(null, "Create Pool"); - $page->add_block(new Block("Create Pool", $create_html, "main", 20)); - } + $this->display_top(null, "Create Pool"); + $page->add_block(new Block("Create Pool", $create_html, "main", 20)); + } - private function display_top(array $pools=null, string $heading, bool $check_all=false) { - global $page, $user; + private function display_top(array $pools=null, string $heading, bool $check_all=false) + { + global $page, $user; - $page->set_title($heading); - $page->set_heading($heading); + $page->set_title($heading); + $page->set_heading($heading); - $poolnav_html = ' + $poolnav_html = ' Pool Index Title:
Create Pool
Pool Changes '; - $page->add_block(new NavBlock()); - $page->add_block(new Block("Pool Navigation", $poolnav_html, "left", 10)); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Pool Navigation", $poolnav_html, "left", 10)); - if(!is_null($pools) && count($pools) == 1) { - $pool = $pools[0]; - if($pool['public'] == "Y" || $user->is_admin()) {// IF THE POOL IS PUBLIC OR IS ADMIN SHOW EDIT PANEL - if(!$user->is_anonymous()) {// IF THE USER IS REGISTERED AND LOGGED IN SHOW EDIT PANEL - $this->sidebar_options($page, $pool, $check_all); - } - } + if (!is_null($pools) && count($pools) == 1) { + $pool = $pools[0]; + if ($pool['public'] == "Y" || $user->is_admin()) {// IF THE POOL IS PUBLIC OR IS ADMIN SHOW EDIT PANEL + if (!$user->is_anonymous()) {// IF THE USER IS REGISTERED AND LOGGED IN SHOW EDIT PANEL + $this->sidebar_options($page, $pool, $check_all); + } + } - $tfe = new TextFormattingEvent($pool['description']); - send_event($tfe); - $page->add_block(new Block(html_escape($pool['title']), $tfe->formatted, "main", 10)); - } - } + $tfe = new TextFormattingEvent($pool['description']); + send_event($tfe); + $page->add_block(new Block(html_escape($pool['title']), $tfe->formatted, "main", 10)); + } + } - /** - * HERE WE DISPLAY THE POOL WITH TITLE DESCRIPTION AND IMAGES WITH PAGINATION. - */ - public function view_pool(array $pools, array $images, int $pageNumber, int $totalPages) { - global $page; + /** + * HERE WE DISPLAY THE POOL WITH TITLE DESCRIPTION AND IMAGES WITH PAGINATION. + */ + public function view_pool(array $pools, array $images, int $pageNumber, int $totalPages) + { + global $page; - $this->display_top($pools, "Pool: ".html_escape($pools[0]['title'])); + $this->display_top($pools, "Pool: ".html_escape($pools[0]['title'])); - $pool_images = ''; - foreach($images as $image) { - $thumb_html = $this->build_thumb_html($image); - $pool_images .= "\n".$thumb_html."\n"; - } + $pool_images = ''; + foreach ($images as $image) { + $thumb_html = $this->build_thumb_html($image); + $pool_images .= "\n".$thumb_html."\n"; + } - $page->add_block(new Block("Viewing Posts", $pool_images, "main", 30)); - $this->display_paginator($page, "pool/view/".$pools[0]['id'], null, $pageNumber, $totalPages); - } + $page->add_block(new Block("Viewing Posts", $pool_images, "main", 30)); + $this->display_paginator($page, "pool/view/".$pools[0]['id'], null, $pageNumber, $totalPages); + } - /** - * HERE WE DISPLAY THE POOL OPTIONS ON SIDEBAR BUT WE HIDE REMOVE OPTION IF THE USER IS NOT THE OWNER OR ADMIN. - */ - public function sidebar_options(Page $page, array $pool, bool $check_all) { - global $user; + /** + * HERE WE DISPLAY THE POOL OPTIONS ON SIDEBAR BUT WE HIDE REMOVE OPTION IF THE USER IS NOT THE OWNER OR ADMIN. + */ + public function sidebar_options(Page $page, array $pool, bool $check_all) + { + global $user; - $editor = "\n".make_form( make_link('pool/import') ).' + $editor = "\n".make_form(make_link('pool/import')).' - '.make_form( make_link('pool/edit') ).' + '.make_form(make_link('pool/edit')).' - '.make_form( make_link('pool/order') ).' + '.make_form(make_link('pool/order')).' '; - if($user->id == $pool['user_id'] || $user->is_admin()){ - $editor .= " + if ($user->id == $pool['user_id'] || $user->is_admin()) { + $editor .= " "; - $pool_images .= ""; + $pool_images .= " "; - foreach($images as $image) { - $thumb_html = $this->build_thumb_html($image); + foreach ($images as $image) { + $thumb_html = $this->build_thumb_html($image); - $pool_images .= ''. $thumb_html .' "; + $pool_images .= "
'. - ''. - ''; - } + $pool_images .= ''. $thumb_html .'
'. + ''. + ''; + } - $pool_images .= "
". - "". - "". - "
". + "". + "". + ""; - $page->add_block(new Block("Import", $pool_images, "main", 30)); - } + $page->add_block(new Block("Import", $pool_images, "main", 30)); + } - /** - * HERE WE DISPLAY THE POOL ORDERER. - * WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH A TEXT INPUT TO SET A NUMBER AND CHANGE THE ORDER - */ - public function edit_order(Page $page, array $pools, array $images) { - $this->display_top($pools, "Sorting Pool"); + /** + * HERE WE DISPLAY THE POOL ORDERER. + * WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH A TEXT INPUT TO SET A NUMBER AND CHANGE THE ORDER + */ + public function edit_order(Page $page, array $pools, array $images) + { + $this->display_top($pools, "Sorting Pool"); - $pool_images = "\n"; - $i = 0; - foreach($images as $pair) { - $image = $pair[0]; - $thumb_html = $this->build_thumb_html($image); - $pool_images .= ''."\n".$thumb_html."\n". - '
'. - ''. - ''; - $i++; - } + $pool_images = "\n"; + $i = 0; + foreach ($images as $pair) { + $image = $pair[0]; + $thumb_html = $this->build_thumb_html($image); + $pool_images .= ''."\n".$thumb_html."\n". + ' "; + $pool_images .= "
'. + ''. + ''; + $i++; + } - $pool_images .= "
". - "". - "". - "
". + "". + "". + ""; - $page->add_block(new Block("Sorting Posts", $pool_images, "main", 30)); - } + $page->add_block(new Block("Sorting Posts", $pool_images, "main", 30)); + } - /** - * HERE WE DISPLAY THE POOL EDITOR. - * - * WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH - * A CHECKBOX TO SELECT WHICH IMAGE WE WANT TO REMOVE - */ - public function edit_pool(Page $page, array $pools, array $images) { - /* EDIT POOL DESCRIPTION */ - $desc_html = " + /** + * HERE WE DISPLAY THE POOL EDITOR. + * + * WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH + * A CHECKBOX TO SELECT WHICH IMAGE WE WANT TO REMOVE + */ + public function edit_pool(Page $page, array $pools, array $images) + { + /* EDIT POOL DESCRIPTION */ + $desc_html = " ".make_form(make_link("pool/edit_description"))."
@@ -300,37 +310,38 @@ class PoolsTheme extends Themelet { "; - /* REMOVE POOLS */ - $pool_images = "\n"; + /* REMOVE POOLS */ + $pool_images = "\n "; - foreach($images as $pair) { - $image = $pair[0]; + foreach ($images as $pair) { + $image = $pair[0]; - $thumb_html = $this->build_thumb_html($image); + $thumb_html = $this->build_thumb_html($image); - $pool_images .= ''."\n".$thumb_html."\n". - ' "; + $pool_images .= "
'. - ''; - } + $pool_images .= ''."\n".$thumb_html."\n". + '
'. + ''; + } - $pool_images .= "
". - "". - "". - "
". + "". + "". + ""; - $pools[0]['description'] = ""; //This is a rough fix to avoid showing the description twice. - $this->display_top($pools, "Editing Pool", true); - $page->add_block(new Block("Editing Description", $desc_html, "main", 28)); - $page->add_block(new Block("Editing Posts", $pool_images, "main", 30)); - } + $pools[0]['description'] = ""; //This is a rough fix to avoid showing the description twice. + $this->display_top($pools, "Editing Pool", true); + $page->add_block(new Block("Editing Description", $desc_html, "main", 28)); + $page->add_block(new Block("Editing Posts", $pool_images, "main", 30)); + } - /** - * HERE WE DISPLAY THE HISTORY LIST. - */ - public function show_history(array $histories, int $pageNumber, int $totalPages) { - global $page; - $html = ' + /** + * HERE WE DISPLAY THE HISTORY LIST. + */ + public function show_history(array $histories, int $pageNumber, int $totalPages) + { + global $page; + $html = '"; + $html .= "
'; - foreach($histories as $history) { - $pool_link = "".html_escape($history['title']).""; - $user_link = "".html_escape($history['user_name']).""; - $revert_link = "Revert"; + foreach ($histories as $history) { + $pool_link = "".html_escape($history['title']).""; + $user_link = "".html_escape($history['user_name']).""; + $revert_link = "Revert"; - if ($history['action'] == 1) { - $prefix = "+"; - } elseif ($history['action'] == 0) { - $prefix = "-"; - } + if ($history['action'] == 1) { + $prefix = "+"; + } elseif ($history['action'] == 0) { + $prefix = "-"; + } - $images = trim($history['images']); - $images = explode(" ", $images); + $images = trim($history['images']); + $images = explode(" ", $images); - $image_link = ""; - foreach ($images as $image) { - $image_link .= "".$prefix.$image." "; - } + $image_link = ""; + foreach ($images as $image) { + $image_link .= "".$prefix.$image." "; + } - $html .= " Pool @@ -341,41 +352,40 @@ class PoolsTheme extends Themelet {Action ". - " "; - } + $html .= "".$pool_link." ". - "".$history['count']." ". - "".$image_link." ". - "".$user_link." ". - "".$history['date']." ". - "".$revert_link." ". - "". + " "; + } - $html .= "".$pool_link." ". + "".$history['count']." ". + "".$image_link." ". + "".$user_link." ". + "".$history['date']." ". + "".$revert_link." ". + "/random_image/download/size=1024x768+cute
*/ -class RandomImage extends Extension { - public function onPageRequest(PageRequestEvent $event) { - global $page; +class RandomImage extends Extension +{ + public function onPageRequest(PageRequestEvent $event) + { + global $page; - if($event->page_matches("random_image")) { - if($event->count_args() == 1) { - $action = $event->get_arg(0); - $search_terms = array(); - } - else if($event->count_args() == 2) { - $action = $event->get_arg(0); - $search_terms = explode(' ', $event->get_arg(1)); - } - else { - throw new SCoreException("Error: too many arguments."); - } - $image = Image::by_random($search_terms); + if ($event->page_matches("random_image")) { + if ($event->count_args() == 1) { + $action = $event->get_arg(0); + $search_terms = []; + } elseif ($event->count_args() == 2) { + $action = $event->get_arg(0); + $search_terms = explode(' ', $event->get_arg(1)); + } else { + throw new SCoreException("Error: too many arguments."); + } + $image = Image::by_random($search_terms); - if($action === "download") { - if(!is_null($image)) { - $page->set_mode("data"); - $page->set_type($image->get_mime_type()); - $page->set_data(file_get_contents($image->get_image_filename())); - } - } - else if($action === "view") { - if(!is_null($image)) { - send_event(new DisplayingImageEvent($image)); - } - } - else if($action === "widget") { - if(!is_null($image)) { - $page->set_mode("data"); - $page->set_type("text/html"); - $page->set_data($this->theme->build_thumb_html($image)); - } - } - } - } + if ($action === "download") { + if (!is_null($image)) { + $page->set_mode("data"); + $page->set_type($image->get_mime_type()); + $page->set_data(file_get_contents($image->get_image_filename())); + } + } elseif ($action === "view") { + if (!is_null($image)) { + send_event(new DisplayingImageEvent($image)); + } + } elseif ($action === "widget") { + if (!is_null($image)) { + $page->set_mode("data"); + $page->set_type("text/html"); + $page->set_data($this->theme->build_thumb_html($image)); + } + } + } + } - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Random Image"); - $sb->add_bool_option("show_random_block", "Show Random Block: "); - $event->panel->add_block($sb); - } + public function onSetupBuilding(SetupBuildingEvent $event) + { + $sb = new SetupBlock("Random Image"); + $sb->add_bool_option("show_random_block", "Show Random Block: "); + $event->panel->add_block($sb); + } - public function onPostListBuilding(PostListBuildingEvent $event) { - global $config, $page; - if($config->get_bool("show_random_block")) { - $image = Image::by_random($event->search_terms); - if(!is_null($image)) { - $this->theme->display_random($page, $image); - } - } - } + public function onPostListBuilding(PostListBuildingEvent $event) + { + global $config, $page; + if ($config->get_bool("show_random_block")) { + $image = Image::by_random($event->search_terms); + if (!is_null($image)) { + $this->theme->display_random($page, $image); + } + } + } } - diff --git a/ext/random_image/test.php b/ext/random_image/test.php index ca4031c3..6fa42f69 100644 --- a/ext/random_image/test.php +++ b/ext/random_image/test.php @@ -1,57 +1,59 @@ log_in_as_user(); - $image_id = $this->post_image("tests/pbx_screenshot.jpg", "test"); - $this->log_out(); +class RandomTest extends ShimmiePHPUnitTestCase +{ + public function testRandom() + { + $this->log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "test"); + $this->log_out(); - $this->get_page("random_image/view"); - $this->assert_title("Image $image_id: test"); + $this->get_page("random_image/view"); + $this->assert_title("Image $image_id: test"); - $this->get_page("random_image/view/test"); - $this->assert_title("Image $image_id: test"); + $this->get_page("random_image/view/test"); + $this->assert_title("Image $image_id: test"); - $this->get_page("random_image/download"); - # FIXME: assert($raw == file(blah.jpg)) - } + $this->get_page("random_image/download"); + # FIXME: assert($raw == file(blah.jpg)) + } - public function testPostListBlock() { - $this->log_in_as_admin(); - $this->get_page("setup"); + public function testPostListBlock() + { + $this->log_in_as_admin(); + $this->get_page("setup"); - $this->markTestIncomplete(); + $this->markTestIncomplete(); - $this->set_field("_config_show_random_block", true); - $this->click("Save Settings"); - $this->log_out(); + $this->set_field("_config_show_random_block", true); + $this->click("Save Settings"); + $this->log_out(); - # enabled, no image = no text - $this->get_page("post/list"); - $this->assert_no_text("Random Image"); + # enabled, no image = no text + $this->get_page("post/list"); + $this->assert_no_text("Random Image"); - $this->log_in_as_user(); - $image_id = $this->post_image("tests/pbx_screenshot.jpg", "test"); - $this->log_out(); + $this->log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "test"); + $this->log_out(); - # enabled, image = text - $this->get_page("post/list"); - $this->assert_text("Random Image"); + # enabled, image = text + $this->get_page("post/list"); + $this->assert_text("Random Image"); - $this->log_in_as_admin(); - $this->get_page("setup"); - $this->set_field("_config_show_random_block", true); - $this->click("Save Settings"); + $this->log_in_as_admin(); + $this->get_page("setup"); + $this->set_field("_config_show_random_block", true); + $this->click("Save Settings"); - # disabled, image = no text - $this->get_page("post/list"); - $this->assert_text("Random Image"); + # disabled, image = no text + $this->get_page("post/list"); + $this->assert_text("Random Image"); - $this->delete_image($image_id); - $this->log_out(); + $this->delete_image($image_id); + $this->log_out(); - # disabled, no image = no image - $this->get_page("post/list"); - $this->assert_no_text("Random Image"); - } + # disabled, no image = no image + $this->get_page("post/list"); + $this->assert_no_text("Random Image"); + } } - diff --git a/ext/random_image/theme.php b/ext/random_image/theme.php index e1c43585..2040ac05 100644 --- a/ext/random_image/theme.php +++ b/ext/random_image/theme.php @@ -1,19 +1,21 @@ add_block(new Block("Random Image", $this->build_random_html($image), "left", 8)); - } +class RandomImageTheme extends Themelet +{ + public function display_random(Page $page, Image $image) + { + $page->add_block(new Block("Random Image", $this->build_random_html($image), "left", 8)); + } - public function build_random_html(Image $image, ?string $query = null): string { + public function build_random_html(Image $image, ?string $query = null): string + { + $i_id = int_escape($image->id); + $h_view_link = make_link("post/view/$i_id", $query); + $h_thumb_link = $image->get_thumb_link(); + $h_tip = html_escape($image->get_tooltip()); + $tsize = get_thumbnail_size($image->width, $image->height); - $i_id = int_escape($image->id); - $h_view_link = make_link("post/view/$i_id", $query); - $h_thumb_link = $image->get_thumb_link(); - $h_tip = html_escape($image->get_tooltip()); - $tsize = get_thumbnail_size($image->width, $image->height); - - return " + return ""; - } + } } - diff --git a/ext/random_list/main.php b/ext/random_list/main.php index 46c49801..a4da5604 100644 --- a/ext/random_list/main.php +++ b/ext/random_list/main.php @@ -5,69 +5,73 @@ * Link: http://www.drudexsoftware.com * License: GPLv2 * Description: Allows displaying a page with random images - * Documentation: + * Documentation: * Random image list can be accessed through www.yoursite.com/random * It is recommended that you create a link to this page so users know it exists. */ -class RandomList extends Extension { - public function onPageRequest(PageRequestEvent $event) { - global $config, $page; +class RandomList extends Extension +{ + public function onPageRequest(PageRequestEvent $event) + { + global $config, $page; - if($event->page_matches("random")) { - if(isset($_GET['search'])) { - // implode(explode()) to resolve aliases and sanitise - $search = url_escape(Tag::implode(Tag::explode($_GET['search'], false))); - if(empty($search)) { - $page->set_mode("redirect"); - $page->set_redirect(make_link("random")); - } - else { - $page->set_mode("redirect"); - $page->set_redirect(make_link('random/'.$search)); - } - return; - } + if ($event->page_matches("random")) { + if (isset($_GET['search'])) { + // implode(explode()) to resolve aliases and sanitise + $search = url_escape(Tag::implode(Tag::explode($_GET['search'], false))); + if (empty($search)) { + $page->set_mode("redirect"); + $page->set_redirect(make_link("random")); + } else { + $page->set_mode("redirect"); + $page->set_redirect(make_link('random/'.$search)); + } + return; + } - if($event->count_args() == 0) { - $search_terms = array(); - } - else if($event->count_args() == 1) { - $search_terms = explode(' ', $event->get_arg(0)); - } - else { - throw new SCoreException("Error: too many arguments."); - } + if ($event->count_args() == 0) { + $search_terms = []; + } elseif ($event->count_args() == 1) { + $search_terms = explode(' ', $event->get_arg(0)); + } else { + throw new SCoreException("Error: too many arguments."); + } - // set vars - $images_per_page = $config->get_int("random_images_list_count", 12); - $random_images = array(); + // set vars + $images_per_page = $config->get_int("random_images_list_count", 12); + $random_images = []; - // generate random images - for ($i = 0; $i < $images_per_page; $i++) { - $random_image = Image::by_random($search_terms); - if (!$random_image) continue; - array_push($random_images, $random_image); - } + // generate random images + for ($i = 0; $i < $images_per_page; $i++) { + $random_image = Image::by_random($search_terms); + if (!$random_image) { + continue; + } + array_push($random_images, $random_image); + } - $this->theme->set_page($search_terms); - $this->theme->display_page($page, $random_images); - } - } + $this->theme->set_page($search_terms); + $this->theme->display_page($page, $random_images); + } + } - public function onInitExt(InitExtEvent $event) { - global $config; - $config->set_default_int("random_images_list_count", 12); - } + public function onInitExt(InitExtEvent $event) + { + global $config; + $config->set_default_int("random_images_list_count", 12); + } - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Random Images List"); + public function onSetupBuilding(SetupBuildingEvent $event) + { + $sb = new SetupBlock("Random Images List"); - // custom headers - $sb->add_int_option("random_images_list_count", - "Amount of Random images to display "); + // custom headers + $sb->add_int_option( + "random_images_list_count", + "Amount of Random images to display " + ); - $event->panel->add_block($sb); - } + $event->panel->add_block($sb); + } } - diff --git a/ext/random_list/theme.php b/ext/random_list/theme.php index 6157ce05..aa898906 100644 --- a/ext/random_list/theme.php +++ b/ext/random_list/theme.php @@ -1,43 +1,48 @@ search_terms = $search_terms; - } + /** + * #param string[] $search_terms + */ + public function set_page(array $search_terms) + { + $this->search_terms = $search_terms; + } - /** - * #param Image[] $images - */ - public function display_page(Page $page, array $images) { - $page->title = "Random Images"; + /** + * #param Image[] $images + */ + public function display_page(Page $page, array $images) + { + $page->title = "Random Images"; - $html = "Refresh the page to view more images"; - if (count($images)) { - $html .= " "; + $html = "Refresh the page to view more images"; + if (count($images)) { + $html .= ""; + } else { + $html .= ""; - foreach ($images as $image) - $html .= $this->build_thumb_html($image); + foreach ($images as $image) { + $html .= $this->build_thumb_html($image); + } - $html .= ""; - } else { - $html .= "
No images were found to match the search criteria"; - } + $html .= "
No images were found to match the search criteria"; + } - $page->add_block(new Block("Random Images", $html)); + $page->add_block(new Block("Random Images", $html)); - $nav = $this->build_navigation($this->search_terms); - $page->add_block(new Block("Navigation", $nav, "left", 0)); - } + $nav = $this->build_navigation($this->search_terms); + $page->add_block(new Block("Navigation", $nav, "left", 0)); + } - protected function build_navigation(array $search_terms): string { - $h_search_string = html_escape(Tag::implode($search_terms)); - $h_search_link = make_link("random"); - $h_search = " + protected function build_navigation(array $search_terms): string + { + $h_search_string = html_escape(Tag::implode($search_terms)); + $h_search_link = make_link("random"); + $h_search = "@@ -45,7 +50,6 @@ class RandomListTheme extends Themelet { "; - return $h_search; - } + return $h_search; + } } - diff --git a/ext/rating/main.php b/ext/rating/main.php index 385d1ab8..7d5d9468 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -19,241 +19,269 @@ * */ -class RatingSetEvent extends Event { - /** @var \Image */ - public $image; - /** @var string */ - public $rating; +class RatingSetEvent extends Event +{ + /** @var \Image */ + public $image; + /** @var string */ + public $rating; - public function __construct(Image $image, string $rating) { - assert(in_array($rating, array("s", "q", "e", "u"))); + public function __construct(Image $image, string $rating) + { + assert(in_array($rating, ["s", "q", "e", "u"])); - $this->image = $image; - $this->rating = $rating; - } + $this->image = $image; + $this->rating = $rating; + } } -class Ratings extends Extension { - protected $db_support = ['mysql']; // ? +class Ratings extends Extension +{ + protected $db_support = ['mysql']; // ? - public function get_priority(): int {return 50;} + public function get_priority(): int + { + return 50; + } - public function onInitExt(InitExtEvent $event) { - global $config; - - if($config->get_int("ext_ratings2_version") < 2) { - $this->install(); - } + public function onInitExt(InitExtEvent $event) + { + global $config; + + if ($config->get_int("ext_ratings2_version") < 2) { + $this->install(); + } - $config->set_default_string("ext_rating_anon_privs", 'squ'); - $config->set_default_string("ext_rating_user_privs", 'sqeu'); - $config->set_default_string("ext_rating_admin_privs", 'sqeu'); - } - - public function onSetupBuilding(SetupBuildingEvent $event) { - $privs = array(); - $privs['Safe Only'] = 's'; - $privs['Safe and Unknown'] = 'su'; - $privs['Safe and Questionable'] = 'sq'; - $privs['Safe, Questionable, Unknown'] = 'squ'; - $privs['All'] = 'sqeu'; + $config->set_default_string("ext_rating_anon_privs", 'squ'); + $config->set_default_string("ext_rating_user_privs", 'sqeu'); + $config->set_default_string("ext_rating_admin_privs", 'sqeu'); + } + + public function onSetupBuilding(SetupBuildingEvent $event) + { + $privs = []; + $privs['Safe Only'] = 's'; + $privs['Safe and Unknown'] = 'su'; + $privs['Safe and Questionable'] = 'sq'; + $privs['Safe, Questionable, Unknown'] = 'squ'; + $privs['All'] = 'sqeu'; - $sb = new SetupBlock("Image Ratings"); - $sb->add_choice_option("ext_rating_anon_privs", $privs, "Anonymous: "); - $sb->add_choice_option("ext_rating_user_privs", $privs, "
Users: "); - $sb->add_choice_option("ext_rating_admin_privs", $privs, "
Admins: "); - $event->panel->add_block($sb); - } - - public function onPostListBuilding(PostListBuildingEvent $event) { - global $user; - if($user->is_admin() && !empty($event->search_terms)) { - $this->theme->display_bulk_rater(Tag::implode($event->search_terms)); - } - } + $sb = new SetupBlock("Image Ratings"); + $sb->add_choice_option("ext_rating_anon_privs", $privs, "Anonymous: "); + $sb->add_choice_option("ext_rating_user_privs", $privs, "
Users: "); + $sb->add_choice_option("ext_rating_admin_privs", $privs, "
Admins: "); + $event->panel->add_block($sb); + } + + public function onPostListBuilding(PostListBuildingEvent $event) + { + global $user; + if ($user->is_admin() && !empty($event->search_terms)) { + $this->theme->display_bulk_rater(Tag::implode($event->search_terms)); + } + } - - public function onDisplayingImage(DisplayingImageEvent $event) { - global $user, $page; - /** - * Deny images upon insufficient permissions. - **/ - $user_view_level = Ratings::get_user_privs($user); - $user_view_level = preg_split('//', $user_view_level, -1); - if(!in_array($event->image->rating, $user_view_level)) { - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/list")); - } - } - - public function onRatingSet(RatingSetEvent $event) { - if(empty($event->image->rating)){ - $old_rating = ""; - }else{ - $old_rating = $event->image->rating; - } - $this->set_rating($event->image->id, $event->rating, $old_rating); - } - - public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event) { - $event->add_part($this->theme->get_rater_html($event->image->id, $event->image->rating, $this->can_rate()), 80); - } - - public function onImageInfoSet(ImageInfoSetEvent $event) { - if($this->can_rate() && isset($_POST["rating"])) { - $rating = $_POST["rating"]; - if (Ratings::rating_is_valid($rating)) { - send_event(new RatingSetEvent($event->image, $rating)); - } - } - } + + public function onDisplayingImage(DisplayingImageEvent $event) + { + global $user, $page; + /** + * Deny images upon insufficient permissions. + **/ + $user_view_level = Ratings::get_user_privs($user); + $user_view_level = preg_split('//', $user_view_level, -1); + if (!in_array($event->image->rating, $user_view_level)) { + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/list")); + } + } + + public function onRatingSet(RatingSetEvent $event) + { + if (empty($event->image->rating)) { + $old_rating = ""; + } else { + $old_rating = $event->image->rating; + } + $this->set_rating($event->image->id, $event->rating, $old_rating); + } + + public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event) + { + $event->add_part($this->theme->get_rater_html($event->image->id, $event->image->rating, $this->can_rate()), 80); + } + + public function onImageInfoSet(ImageInfoSetEvent $event) + { + if ($this->can_rate() && isset($_POST["rating"])) { + $rating = $_POST["rating"]; + if (Ratings::rating_is_valid($rating)) { + send_event(new RatingSetEvent($event->image, $rating)); + } + } + } - public function onParseLinkTemplate(ParseLinkTemplateEvent $event) { - $event->replace('$rating', $this->rating_to_human($event->image->rating)); - } + public function onParseLinkTemplate(ParseLinkTemplateEvent $event) + { + $event->replace('$rating', $this->rating_to_human($event->image->rating)); + } - public function onSearchTermParse(SearchTermParseEvent $event) { - global $user; - - $matches = array(); - if(is_null($event->term) && $this->no_rating_query($event->context)) { - $set = Ratings::privs_to_sql(Ratings::get_user_privs($user)); - $event->add_querylet(new Querylet("rating IN ($set)")); - } - if(preg_match("/^rating[=|:](?:([sqeu]+)|(safe|questionable|explicit|unknown))$/D", strtolower($event->term), $matches)) { - $ratings = $matches[1] ? $matches[1] : $matches[2][0]; - $ratings = array_intersect(str_split($ratings), str_split(Ratings::get_user_privs($user))); - $set = "'" . join("', '", $ratings) . "'"; - $event->add_querylet(new Querylet("rating IN ($set)")); - } - } + public function onSearchTermParse(SearchTermParseEvent $event) + { + global $user; + + $matches = []; + if (is_null($event->term) && $this->no_rating_query($event->context)) { + $set = Ratings::privs_to_sql(Ratings::get_user_privs($user)); + $event->add_querylet(new Querylet("rating IN ($set)")); + } + if (preg_match("/^rating[=|:](?:([sqeu]+)|(safe|questionable|explicit|unknown))$/D", strtolower($event->term), $matches)) { + $ratings = $matches[1] ? $matches[1] : $matches[2][0]; + $ratings = array_intersect(str_split($ratings), str_split(Ratings::get_user_privs($user))); + $set = "'" . join("', '", $ratings) . "'"; + $event->add_querylet(new Querylet("rating IN ($set)")); + } + } - public function onPageRequest(PageRequestEvent $event) { - global $user, $page; - - if ($event->page_matches("admin/bulk_rate")) { - if(!$user->is_admin()) { - throw new PermissionDeniedException(); - } - else { - $n = 0; - while(true) { - $images = Image::find_images($n, 100, Tag::explode($_POST["query"])); - if(count($images) == 0) break; - - reset($images); // rewind to first element in array. - - foreach($images as $image) { - send_event(new RatingSetEvent($image, $_POST['rating'])); - } - $n += 100; - } - #$database->execute(" - # update images set rating=? where images.id in ( - # select image_id from image_tags join tags - # on image_tags.tag_id = tags.id where tags.tag = ?); - # ", array($_POST["rating"], $_POST["tag"])); - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/list")); - } - } - } + public function onPageRequest(PageRequestEvent $event) + { + global $user, $page; + + if ($event->page_matches("admin/bulk_rate")) { + if (!$user->is_admin()) { + throw new PermissionDeniedException(); + } else { + $n = 0; + while (true) { + $images = Image::find_images($n, 100, Tag::explode($_POST["query"])); + if (count($images) == 0) { + break; + } + + reset($images); // rewind to first element in array. + + foreach ($images as $image) { + send_event(new RatingSetEvent($image, $_POST['rating'])); + } + $n += 100; + } + #$database->execute(" + # update images set rating=? where images.id in ( + # select image_id from image_tags join tags + # on image_tags.tag_id = tags.id where tags.tag = ?); + # ", array($_POST["rating"], $_POST["tag"])); + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/list")); + } + } + } - public static function get_user_privs(User $user): string { - global $config; + public static function get_user_privs(User $user): string + { + global $config; - if($user->is_anonymous()) { - $sqes = $config->get_string("ext_rating_anon_privs"); - } - else if($user->is_admin()) { - $sqes = $config->get_string("ext_rating_admin_privs"); - } - else { - $sqes = $config->get_string("ext_rating_user_privs"); - } - return $sqes; - } + if ($user->is_anonymous()) { + $sqes = $config->get_string("ext_rating_anon_privs"); + } elseif ($user->is_admin()) { + $sqes = $config->get_string("ext_rating_admin_privs"); + } else { + $sqes = $config->get_string("ext_rating_user_privs"); + } + return $sqes; + } - public static function privs_to_sql(string $sqes): string { - $arr = array(); - $length = strlen($sqes); - for($i=0; $i<$length; $i++) { - $arr[] = "'" . $sqes[$i] . "'"; - } - $set = join(', ', $arr); - return $set; - } + public static function privs_to_sql(string $sqes): string + { + $arr = []; + $length = strlen($sqes); + for ($i=0; $i<$length; $i++) { + $arr[] = "'" . $sqes[$i] . "'"; + } + $set = join(', ', $arr); + return $set; + } - public static function rating_to_human(string $rating): string { - switch($rating) { - case "s": return "Safe"; - case "q": return "Questionable"; - case "e": return "Explicit"; - default: return "Unknown"; - } - } + public static function rating_to_human(string $rating): string + { + switch ($rating) { + case "s": return "Safe"; + case "q": return "Questionable"; + case "e": return "Explicit"; + default: return "Unknown"; + } + } - public static function rating_is_valid(string $rating): bool { - switch($rating) { - case "s": - case "q": - case "e": - case "u": - return true; - default: - return false; - } - } + public static function rating_is_valid(string $rating): bool + { + switch ($rating) { + case "s": + case "q": + case "e": + case "u": + return true; + default: + return false; + } + } - /** - * FIXME: this is a bit ugly and guessey, should have proper options - */ - private function can_rate(): bool { - global $config, $user; - if($user->is_anonymous() && $config->get_string("ext_rating_anon_privs") == "sqeu") return false; - if($user->is_admin()) return true; - if(!$user->is_anonymous() && $config->get_string("ext_rating_user_privs") == "sqeu") return true; - return false; - } + /** + * FIXME: this is a bit ugly and guessey, should have proper options + */ + private function can_rate(): bool + { + global $config, $user; + if ($user->is_anonymous() && $config->get_string("ext_rating_anon_privs") == "sqeu") { + return false; + } + if ($user->is_admin()) { + return true; + } + if (!$user->is_anonymous() && $config->get_string("ext_rating_user_privs") == "sqeu") { + return true; + } + return false; + } - /** - * #param string[] $context - */ - private function no_rating_query(array $context): bool { - foreach($context as $term) { - if(preg_match("/^rating[=|:]/", $term)) { - return false; - } - } - return true; - } + /** + * #param string[] $context + */ + private function no_rating_query(array $context): bool + { + foreach ($context as $term) { + if (preg_match("/^rating[=|:]/", $term)) { + return false; + } + } + return true; + } - private function install() { - global $database, $config; + private function install() + { + global $database, $config; - if($config->get_int("ext_ratings2_version") < 1) { - $database->Execute("ALTER TABLE images ADD COLUMN rating CHAR(1) NOT NULL DEFAULT 'u'"); - $database->Execute("CREATE INDEX images__rating ON images(rating)"); - $config->set_int("ext_ratings2_version", 3); - } + if ($config->get_int("ext_ratings2_version") < 1) { + $database->Execute("ALTER TABLE images ADD COLUMN rating CHAR(1) NOT NULL DEFAULT 'u'"); + $database->Execute("CREATE INDEX images__rating ON images(rating)"); + $config->set_int("ext_ratings2_version", 3); + } - if($config->get_int("ext_ratings2_version") < 2) { - $database->Execute("CREATE INDEX images__rating ON images(rating)"); - $config->set_int("ext_ratings2_version", 2); - } + if ($config->get_int("ext_ratings2_version") < 2) { + $database->Execute("CREATE INDEX images__rating ON images(rating)"); + $config->set_int("ext_ratings2_version", 2); + } - if($config->get_int("ext_ratings2_version") < 3) { - $database->Execute("ALTER TABLE images CHANGE rating rating CHAR(1) NOT NULL DEFAULT 'u'"); - $config->set_int("ext_ratings2_version", 3); - } - } + if ($config->get_int("ext_ratings2_version") < 3) { + $database->Execute("ALTER TABLE images CHANGE rating rating CHAR(1) NOT NULL DEFAULT 'u'"); + $config->set_int("ext_ratings2_version", 3); + } + } - private function set_rating(int $image_id, string $rating, string $old_rating) { - global $database; - if($old_rating != $rating){ - $database->Execute("UPDATE images SET rating=? WHERE id=?", array($rating, $image_id)); - log_info("rating", "Rating for Image #{$image_id} set to: ".$this->rating_to_human($rating)); - } - } + private function set_rating(int $image_id, string $rating, string $old_rating) + { + global $database; + if ($old_rating != $rating) { + $database->Execute("UPDATE images SET rating=? WHERE id=?", [$rating, $image_id]); + log_info("rating", "Rating for Image #{$image_id} set to: ".$this->rating_to_human($rating)); + } + } } - diff --git a/ext/rating/test.php b/ext/rating/test.php index 87d5e1f3..119a8b09 100644 --- a/ext/rating/test.php +++ b/ext/rating/test.php @@ -1,54 +1,55 @@ log_in_as_user(); - $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); +class RatingTest extends ShimmiePHPUnitTestCase +{ + public function testRating() + { + $this->log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); - # test for bug #735: user forced to set rating, can't - # set tags and leave unrated - $this->get_page("post/view/$image_id"); - $this->assert_title("Image $image_id: pbx"); + # test for bug #735: user forced to set rating, can't + # set tags and leave unrated + $this->get_page("post/view/$image_id"); + $this->assert_title("Image $image_id: pbx"); - $this->markTestIncomplete(); + $this->markTestIncomplete(); - $this->set_field("tag_edit__tags", "new"); - $this->click("Set"); - $this->assert_title("Image $image_id: new"); + $this->set_field("tag_edit__tags", "new"); + $this->click("Set"); + $this->assert_title("Image $image_id: new"); - # set safe - $this->set_field("rating", "s"); - $this->click("Set"); - $this->assert_title("Image $image_id: new"); + # set safe + $this->set_field("rating", "s"); + $this->click("Set"); + $this->assert_title("Image $image_id: new"); - # search for it in various ways - $this->get_page("post/list/rating=Safe/1"); - $this->assert_title("Image $image_id: new"); + # search for it in various ways + $this->get_page("post/list/rating=Safe/1"); + $this->assert_title("Image $image_id: new"); - $this->get_page("post/list/rating=s/1"); - $this->assert_title("Image $image_id: new"); + $this->get_page("post/list/rating=s/1"); + $this->assert_title("Image $image_id: new"); - $this->get_page("post/list/rating=sqe/1"); - $this->assert_title("Image $image_id: new"); + $this->get_page("post/list/rating=sqe/1"); + $this->assert_title("Image $image_id: new"); - # test that search by tag still works - $this->get_page("post/list/new/1"); - $this->assert_title("Image $image_id: new"); + # test that search by tag still works + $this->get_page("post/list/new/1"); + $this->assert_title("Image $image_id: new"); - # searching for a different rating should return nothing - $this->get_page("post/list/rating=q/1"); - $this->assert_text("No Images Found"); + # searching for a different rating should return nothing + $this->get_page("post/list/rating=q/1"); + $this->assert_text("No Images Found"); - # now set explicit, for the next test - $this->get_page("post/view/$image_id"); - $this->set_field("rating", "e"); - $this->click("Set"); - $this->assert_title("Image $image_id: new"); + # now set explicit, for the next test + $this->get_page("post/view/$image_id"); + $this->set_field("rating", "e"); + $this->click("Set"); + $this->assert_title("Image $image_id: new"); - $this->log_out(); + $this->log_out(); - # the explicit image shouldn't show up in anon's searches - $this->get_page("post/list/new/1"); - $this->assert_text("No Images Found"); - } + # the explicit image shouldn't show up in anon's searches + $this->get_page("post/list/new/1"); + $this->assert_text("No Images Found"); + } } - diff --git a/ext/rating/theme.php b/ext/rating/theme.php index 0c218bd3..241c20c7 100644 --- a/ext/rating/theme.php +++ b/ext/rating/theme.php @@ -1,12 +1,14 @@Rating @@ -23,12 +25,13 @@ class RatingsTheme extends Themelet { "; - return $html; - } + return $html; + } - public function display_bulk_rater(string $terms) { - global $page; - $html = " + public function display_bulk_rater(string $terms) + { + global $page; + $html = " ".make_form(make_link("admin/bulk_rate"))." "; - $html = " + $html = " ".make_form(make_link("tips/save"))."
@@ -32,64 +34,65 @@ class TipsTheme extends Themelet { "; - $page->set_title("Tips List"); - $page->set_heading("Tips List"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Add Tip", $html, "main", 10)); - } + $page->set_title("Tips List"); + $page->set_heading("Tips List"); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Add Tip", $html, "main", 10)); + } - public function showTip($url, $tip) { - global $page; + public function showTip($url, $tip) + { + global $page; - $img = ""; - if(!empty($tip['image'])) { - $img = " "; - } - $html = " ".$img.$tip['text'].""; - $page->add_block(new Block(null, $html, "subheading", 10)); - } + $img = ""; + if (!empty($tip['image'])) { + $img = " "; + } + $html = "".$img.$tip['text'].""; + $page->add_block(new Block(null, $html, "subheading", 10)); + } - public function showAll($url, $tips){ - global $user, $page; + public function showAll($url, $tips) + { + global $user, $page; - $html = "". - "
"; - $page->add_block(new Block("All Tips", $html, "main", 20)); - } + $page->add_block(new Block("All Tips", $html, "main", 20)); + } } - diff --git a/ext/update/main.php b/ext/update/main.php index 653c4176..cf995c10 100644 --- a/ext/update/main.php +++ b/ext/update/main.php @@ -6,106 +6,120 @@ * License: GPLv2 * Description: Shimmie updater! (Requires admin panel extension & transload engine (cURL/fopen/Wget)) */ -class Update extends Extension { - public function onInitExt(InitExtEvent $event) { - global $config; - $config->set_default_string("update_guserrepo", "shish/shimmie2"); - $config->set_default_string("commit_hash", "unknown"); - $config->set_default_string("update_time", "01/01/1970"); - } +class Update extends Extension +{ + public function onInitExt(InitExtEvent $event) + { + global $config; + $config->set_default_string("update_guserrepo", "shish/shimmie2"); + $config->set_default_string("commit_hash", "unknown"); + $config->set_default_string("update_time", "01/01/1970"); + } - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Update"); - $sb->add_text_option("update_guserrepo", "User/Repo: "); - $event->panel->add_block($sb); - } + public function onSetupBuilding(SetupBuildingEvent $event) + { + $sb = new SetupBlock("Update"); + $sb->add_text_option("update_guserrepo", "User/Repo: "); + $event->panel->add_block($sb); + } - public function onAdminBuilding(AdminBuildingEvent $event) { - global $config; - if($config->get_string('transload_engine') !== "none"){ - $this->theme->display_admin_block(); - } - } + public function onAdminBuilding(AdminBuildingEvent $event) + { + global $config; + if ($config->get_string('transload_engine') !== "none") { + $this->theme->display_admin_block(); + } + } - public function onPageRequest(PageRequestEvent $event) { - global $user, $page; - if($user->is_admin() && isset($_GET['sha'])){ - if($event->page_matches("update/download")){ - $ok = $this->download_shimmie(); + public function onPageRequest(PageRequestEvent $event) + { + global $user, $page; + if ($user->is_admin() && isset($_GET['sha'])) { + if ($event->page_matches("update/download")) { + $ok = $this->download_shimmie(); - $page->set_mode("redirect"); - if($ok) $page->set_redirect(make_link("update/update", "sha=".$_GET['sha'])); - else $page->set_redirect(make_link("admin")); //TODO: Show error? - }elseif($event->page_matches("update/update")){ - $ok = $this->update_shimmie(); + $page->set_mode("redirect"); + if ($ok) { + $page->set_redirect(make_link("update/update", "sha=".$_GET['sha'])); + } else { + $page->set_redirect(make_link("admin")); + } //TODO: Show error? + } elseif ($event->page_matches("update/update")) { + $ok = $this->update_shimmie(); - $page->set_mode("redirect"); - if($ok) $page->set_redirect(make_link("admin")); //TODO: Show success? - else $page->set_redirect(make_link("admin")); //TODO: Show error? - } - } - } + $page->set_mode("redirect"); + if ($ok) { + $page->set_redirect(make_link("admin")); + } //TODO: Show success? + else { + $page->set_redirect(make_link("admin")); + } //TODO: Show error? + } + } + } - private function download_shimmie(): bool { - global $config; + private function download_shimmie(): bool + { + global $config; - $commitSHA = $_GET['sha']; - $g_userrepo = $config->get_string('update_guserrepo'); + $commitSHA = $_GET['sha']; + $g_userrepo = $config->get_string('update_guserrepo'); - $url = "https://codeload.github.com/".$g_userrepo."/zip/".$commitSHA; - $filename = "./data/update_{$commitSHA}.zip"; + $url = "https://codeload.github.com/".$g_userrepo."/zip/".$commitSHA; + $filename = "./data/update_{$commitSHA}.zip"; - log_info("update", "Attempting to download Shimmie commit: ".$commitSHA); - if($headers = transload($url, $filename)){ - if(($headers['Content-Type'] !== "application/zip") || ((int) $headers['Content-Length'] !== filesize($filename))){ - unlink("./data/update_{$commitSHA}.zip"); - log_warning("update", "Download failed: not zip / not same size as remote file."); - return false; - } + log_info("update", "Attempting to download Shimmie commit: ".$commitSHA); + if ($headers = transload($url, $filename)) { + if (($headers['Content-Type'] !== "application/zip") || ((int) $headers['Content-Length'] !== filesize($filename))) { + unlink("./data/update_{$commitSHA}.zip"); + log_warning("update", "Download failed: not zip / not same size as remote file."); + return false; + } - return true; - } + return true; + } - log_warning("update", "Download failed to download."); - return false; - } + log_warning("update", "Download failed to download."); + return false; + } - private function update_shimmie(): bool { - global $config; + private function update_shimmie(): bool + { + global $config; - $commitSHA = $_GET['sha']; + $commitSHA = $_GET['sha']; - log_info("update", "Download succeeded. Attempting to update Shimmie."); - $config->set_bool("in_upgrade", TRUE); - $ok = FALSE; + log_info("update", "Download succeeded. Attempting to update Shimmie."); + $config->set_bool("in_upgrade", true); + $ok = false; - /** TODO: Backup all folders (except /data, /images, /thumbs) before attempting this? - Either that or point to https://github.com/shish/shimmie2/blob/master/README.txt -> Upgrade from 2.3.X **/ + /** TODO: Backup all folders (except /data, /images, /thumbs) before attempting this? + Either that or point to https://github.com/shish/shimmie2/blob/master/README.txt -> Upgrade from 2.3.X **/ - $zip = new ZipArchive; - if ($zip->open("./data/update_$commitSHA.zip") === TRUE) { - for($i = 1; $i < $zip->numFiles; $i++) { - $filename = $zip->getNameIndex($i); + $zip = new ZipArchive; + if ($zip->open("./data/update_$commitSHA.zip") === true) { + for ($i = 1; $i < $zip->numFiles; $i++) { + $filename = $zip->getNameIndex($i); - if(substr($filename, -1) !== "/"){ - copy("zip://".dirname(dirname(__DIR__)).'/'."./data/update_$commitSHA.zip"."#".$filename, substr($filename, 50)); - } - } - $ok = TRUE; //TODO: Do proper checking to see if everything copied properly - }else{ log_warning("update", "Update failed to open ZIP."); } + if (substr($filename, -1) !== "/") { + copy("zip://".dirname(dirname(__DIR__)).'/'."./data/update_$commitSHA.zip"."#".$filename, substr($filename, 50)); + } + } + $ok = true; //TODO: Do proper checking to see if everything copied properly + } else { + log_warning("update", "Update failed to open ZIP."); + } - $zip->close(); - unlink("./data/update_$commitSHA.zip"); - $config->set_bool("in_upgrade", FALSE); + $zip->close(); + unlink("./data/update_$commitSHA.zip"); + $config->set_bool("in_upgrade", false); - if($ok){ - $config->set_string("commit_hash", $commitSHA); - $config->set_string("update_time", date('d-m-Y')); - log_info("update", "Update succeeded?"); - } + if ($ok) { + $config->set_string("commit_hash", $commitSHA); + $config->set_string("update_time", date('d-m-Y')); + log_info("update", "Update succeeded?"); + } - return $ok; - } + return $ok; + } } - - diff --git a/ext/update/theme.php b/ext/update/theme.php index e3dffb6a..fe29b6a1 100644 --- a/ext/update/theme.php +++ b/ext/update/theme.php @@ -1,14 +1,15 @@ Current Commit: ".$config->get_string('commit_hash')." | (".$config->get_string('update_time').")". - "". - " "; + } + $html .= "ID ". - "Enabled ". - "Image ". - "Text "; + $html = "". + "
"; + $html .= "". + " "; + $html .= ""; - foreach ($tips as $tip) { - $tip_enable = ($tip['enable'] == "Y") ? "Yes" : "No"; - $set_link = "".$tip_enable.""; + foreach ($tips as $tip) { + $tip_enable = ($tip['enable'] == "Y") ? "Yes" : "No"; + $set_link = "".$tip_enable.""; - $html .= "ID ". + "Enabled ". + "Image ". + "Text "; - if($user->is_admin()){ - $html .= "Action "; - } + if ($user->is_admin()) { + $html .= "Action "; + } - $html .= "". - " ".$tip['id']." ". - "".$set_link." ". - ( - empty($tip['image']) ? - "" : - " " - ). - " ".$tip['text']." "; + $html .= "". + " "; - } - $html .= "".$tip['id']." ". + "".$set_link." ". + ( + empty($tip['image']) ? + "" : + " " + ). + " ".$tip['text']." "; - $del_link = "Delete"; + $del_link = "Delete"; - if($user->is_admin()){ - $html .= "".$del_link." "; - } + if ($user->is_admin()) { + $html .= "".$del_link." "; + } - $html .= "
Latest Commit: Loading...". - "
"; - //TODO: Show warning before use. - $page->add_block(new Block("Software Update", $html, "main", 75)); - } + $html = "". + "Current Commit: ".$config->get_string('commit_hash')." | (".$config->get_string('update_time').")". + "
Latest Commit: Loading...". + "
"; + //TODO: Show warning before use. + $page->add_block(new Block("Software Update", $html, "main", 75)); + } } - diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index 24d0e5bc..3321b409 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -7,128 +7,132 @@ * Visibility: admin */ -class Upgrade extends Extension { - public function onInitExt(InitExtEvent $event) { - global $config, $database; +class Upgrade extends Extension +{ + public function onInitExt(InitExtEvent $event) + { + global $config, $database; - if($config->get_bool("in_upgrade")) return; + if ($config->get_bool("in_upgrade")) { + return; + } - if(!is_numeric($config->get_string("db_version"))) { - $config->set_int("db_version", 2); - } + if (!is_numeric($config->get_string("db_version"))) { + $config->set_int("db_version", 2); + } - if($config->get_int("db_version") < 6) { - // cry :S - } + if ($config->get_int("db_version") < 6) { + // cry :S + } - // v7 is convert to innodb with adodb - // now done again as v9 with PDO + // v7 is convert to innodb with adodb + // now done again as v9 with PDO - if($config->get_int("db_version") < 8) { - $config->set_bool("in_upgrade", true); - $config->set_int("db_version", 8); + if ($config->get_int("db_version") < 8) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 8); - $database->execute($database->scoreql_to_sql( - "ALTER TABLE images ADD COLUMN locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" - )); + $database->execute($database->scoreql_to_sql( + "ALTER TABLE images ADD COLUMN locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" + )); - log_info("upgrade", "Database at version 8"); - $config->set_bool("in_upgrade", false); - } + log_info("upgrade", "Database at version 8"); + $config->set_bool("in_upgrade", false); + } - if($config->get_int("db_version") < 9) { - $config->set_bool("in_upgrade", true); - $config->set_int("db_version", 9); + if ($config->get_int("db_version") < 9) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 9); - if($database->get_driver_name() == 'mysql') { - $tables = $database->get_col("SHOW TABLES"); - foreach($tables as $table) { - log_info("upgrade", "converting $table to innodb"); - $database->execute("ALTER TABLE $table ENGINE=INNODB"); - } - } + if ($database->get_driver_name() == 'mysql') { + $tables = $database->get_col("SHOW TABLES"); + foreach ($tables as $table) { + log_info("upgrade", "converting $table to innodb"); + $database->execute("ALTER TABLE $table ENGINE=INNODB"); + } + } - log_info("upgrade", "Database at version 9"); - $config->set_bool("in_upgrade", false); - } + log_info("upgrade", "Database at version 9"); + $config->set_bool("in_upgrade", false); + } - if($config->get_int("db_version") < 10) { - $config->set_bool("in_upgrade", true); - $config->set_int("db_version", 10); + if ($config->get_int("db_version") < 10) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 10); - log_info("upgrade", "Adding foreign keys to images"); - $database->Execute("ALTER TABLE images ADD FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT"); - - log_info("upgrade", "Database at version 10"); - $config->set_bool("in_upgrade", false); - } + log_info("upgrade", "Adding foreign keys to images"); + $database->Execute("ALTER TABLE images ADD FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT"); + + log_info("upgrade", "Database at version 10"); + $config->set_bool("in_upgrade", false); + } - if($config->get_int("db_version") < 11) { - $config->set_bool("in_upgrade", true); - $config->set_int("db_version", 11); + if ($config->get_int("db_version") < 11) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 11); - log_info("upgrade", "Converting user flags to classes"); - $database->execute("ALTER TABLE users ADD COLUMN class VARCHAR(32) NOT NULL default :user", array("user" => "user")); - $database->execute("UPDATE users SET class = :name WHERE id=:id", array("name"=>"anonymous", "id"=>$config->get_int('anon_id'))); - $database->execute("UPDATE users SET class = :name WHERE admin=:admin", array("name"=>"admin", "admin"=>'Y')); + log_info("upgrade", "Converting user flags to classes"); + $database->execute("ALTER TABLE users ADD COLUMN class VARCHAR(32) NOT NULL default :user", ["user" => "user"]); + $database->execute("UPDATE users SET class = :name WHERE id=:id", ["name"=>"anonymous", "id"=>$config->get_int('anon_id')]); + $database->execute("UPDATE users SET class = :name WHERE admin=:admin", ["name"=>"admin", "admin"=>'Y']); - log_info("upgrade", "Database at version 11"); - $config->set_bool("in_upgrade", false); - } + log_info("upgrade", "Database at version 11"); + $config->set_bool("in_upgrade", false); + } - if($config->get_int("db_version") < 12) { - $config->set_bool("in_upgrade", true); - $config->set_int("db_version", 12); + if ($config->get_int("db_version") < 12) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 12); - if($database->get_driver_name() == 'pgsql') { - log_info("upgrade", "Changing ext column to VARCHAR"); - $database->execute("ALTER TABLE images ALTER COLUMN ext SET DATA TYPE VARCHAR(4)"); - } + if ($database->get_driver_name() == 'pgsql') { + log_info("upgrade", "Changing ext column to VARCHAR"); + $database->execute("ALTER TABLE images ALTER COLUMN ext SET DATA TYPE VARCHAR(4)"); + } - log_info("upgrade", "Lowering case of all exts"); - $database->execute("UPDATE images SET ext = LOWER(ext)"); + log_info("upgrade", "Lowering case of all exts"); + $database->execute("UPDATE images SET ext = LOWER(ext)"); - log_info("upgrade", "Database at version 12"); - $config->set_bool("in_upgrade", false); - } + log_info("upgrade", "Database at version 12"); + $config->set_bool("in_upgrade", false); + } - if($config->get_int("db_version") < 13) { - $config->set_bool("in_upgrade", true); - $config->set_int("db_version", 13); + if ($config->get_int("db_version") < 13) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 13); - log_info("upgrade", "Changing password column to VARCHAR(250)"); - if($database->get_driver_name() == 'pgsql') { - $database->execute("ALTER TABLE users ALTER COLUMN pass SET DATA TYPE VARCHAR(250)"); - } - else if($database->get_driver_name() == 'mysql') { - $database->execute("ALTER TABLE users CHANGE pass pass VARCHAR(250)"); - } + log_info("upgrade", "Changing password column to VARCHAR(250)"); + if ($database->get_driver_name() == 'pgsql') { + $database->execute("ALTER TABLE users ALTER COLUMN pass SET DATA TYPE VARCHAR(250)"); + } elseif ($database->get_driver_name() == 'mysql') { + $database->execute("ALTER TABLE users CHANGE pass pass VARCHAR(250)"); + } - log_info("upgrade", "Database at version 13"); - $config->set_bool("in_upgrade", false); - } + log_info("upgrade", "Database at version 13"); + $config->set_bool("in_upgrade", false); + } - if($config->get_int("db_version") < 14) { - $config->set_bool("in_upgrade", true); - $config->set_int("db_version", 14); + if ($config->get_int("db_version") < 14) { + $config->set_bool("in_upgrade", true); + $config->set_int("db_version", 14); - log_info("upgrade", "Changing tag column to VARCHAR(255)"); - if($database->get_driver_name() == 'pgsql') { - $database->execute('ALTER TABLE tags ALTER COLUMN tag SET DATA TYPE VARCHAR(255)'); - $database->execute('ALTER TABLE aliases ALTER COLUMN oldtag SET DATA TYPE VARCHAR(255)'); - $database->execute('ALTER TABLE aliases ALTER COLUMN newtag SET DATA TYPE VARCHAR(255)'); - } - else if($database->get_driver_name() == 'mysql') { - $database->execute('ALTER TABLE tags MODIFY COLUMN tag VARCHAR(255) NOT NULL'); - $database->execute('ALTER TABLE aliases MODIFY COLUMN oldtag VARCHAR(255) NOT NULL'); - $database->execute('ALTER TABLE aliases MODIFY COLUMN newtag VARCHAR(255) NOT NULL'); - } + log_info("upgrade", "Changing tag column to VARCHAR(255)"); + if ($database->get_driver_name() == 'pgsql') { + $database->execute('ALTER TABLE tags ALTER COLUMN tag SET DATA TYPE VARCHAR(255)'); + $database->execute('ALTER TABLE aliases ALTER COLUMN oldtag SET DATA TYPE VARCHAR(255)'); + $database->execute('ALTER TABLE aliases ALTER COLUMN newtag SET DATA TYPE VARCHAR(255)'); + } elseif ($database->get_driver_name() == 'mysql') { + $database->execute('ALTER TABLE tags MODIFY COLUMN tag VARCHAR(255) NOT NULL'); + $database->execute('ALTER TABLE aliases MODIFY COLUMN oldtag VARCHAR(255) NOT NULL'); + $database->execute('ALTER TABLE aliases MODIFY COLUMN newtag VARCHAR(255) NOT NULL'); + } - log_info("upgrade", "Database at version 14"); - $config->set_bool("in_upgrade", false); - } - } + log_info("upgrade", "Database at version 14"); + $config->set_bool("in_upgrade", false); + } + } - public function get_priority(): int {return 5;} + public function get_priority(): int + { + return 5; + } } - diff --git a/ext/upload/main.php b/ext/upload/main.php index 64715808..84279727 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -9,407 +9,424 @@ /** * Occurs when some data is being uploaded. */ -class DataUploadEvent extends Event { - /** @var string */ - public $tmpname; - /** @var array */ - public $metadata; - /** @var string */ - public $hash; - /** @var string */ - public $type; - /** @var int */ - public $image_id = -1; +class DataUploadEvent extends Event +{ + /** @var string */ + public $tmpname; + /** @var array */ + public $metadata; + /** @var string */ + public $hash; + /** @var string */ + public $type; + /** @var int */ + public $image_id = -1; - /** - * Some data is being uploaded. - * This should be caught by a file handler. - * $metadata should contain at least "filename", "extension", "tags" and "source". - */ - public function __construct(string $tmpname, array $metadata) { - assert(file_exists($tmpname)); - assert(is_string($metadata["filename"])); - assert(is_string($metadata["extension"])); - assert(is_array($metadata["tags"])); - assert(is_string($metadata["source"]) || is_null($metadata["source"])); + /** + * Some data is being uploaded. + * This should be caught by a file handler. + * $metadata should contain at least "filename", "extension", "tags" and "source". + */ + public function __construct(string $tmpname, array $metadata) + { + assert(file_exists($tmpname)); + assert(is_string($metadata["filename"])); + assert(is_string($metadata["extension"])); + assert(is_array($metadata["tags"])); + assert(is_string($metadata["source"]) || is_null($metadata["source"])); - $this->tmpname = $tmpname; + $this->tmpname = $tmpname; - $this->metadata = $metadata; - $this->metadata['hash'] = md5_file($tmpname); - $this->metadata['size'] = filesize($tmpname); + $this->metadata = $metadata; + $this->metadata['hash'] = md5_file($tmpname); + $this->metadata['size'] = filesize($tmpname); - // useful for most file handlers, so pull directly into fields - $this->hash = $this->metadata['hash']; - $this->type = strtolower($metadata['extension']); - } + // useful for most file handlers, so pull directly into fields + $this->hash = $this->metadata['hash']; + $this->type = strtolower($metadata['extension']); + } } -class UploadException extends SCoreException {} +class UploadException extends SCoreException +{ +} /** * Main upload class. * All files that are uploaded to the site are handled through this class. * This also includes transloaded files as well. */ -class Upload extends Extension { - /** @var bool */ - public $is_full; +class Upload extends Extension +{ + /** @var bool */ + public $is_full; - /** - * Early, so it can stop the DataUploadEvent before any data handlers see it. - */ - public function get_priority(): int {return 40;} + /** + * Early, so it can stop the DataUploadEvent before any data handlers see it. + */ + public function get_priority(): int + { + return 40; + } - public function onInitExt(InitExtEvent $event) { - global $config; - $config->set_default_int('upload_count', 3); - $config->set_default_int('upload_size', parse_shorthand_int('1MB')); - $config->set_default_int('upload_min_free_space', parse_shorthand_int('100MB')); - $config->set_default_bool('upload_tlsource', TRUE); + public function onInitExt(InitExtEvent $event) + { + global $config; + $config->set_default_int('upload_count', 3); + $config->set_default_int('upload_size', parse_shorthand_int('1MB')); + $config->set_default_int('upload_min_free_space', parse_shorthand_int('100MB')); + $config->set_default_bool('upload_tlsource', true); - $this->is_full = false; + $this->is_full = false; - $min_free_space = $config->get_int("upload_min_free_space"); - if($min_free_space > 0) { - // SHIT: fucking PHP "security" measures -_-;;; - $free_num = @disk_free_space(realpath("./images/")); - if($free_num !== FALSE) { - $this->is_full = $free_num < $min_free_space; - } - } - } + $min_free_space = $config->get_int("upload_min_free_space"); + if ($min_free_space > 0) { + // SHIT: fucking PHP "security" measures -_-;;; + $free_num = @disk_free_space(realpath("./images/")); + if ($free_num !== false) { + $this->is_full = $free_num < $min_free_space; + } + } + } - public function onSetupBuilding(SetupBuildingEvent $event) { - $tes = array(); - $tes["Disabled"] = "none"; - if(function_exists("curl_init")) { - $tes["cURL"] = "curl"; - } - $tes["fopen"] = "fopen"; - $tes["WGet"] = "wget"; + public function onSetupBuilding(SetupBuildingEvent $event) + { + $tes = []; + $tes["Disabled"] = "none"; + if (function_exists("curl_init")) { + $tes["cURL"] = "curl"; + } + $tes["fopen"] = "fopen"; + $tes["WGet"] = "wget"; - $sb = new SetupBlock("Upload"); - $sb->position = 10; - // Output the limits from PHP so the user has an idea of what they can set. - $sb->add_int_option("upload_count", "Max uploads: "); - $sb->add_label("PHP Limit = ".ini_get('max_file_uploads').""); - $sb->add_shorthand_int_option("upload_size", "
Max size per file: "); - $sb->add_label("PHP Limit = ".ini_get('upload_max_filesize').""); - $sb->add_choice_option("transload_engine", $tes, "
Transload: "); - $sb->add_bool_option("upload_tlsource", "
Use transloaded URL as source if none is provided: "); - $event->panel->add_block($sb); - } + $sb = new SetupBlock("Upload"); + $sb->position = 10; + // Output the limits from PHP so the user has an idea of what they can set. + $sb->add_int_option("upload_count", "Max uploads: "); + $sb->add_label("PHP Limit = ".ini_get('max_file_uploads').""); + $sb->add_shorthand_int_option("upload_size", "
Max size per file: "); + $sb->add_label("PHP Limit = ".ini_get('upload_max_filesize').""); + $sb->add_choice_option("transload_engine", $tes, "
Transload: "); + $sb->add_bool_option("upload_tlsource", "
Use transloaded URL as source if none is provided: "); + $event->panel->add_block($sb); + } - public function onDataUpload(DataUploadEvent $event) { - global $config; - if($this->is_full) { - throw new UploadException("Upload failed; disk nearly full"); - } - if(filesize($event->tmpname) > $config->get_int('upload_size')) { - $size = to_shorthand_int(filesize($event->tmpname)); - $limit = to_shorthand_int($config->get_int('upload_size')); - throw new UploadException("File too large ($size > $limit)"); - } - } + public function onDataUpload(DataUploadEvent $event) + { + global $config; + if ($this->is_full) { + throw new UploadException("Upload failed; disk nearly full"); + } + if (filesize($event->tmpname) > $config->get_int('upload_size')) { + $size = to_shorthand_int(filesize($event->tmpname)); + $limit = to_shorthand_int($config->get_int('upload_size')); + throw new UploadException("File too large ($size > $limit)"); + } + } - public function onPageRequest(PageRequestEvent $event) { - global $database, $page, $user; + public function onPageRequest(PageRequestEvent $event) + { + global $database, $page, $user; - if($user->can("create_image")) { - if($this->is_full) { - $this->theme->display_full($page); - } - else { - $this->theme->display_block($page); - } - } + if ($user->can("create_image")) { + if ($this->is_full) { + $this->theme->display_full($page); + } else { + $this->theme->display_block($page); + } + } - if($event->page_matches("upload/replace")) { - // check if the user is an administrator and can upload files. - if(!$user->can("replace_image")) { - $this->theme->display_permission_denied(); - } - else { - if($this->is_full) { - throw new UploadException("Can not replace Image: disk nearly full"); - } - // Try to get the image ID - $image_id = int_escape($event->get_arg(0)); - if(empty($image_id)) { - $image_id = isset($_POST['image_id']) ? $_POST['image_id'] : null; - } - if(empty($image_id)) { - throw new UploadException("Can not replace Image: No valid Image ID given."); - } + if ($event->page_matches("upload/replace")) { + // check if the user is an administrator and can upload files. + if (!$user->can("replace_image")) { + $this->theme->display_permission_denied(); + } else { + if ($this->is_full) { + throw new UploadException("Can not replace Image: disk nearly full"); + } + // Try to get the image ID + $image_id = int_escape($event->get_arg(0)); + if (empty($image_id)) { + $image_id = isset($_POST['image_id']) ? $_POST['image_id'] : null; + } + if (empty($image_id)) { + throw new UploadException("Can not replace Image: No valid Image ID given."); + } - $image_old = Image::by_id($image_id); - if(is_null($image_old)) { - $this->theme->display_error(404, "Image not found", "No image in the database has the ID #$image_id"); - } + $image_old = Image::by_id($image_id); + if (is_null($image_old)) { + $this->theme->display_error(404, "Image not found", "No image in the database has the ID #$image_id"); + } - if(count($_FILES) + count($_POST) > 0) { - if(count($_FILES) > 1) { - throw new UploadException("Can not upload more than one image for replacing."); - } - - $source = isset($_POST['source']) ? $_POST['source'] : null; - $tags = array(); // Tags aren't changed when replacing. Set to empty to stop PHP warnings. - - $ok = false; - if(count($_FILES)) { - foreach($_FILES as $file) { - $ok = $this->try_upload($file, $tags, $source, $image_id); - break; // leave the foreach loop. - } - } - else { - foreach($_POST as $name => $value) { - if(substr($name, 0, 3) == "url" && strlen($value) > 0) { - $ok = $this->try_transload($value, $tags, $source, $image_id); - break; // leave the foreach loop. - } - } - } - $database->cache->delete("thumb-block:{$image_id}"); - $this->theme->display_upload_status($page, $ok); - } - else if(!empty($_GET['url'])) { - $url = $_GET['url']; - $tags = isset($_GET['tags']) ? Tag::explode($_GET['tags']) : 'tagme'; - $source = isset($_GET['source']) ? $_GET['source'] : $url; - $ok = $this->try_transload($url, $tags, $source, $image_id); - $database->cache->delete("thumb-block:{$image_id}"); - $this->theme->display_upload_status($page, $ok); - } - else { - $this->theme->display_replace_page($page, $image_id); - } - } - } - else if($event->page_matches("upload")) { - if(!$user->can("create_image")) { - $this->theme->display_permission_denied(); - } - else { - /* Regular Upload Image */ - if(count($_FILES) + count($_POST) > 0) { - $ok = true; - foreach($_FILES as $name => $file) { - $tags = $this->tags_for_upload_slot(int_escape(substr($name, 4))); - $source = isset($_POST['source']) ? $_POST['source'] : null; - $ok = $ok & $this->try_upload($file, $tags, $source); - } - foreach($_POST as $name => $value) { - if(substr($name, 0, 3) == "url" && strlen($value) > 0) { - $tags = $this->tags_for_upload_slot(int_escape(substr($name, 3))); - $source = isset($_POST['source']) ? $_POST['source'] : $value; - $ok = $ok & $this->try_transload($value, $tags, $source); - } - } + if (count($_FILES) + count($_POST) > 0) { + if (count($_FILES) > 1) { + throw new UploadException("Can not upload more than one image for replacing."); + } + + $source = isset($_POST['source']) ? $_POST['source'] : null; + $tags = []; // Tags aren't changed when replacing. Set to empty to stop PHP warnings. + + $ok = false; + if (count($_FILES)) { + foreach ($_FILES as $file) { + $ok = $this->try_upload($file, $tags, $source, $image_id); + break; // leave the foreach loop. + } + } else { + foreach ($_POST as $name => $value) { + if (substr($name, 0, 3) == "url" && strlen($value) > 0) { + $ok = $this->try_transload($value, $tags, $source, $image_id); + break; // leave the foreach loop. + } + } + } + $database->cache->delete("thumb-block:{$image_id}"); + $this->theme->display_upload_status($page, $ok); + } elseif (!empty($_GET['url'])) { + $url = $_GET['url']; + $tags = isset($_GET['tags']) ? Tag::explode($_GET['tags']) : 'tagme'; + $source = isset($_GET['source']) ? $_GET['source'] : $url; + $ok = $this->try_transload($url, $tags, $source, $image_id); + $database->cache->delete("thumb-block:{$image_id}"); + $this->theme->display_upload_status($page, $ok); + } else { + $this->theme->display_replace_page($page, $image_id); + } + } + } elseif ($event->page_matches("upload")) { + if (!$user->can("create_image")) { + $this->theme->display_permission_denied(); + } else { + /* Regular Upload Image */ + if (count($_FILES) + count($_POST) > 0) { + $ok = true; + foreach ($_FILES as $name => $file) { + $tags = $this->tags_for_upload_slot(int_escape(substr($name, 4))); + $source = isset($_POST['source']) ? $_POST['source'] : null; + $ok = $ok & $this->try_upload($file, $tags, $source); + } + foreach ($_POST as $name => $value) { + if (substr($name, 0, 3) == "url" && strlen($value) > 0) { + $tags = $this->tags_for_upload_slot(int_escape(substr($name, 3))); + $source = isset($_POST['source']) ? $_POST['source'] : $value; + $ok = $ok & $this->try_transload($value, $tags, $source); + } + } - $this->theme->display_upload_status($page, $ok); - } - else if(!empty($_GET['url'])) { - $url = $_GET['url']; - $source = isset($_GET['source']) ? $_GET['source'] : $url; - $tags = array('tagme'); - if(!empty($_GET['tags']) && $_GET['tags'] != "null") { - $tags = Tag::explode($_GET['tags']); - } - - $ok = $this->try_transload($url, $tags, $source); - $this->theme->display_upload_status($page, $ok); - } - else { - if ($this->is_full) { - $this->theme->display_full($page); - } else { - $this->theme->display_page($page); - } - } - } - } - } + $this->theme->display_upload_status($page, $ok); + } elseif (!empty($_GET['url'])) { + $url = $_GET['url']; + $source = isset($_GET['source']) ? $_GET['source'] : $url; + $tags = ['tagme']; + if (!empty($_GET['tags']) && $_GET['tags'] != "null") { + $tags = Tag::explode($_GET['tags']); + } + + $ok = $this->try_transload($url, $tags, $source); + $this->theme->display_upload_status($page, $ok); + } else { + if ($this->is_full) { + $this->theme->display_full($page); + } else { + $this->theme->display_page($page); + } + } + } + } + } - private function tags_for_upload_slot(int $id): array { - $post_tags = isset($_POST["tags"]) ? $_POST["tags"] : ""; + private function tags_for_upload_slot(int $id): array + { + $post_tags = isset($_POST["tags"]) ? $_POST["tags"] : ""; - if(isset($_POST["tags$id"])) { - # merge then explode, not explode then merge - else - # one of the merges may create a surplus "tagme" - $tags = Tag::explode($post_tags . " " . $_POST["tags$id"]); - } - else { - $tags = Tag::explode($post_tags); - } - return $tags; - } + if (isset($_POST["tags$id"])) { + # merge then explode, not explode then merge - else + # one of the merges may create a surplus "tagme" + $tags = Tag::explode($post_tags . " " . $_POST["tags$id"]); + } else { + $tags = Tag::explode($post_tags); + } + return $tags; + } -// do things {{{ + // do things {{{ - /** - * Returns a descriptive error message for the specified PHP error code. - * - * This is a helper function based on the one from the online PHP Documentation - * which is licensed under Creative Commons Attribution 3.0 License - * - * TODO: Make these messages user/admin editable - */ - private function upload_error_message(int $error_code): string { - switch ($error_code) { - case UPLOAD_ERR_INI_SIZE: - return 'The uploaded file exceeds the upload_max_filesize directive in php.ini'; - case UPLOAD_ERR_FORM_SIZE: - return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'; - case UPLOAD_ERR_PARTIAL: - return 'The uploaded file was only partially uploaded'; - case UPLOAD_ERR_NO_FILE: - return 'No file was uploaded'; - case UPLOAD_ERR_NO_TMP_DIR: - return 'Missing a temporary folder'; - case UPLOAD_ERR_CANT_WRITE: - return 'Failed to write file to disk'; - case UPLOAD_ERR_EXTENSION: - return 'File upload stopped by extension'; - default: - return 'Unknown upload error'; - } - } + /** + * Returns a descriptive error message for the specified PHP error code. + * + * This is a helper function based on the one from the online PHP Documentation + * which is licensed under Creative Commons Attribution 3.0 License + * + * TODO: Make these messages user/admin editable + */ + private function upload_error_message(int $error_code): string + { + switch ($error_code) { + case UPLOAD_ERR_INI_SIZE: + return 'The uploaded file exceeds the upload_max_filesize directive in php.ini'; + case UPLOAD_ERR_FORM_SIZE: + return 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'; + case UPLOAD_ERR_PARTIAL: + return 'The uploaded file was only partially uploaded'; + case UPLOAD_ERR_NO_FILE: + return 'No file was uploaded'; + case UPLOAD_ERR_NO_TMP_DIR: + return 'Missing a temporary folder'; + case UPLOAD_ERR_CANT_WRITE: + return 'Failed to write file to disk'; + case UPLOAD_ERR_EXTENSION: + return 'File upload stopped by extension'; + default: + return 'Unknown upload error'; + } + } - /** - * Handle an upload. - * #param string[] $file - * #param string[] $tags - */ - private function try_upload(array $file, array $tags, ?string $source=null, int $replace=-1): bool { - global $page; + /** + * Handle an upload. + * #param string[] $file + * #param string[] $tags + */ + private function try_upload(array $file, array $tags, ?string $source=null, int $replace=-1): bool + { + global $page; - if(empty($source)) $source = null; + if (empty($source)) { + $source = null; + } - $ok = true; + $ok = true; - // blank file boxes cause empty uploads, no need for error message - if (!empty($file['name'])) { - try { - // check if the upload was successful - if ($file['error'] !== UPLOAD_ERR_OK) { - throw new UploadException($this->upload_error_message($file['error'])); - } - - $pathinfo = pathinfo($file['name']); - $metadata = array(); - $metadata['filename'] = $pathinfo['basename']; - $metadata['extension'] = $pathinfo['extension']; - $metadata['tags'] = $tags; - $metadata['source'] = $source; - - /* check if we have been given an image ID to replace */ - if ($replace >= 0) { - $metadata['replace'] = $replace; - } - - $event = new DataUploadEvent($file['tmp_name'], $metadata); - send_event($event); - if($event->image_id == -1) { - throw new UploadException("File type not recognised"); - } - $page->add_http_header("X-Shimmie-Image-ID: ".int_escape($event->image_id)); - } - catch(UploadException $ex) { - $this->theme->display_upload_error($page, "Error with ".html_escape($file['name']), - $ex->getMessage()); - $ok = false; - } - } + // blank file boxes cause empty uploads, no need for error message + if (!empty($file['name'])) { + try { + // check if the upload was successful + if ($file['error'] !== UPLOAD_ERR_OK) { + throw new UploadException($this->upload_error_message($file['error'])); + } + + $pathinfo = pathinfo($file['name']); + $metadata = []; + $metadata['filename'] = $pathinfo['basename']; + $metadata['extension'] = $pathinfo['extension']; + $metadata['tags'] = $tags; + $metadata['source'] = $source; + + /* check if we have been given an image ID to replace */ + if ($replace >= 0) { + $metadata['replace'] = $replace; + } + + $event = new DataUploadEvent($file['tmp_name'], $metadata); + send_event($event); + if ($event->image_id == -1) { + throw new UploadException("File type not recognised"); + } + $page->add_http_header("X-Shimmie-Image-ID: ".int_escape($event->image_id)); + } catch (UploadException $ex) { + $this->theme->display_upload_error( + $page, + "Error with ".html_escape($file['name']), + $ex->getMessage() + ); + $ok = false; + } + } - return $ok; - } + return $ok; + } - private function try_transload(string $url, array $tags, string $source=null, int $replace=-1): bool { - global $page, $config, $user; + private function try_transload(string $url, array $tags, string $source=null, int $replace=-1): bool + { + global $page, $config, $user; - $ok = true; + $ok = true; - // Checks if user is admin > check if you want locked. - if($user->can("edit_image_lock") && !empty($_GET['locked'])){ - $locked = bool_escape($_GET['locked']); - } - - // Checks if url contains rating, also checks if the rating extension is enabled. - if($config->get_string("transload_engine", "none") != "none" && ext_is_live("Ratings") && !empty($_GET['rating'])) { - // Rating event will validate that this is s/q/e/u - $rating = strtolower($_GET['rating']); - $rating = $rating[0]; - }else{ - $rating = ""; - } + // Checks if user is admin > check if you want locked. + if ($user->can("edit_image_lock") && !empty($_GET['locked'])) { + $locked = bool_escape($_GET['locked']); + } + + // Checks if url contains rating, also checks if the rating extension is enabled. + if ($config->get_string("transload_engine", "none") != "none" && ext_is_live("Ratings") && !empty($_GET['rating'])) { + // Rating event will validate that this is s/q/e/u + $rating = strtolower($_GET['rating']); + $rating = $rating[0]; + } else { + $rating = ""; + } - $tmp_filename = tempnam(ini_get('upload_tmp_dir'), "shimmie_transload"); + $tmp_filename = tempnam(ini_get('upload_tmp_dir'), "shimmie_transload"); - // transload() returns Array or Bool, depending on the transload_engine. - $headers = transload($url, $tmp_filename); - - $s_filename = is_array($headers) ? findHeader($headers, 'Content-Disposition') : null; - $h_filename = ($s_filename ? preg_replace('/^.*filename="([^ ]+)"/i', '$1', $s_filename) : null); - $filename = $h_filename ?: basename($url); + // transload() returns Array or Bool, depending on the transload_engine. + $headers = transload($url, $tmp_filename); + + $s_filename = is_array($headers) ? findHeader($headers, 'Content-Disposition') : null; + $h_filename = ($s_filename ? preg_replace('/^.*filename="([^ ]+)"/i', '$1', $s_filename) : null); + $filename = $h_filename ?: basename($url); - if(!$headers) { - $this->theme->display_upload_error($page, "Error with ".html_escape($filename), - "Error reading from ".html_escape($url)); - return false; - } + if (!$headers) { + $this->theme->display_upload_error( + $page, + "Error with ".html_escape($filename), + "Error reading from ".html_escape($url) + ); + return false; + } - if(filesize($tmp_filename) == 0) { - $this->theme->display_upload_error($page, "Error with ".html_escape($filename), - "No data found -- perhaps the site has hotlink protection?"); - $ok = false; - }else{ - $pathinfo = pathinfo($url); - $metadata = array(); - $metadata['filename'] = $filename; - $metadata['tags'] = $tags; - $metadata['source'] = (($url == $source) && !$config->get_bool('upload_tlsource') ? "" : $source); - - $ext = false; - if (is_array($headers)) { - $ext = getExtension(findHeader($headers, 'Content-Type')); - } - if ($ext === false) { - $ext = $pathinfo['extension']; - } - $metadata['extension'] = $ext; - - /* check for locked > adds to metadata if it has */ - if(!empty($locked)){ - $metadata['locked'] = $locked ? "on" : ""; - } + if (filesize($tmp_filename) == 0) { + $this->theme->display_upload_error( + $page, + "Error with ".html_escape($filename), + "No data found -- perhaps the site has hotlink protection?" + ); + $ok = false; + } else { + $pathinfo = pathinfo($url); + $metadata = []; + $metadata['filename'] = $filename; + $metadata['tags'] = $tags; + $metadata['source'] = (($url == $source) && !$config->get_bool('upload_tlsource') ? "" : $source); + + $ext = false; + if (is_array($headers)) { + $ext = getExtension(findHeader($headers, 'Content-Type')); + } + if ($ext === false) { + $ext = $pathinfo['extension']; + } + $metadata['extension'] = $ext; + + /* check for locked > adds to metadata if it has */ + if (!empty($locked)) { + $metadata['locked'] = $locked ? "on" : ""; + } - /* check for rating > adds to metadata if it has */ - if(!empty($rating)){ - $metadata['rating'] = $rating; - } - - /* check if we have been given an image ID to replace */ - if ($replace >= 0) { - $metadata['replace'] = $replace; - } - - $event = new DataUploadEvent($tmp_filename, $metadata); - try { - send_event($event); - } - catch(UploadException $ex) { - $this->theme->display_upload_error($page, "Error with ".html_escape($url), - $ex->getMessage()); - $ok = false; - } - } + /* check for rating > adds to metadata if it has */ + if (!empty($rating)) { + $metadata['rating'] = $rating; + } + + /* check if we have been given an image ID to replace */ + if ($replace >= 0) { + $metadata['replace'] = $replace; + } + + $event = new DataUploadEvent($tmp_filename, $metadata); + try { + send_event($event); + } catch (UploadException $ex) { + $this->theme->display_upload_error( + $page, + "Error with ".html_escape($url), + $ex->getMessage() + ); + $ok = false; + } + } - unlink($tmp_filename); + unlink($tmp_filename); - return $ok; - } -// }}} + return $ok; + } + // }}} } - diff --git a/ext/upload/test.php b/ext/upload/test.php index b1044202..8b4eb618 100644 --- a/ext/upload/test.php +++ b/ext/upload/test.php @@ -1,47 +1,50 @@ log_in_as_user(); +class UploadTest extends ShimmiePHPUnitTestCase +{ + public function testUploadPage() + { + $this->log_in_as_user(); - $this->get_page("upload"); - $this->assert_title("Upload"); - } + $this->get_page("upload"); + $this->assert_title("Upload"); + } - public function testUpload() { - $this->log_in_as_user(); - $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); - } + public function testUpload() + { + $this->log_in_as_user(); + $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + } - public function testRejectDupe() { - $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + public function testRejectDupe() + { + $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); - try { - $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); - } - catch(UploadException $e) { - $this->assertContains("already has hash", $e->getMessage()); - } - } + try { + $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + } catch (UploadException $e) { + $this->assertContains("already has hash", $e->getMessage()); + } + } - public function testRejectUnknownFiletype() { - try { - $this->post_image("index.php", "test"); - } - catch(UploadException $e) { - $this->assertContains("Invalid or corrupted file", $e->getMessage()); - } - } + public function testRejectUnknownFiletype() + { + try { + $this->post_image("index.php", "test"); + } catch (UploadException $e) { + $this->assertContains("Invalid or corrupted file", $e->getMessage()); + } + } - public function testRejectHuge() { - $this->markTestIncomplete(); + public function testRejectHuge() + { + $this->markTestIncomplete(); - // FIXME: huge.dat is rejected for other reasons; manual testing shows that this works - file_put_contents("huge.dat", file_get_contents("tests/pbx_screenshot.jpg") . str_repeat("U", 1024*1024*3)); - $this->post_image("index.php", "test"); - $this->assert_response(200); - $this->assert_title("Upload Status"); - $this->assert_text("File too large"); - unlink("huge.dat"); - } + // FIXME: huge.dat is rejected for other reasons; manual testing shows that this works + file_put_contents("huge.dat", file_get_contents("tests/pbx_screenshot.jpg") . str_repeat("U", 1024*1024*3)); + $this->post_image("index.php", "test"); + $this->assert_response(200); + $this->assert_title("Upload Status"); + $this->assert_text("File too large"); + unlink("huge.dat"); + } } - diff --git a/ext/upload/theme.php b/ext/upload/theme.php index 934a1f91..6f0c11da 100644 --- a/ext/upload/theme.php +++ b/ext/upload/theme.php @@ -1,23 +1,27 @@ add_block(new Block("Upload", $this->build_upload_block(), "left", 20)); - } +class UploadTheme extends Themelet +{ + public function display_block(Page $page) + { + $page->add_block(new Block("Upload", $this->build_upload_block(), "left", 20)); + } - public function display_full(Page $page) { - $page->add_block(new Block("Upload", "Disk nearly full, uploads disabled", "left", 20)); - } + public function display_full(Page $page) + { + $page->add_block(new Block("Upload", "Disk nearly full, uploads disabled", "left", 20)); + } - public function display_page(Page $page) { - global $config, $page; + public function display_page(Page $page) + { + global $config, $page; - $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); - $max_size = $config->get_int('upload_size'); - $max_kb = to_shorthand_int($max_size); - $upload_list = $this->h_upload_list_1(); - $html = " - ".make_form(make_link("upload"), "POST", $multipart=True, 'file_upload')." + $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); + $max_size = $config->get_int('upload_size'); + $max_kb = to_shorthand_int($max_size); + $upload_list = $this->h_upload_list_1(); + $html = " + ".make_form(make_link("upload"), "POST", $multipart=true, 'file_upload')."
Common Tags @@ -27,24 +31,25 @@ class UploadTheme extends Themelet { (Max file size is $max_kb) "; - - $page->set_title("Upload"); - $page->set_heading("Upload"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Upload", $html, "main", 20)); - if($tl_enabled) { - $page->add_block(new Block("Bookmarklets", $this->h_bookmarklets(), "left", 20)); - } - } + + $page->set_title("Upload"); + $page->set_heading("Upload"); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Upload", $html, "main", 20)); + if ($tl_enabled) { + $page->add_block(new Block("Bookmarklets", $this->h_bookmarklets(), "left", 20)); + } + } - protected function h_upload_list_1(): string { - global $config; - $upload_list = ""; - $upload_count = $config->get_int('upload_count'); - $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); + protected function h_upload_list_1(): string + { + global $config; + $upload_list = ""; + $upload_count = $config->get_int('upload_count'); + $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); - if($tl_enabled) { - $upload_list .= " + if ($tl_enabled) { + $upload_list .= " Common Source "; - for($i=0; $i<$upload_count; $i++) { - $upload_list .= " + for ($i=0; $i<$upload_count; $i++) { + $upload_list .= " Files URLs @@ -52,145 +57,145 @@ class UploadTheme extends Themelet {"; - } - } - else { - $upload_list .= " + } + } else { + $upload_list .= " "; - for($i=0; $i<$upload_count; $i++) { - $upload_list .= " + for ($i=0; $i<$upload_count; $i++) { + $upload_list .= " Files Image-Specific Tags "; - } - } + } + } - return $upload_list; - } + return $upload_list; + } - protected function h_upload_List_2(): string { - global $config; + protected function h_upload_List_2(): string + { + global $config; - $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); - // Uploader 2.0! - $upload_list = ""; - $upload_count = $config->get_int('upload_count'); - - for($i=0; $i<$upload_count; $i++) { - $a = $i+1; - $s = $i-1; - - if($i != 0) { - $upload_list .=" "; - }else{ - $upload_list .= " "; - } - - $upload_list .= " "; - - if($i == 0) { - $js = 'javascript:$(function() { + $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); + // Uploader 2.0! + $upload_list = ""; + $upload_count = $config->get_int('upload_count'); + + for ($i=0; $i<$upload_count; $i++) { + $a = $i+1; + $s = $i-1; + + if ($i != 0) { + $upload_list .=" "; + } else { + $upload_list .= " "; + } + + $upload_list .= " "; - } + } - return $upload_list; - } + return $upload_list; + } - protected function h_bookmarklets(): string { - global $config; - $link = make_http(make_link("upload")); - $main_page = make_http(make_link()); - $title = $config->get_string('title'); - $max_size = $config->get_int('upload_size'); - $max_kb = to_shorthand_int($max_size); - $delimiter = $config->get_bool('nice_urls') ? '?' : '&'; - $html = ''; + protected function h_bookmarklets(): string + { + global $config; + $link = make_http(make_link("upload")); + $main_page = make_http(make_link()); + $title = $config->get_string('title'); + $max_size = $config->get_int('upload_size'); + $max_kb = to_shorthand_int($max_size); + $delimiter = $config->get_bool('nice_urls') ? '?' : '&'; + $html = ''; - $js='javascript:( + $js='javascript:( function() { if(typeof window=="undefined" || !window.location || window.location.href=="about:blank") { window.location = "'. $main_page .'"; @@ -210,19 +215,29 @@ class UploadTheme extends Themelet { } } )();'; - $html .= 'Upload to '.$title.''; - $html .= ' (Drag & drop onto your bookmarks toolbar, then click when looking at an image)'; + $html .= 'Upload to '.$title.''; + $html .= ' (Drag & drop onto your bookmarks toolbar, then click when looking at an image)'; - // Bookmarklet checks if shimmie supports ext. If not, won't upload to site/shows alert saying not supported. - $supported_ext = "jpg jpeg gif png"; - if(class_exists("FlashFileHandler")){$supported_ext .= " swf";} - if(class_exists("ICOFileHandler")){$supported_ext .= " ico ani cur";} - if(class_exists("MP3FileHandler")){$supported_ext .= " mp3";} - if(class_exists("SVGFileHandler")){$supported_ext .= " svg";} - if(class_exists("VideoFileHandler")){$supported_ext .= " flv mp4 ogv webm m4v";} - $title = "Booru to " . $config->get_string('title'); - // CA=0: Ask to use current or new tags | CA=1: Always use current tags | CA=2: Always use new tags - $html .= '"; + + if ($i == 0) { + $js = 'javascript:$(function() { $("#row'.$a.'").show(); $("#hide'.$i.'").hide(); $("#hide'.$a.'").show();});'; - - $upload_list .= " + + $upload_list .= " "; - } else { - $js = 'javascript:$(function() { + } else { + $js = 'javascript:$(function() { $("#row'.$i.'").hide(); $("#hide'.$i.'").hide(); $("#hide'.$s.'").show(); $("#data'.$i.'").val(""); $("#url'.$i.'").val(""); });'; - - $upload_list .=" + + $upload_list .=" "; - - $js2 = 'javascript:$(function() { + + $upload_list .= + "". + ""; + } + $upload_list .= ""; + } + $upload_list .= ""; + + $js2 = 'javascript:$(function() { $("#url'.$i.'").hide(); $("#url'.$i.'").val(""); $("#data'.$i.'").show(); });'; - $upload_list .= " + $upload_list .= ""; - - if($a == $upload_count){ - $upload_list .=""; - } - else{ - $js1 = 'javascript:$(function() { + + if ($a == $upload_count) { + $upload_list .=""; + } else { + $js1 = 'javascript:$(function() { $("#row'.$a.'").show(); $("#hide'.$i.'").hide(); $("#hide'.$a.'").show(); });'; - - $upload_list .= - "". - ""; - } - $upload_list .= ""; - } - $upload_list .= "+ + $upload_list .= + " URL br> File
"; - - if($tl_enabled) { - $js = 'javascript:$(function() { + + if ($tl_enabled) { + $js = 'javascript:$(function() { $("#data'.$i.'").hide(); $("#data'.$i.'").val(""); $("#url'.$i.'").show(); });'; - - $upload_list .= - " URL br>"; - } else { - $upload_list .= " + } else { + $upload_list .= " "; - } - - $upload_list .= " + } + + $upload_list .= " get_string('title'); + // CA=0: Ask to use current or new tags | CA=1: Always use current tags | CA=2: Always use new tags + $html .= '
'. $title . ' (Click when looking at an image page. Works on sites running Shimmie / Danbooru / Gelbooru. (This also grabs the tags / rating / source!))'; - return $html; - } + return $html; + } - /** - * Only allows 1 file to be uploaded - for replacing another image file. - */ - public function display_replace_page(Page $page, int $image_id) { - global $config, $page; - $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); + /** + * Only allows 1 file to be uploaded - for replacing another image file. + */ + public function display_replace_page(Page $page, int $image_id) + { + global $config, $page; + $tl_enabled = ($config->get_string("transload_engine", "none") != "none"); - $upload_list = " + $upload_list = "
"; - if($tl_enabled) { - $upload_list .=" + if ($tl_enabled) { + $upload_list .=" File "; - } + } - $max_size = $config->get_int('upload_size'); - $max_kb = to_shorthand_int($max_size); - - $image = Image::by_id($image_id); - $thumbnail = $this->build_thumb_html($image); - - $html = " + $max_size = $config->get_int('upload_size'); + $max_kb = to_shorthand_int($max_size); + + $image = Image::by_id($image_id); + $thumbnail = $this->build_thumb_html($image); + + $html = " or URL Replacing Image ID ".$image_id."
" - .$thumbnail."
Please note: You will have to refresh the image page, or empty your browser cache.
" - .make_form(make_link("upload/replace/".$image_id), "POST", $multipart=True)." + .$thumbnail."
" + .make_form(make_link("upload/replace/".$image_id), "POST", $multipart=true)."$upload_list @@ -275,45 +291,51 @@ class UploadTheme extends Themelet { (Max file size is $max_kb) "; - $page->set_title("Replace Image"); - $page->set_heading("Replace Image"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Upload Replacement Image", $html, "main", 20)); - } + $page->set_title("Replace Image"); + $page->set_heading("Replace Image"); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Upload Replacement Image", $html, "main", 20)); + } - public function display_upload_status(Page $page, bool $ok) { - if($ok) { - $page->set_mode("redirect"); - $page->set_redirect(make_link()); - } - else { - $page->set_title("Upload Status"); - $page->set_heading("Upload Status"); - $page->add_block(new NavBlock()); - } - } + public function display_upload_status(Page $page, bool $ok) + { + if ($ok) { + $page->set_mode("redirect"); + $page->set_redirect(make_link()); + } else { + $page->set_title("Upload Status"); + $page->set_heading("Upload Status"); + $page->add_block(new NavBlock()); + } + } - public function display_upload_error(Page $page, string $title, string $message) { - $page->add_block(new Block($title, $message)); - } + public function display_upload_error(Page $page, string $title, string $message) + { + $page->add_block(new Block($title, $message)); + } - protected function build_upload_block(): string { - global $config; + protected function build_upload_block(): string + { + global $config; - $upload_list = ""; - $upload_count = $config->get_int('upload_count'); - - for($i=0; $i<$upload_count; $i++) { - if($i == 0) $style = ""; // "style='display:visible'"; - else $style = "style='display:none'"; - $upload_list .= "\n"; - } - $max_size = $config->get_int('upload_size'); - $max_kb = to_shorthand_int($max_size); - // - return " + $upload_list = ""; + $upload_count = $config->get_int('upload_count'); + + for ($i=0; $i<$upload_count; $i++) { + if ($i == 0) { + $style = ""; + } // "style='display:visible'"; + else { + $style = "style='display:none'"; + } + $upload_list .= "\n"; + } + $max_size = $config->get_int('upload_size'); + $max_kb = to_shorthand_int($max_size); + // + return "
- ".make_form(make_link("upload"), "POST", $multipart=True)." + ".make_form(make_link("upload"), "POST", $multipart=true)." $upload_list @@ -322,6 +344,5 @@ class UploadTheme extends Themelet {"; - } + } } - diff --git a/ext/user/main.php b/ext/user/main.php index b998469c..1d5033ff 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -5,563 +5,604 @@ * Description: Allows people to sign up to the website */ -class UserBlockBuildingEvent extends Event { - /** @var array */ - public $parts = array(); +class UserBlockBuildingEvent extends Event +{ + /** @var array */ + public $parts = []; - public function add_link(string $name, string $link, int $position=50) { - while(isset($this->parts[$position])) $position++; - $this->parts[$position] = array("name" => $name, "link" => $link); - } + public function add_link(string $name, string $link, int $position=50) + { + while (isset($this->parts[$position])) { + $position++; + } + $this->parts[$position] = ["name" => $name, "link" => $link]; + } } -class UserPageBuildingEvent extends Event { - /** @var \User */ - public $display_user; - /** @var array */ - public $stats = array(); +class UserPageBuildingEvent extends Event +{ + /** @var \User */ + public $display_user; + /** @var array */ + public $stats = []; - public function __construct(User $display_user) { - $this->display_user = $display_user; - } + public function __construct(User $display_user) + { + $this->display_user = $display_user; + } - public function add_stats(string $html, int $position=50) { - while(isset($this->stats[$position])) { $position++; } - $this->stats[$position] = $html; - } + public function add_stats(string $html, int $position=50) + { + while (isset($this->stats[$position])) { + $position++; + } + $this->stats[$position] = $html; + } } -class UserCreationEvent extends Event { - /** @var string */ - public $username; - /** @var string */ - public $password; - /** @var string */ - public $email; +class UserCreationEvent extends Event +{ + /** @var string */ + public $username; + /** @var string */ + public $password; + /** @var string */ + public $email; - public function __construct(string $name, string $pass, string $email) { - $this->username = $name; - $this->password = $pass; - $this->email = $email; - } + public function __construct(string $name, string $pass, string $email) + { + $this->username = $name; + $this->password = $pass; + $this->email = $email; + } } -class UserDeletionEvent extends Event { - /** @var int */ - public $id; +class UserDeletionEvent extends Event +{ + /** @var int */ + public $id; - public function __construct(int $id) { - $this->id = $id; - } + public function __construct(int $id) + { + $this->id = $id; + } } -class UserCreationException extends SCoreException {} +class UserCreationException extends SCoreException +{ +} -class NullUserException extends SCoreException {} +class NullUserException extends SCoreException +{ +} -class UserPage extends Extension { - /** @var UserPageTheme $theme */ - public $theme; +class UserPage extends Extension +{ + /** @var UserPageTheme $theme */ + public $theme; - public function onInitExt(InitExtEvent $event) { - global $config; - $config->set_default_bool("login_signup_enabled", true); - $config->set_default_int("login_memory", 365); - $config->set_default_string("avatar_host", "none"); - $config->set_default_int("avatar_gravatar_size", 80); - $config->set_default_string("avatar_gravatar_default", ""); - $config->set_default_string("avatar_gravatar_rating", "g"); - $config->set_default_bool("login_tac_bbcode", true); - } + public function onInitExt(InitExtEvent $event) + { + global $config; + $config->set_default_bool("login_signup_enabled", true); + $config->set_default_int("login_memory", 365); + $config->set_default_string("avatar_host", "none"); + $config->set_default_int("avatar_gravatar_size", 80); + $config->set_default_string("avatar_gravatar_default", ""); + $config->set_default_string("avatar_gravatar_rating", "g"); + $config->set_default_bool("login_tac_bbcode", true); + } - public function onPageRequest(PageRequestEvent $event) { - global $config, $database, $page, $user; + public function onPageRequest(PageRequestEvent $event) + { + global $config, $database, $page, $user; - $this->show_user_info(); + $this->show_user_info(); - if($event->page_matches("user_admin")) { - if($event->get_arg(0) == "login") { - if(isset($_POST['user']) && isset($_POST['pass'])) { - $this->page_login($_POST['user'], $_POST['pass']); - } - else { - $this->theme->display_login_page($page); - } - } - else if($event->get_arg(0) == "recover") { - $this->page_recover($_POST['username']); - } - else if($event->get_arg(0) == "create") { - $this->page_create(); - } - else if($event->get_arg(0) == "list") { - $limit = 50; + if ($event->page_matches("user_admin")) { + if ($event->get_arg(0) == "login") { + if (isset($_POST['user']) && isset($_POST['pass'])) { + $this->page_login($_POST['user'], $_POST['pass']); + } else { + $this->theme->display_login_page($page); + } + } elseif ($event->get_arg(0) == "recover") { + $this->page_recover($_POST['username']); + } elseif ($event->get_arg(0) == "create") { + $this->page_create(); + } elseif ($event->get_arg(0) == "list") { + $limit = 50; - $page_num = int_escape($event->get_arg(1)); - if($page_num <= 0) $page_num = 1; - $offset = ($page_num-1) * $limit; + $page_num = int_escape($event->get_arg(1)); + if ($page_num <= 0) { + $page_num = 1; + } + $offset = ($page_num-1) * $limit; - $q = "WHERE 1=1"; - $a = array(); + $q = "WHERE 1=1"; + $a = []; - if(@$_GET['username']) { - $q .= " AND SCORE_STRNORM(name) LIKE SCORE_STRNORM(:name)"; - $a["name"] = '%' . $_GET['username'] . '%'; - } + if (@$_GET['username']) { + $q .= " AND SCORE_STRNORM(name) LIKE SCORE_STRNORM(:name)"; + $a["name"] = '%' . $_GET['username'] . '%'; + } - if($user->can('delete_user') && @$_GET['email']) { - $q .= " AND SCORE_STRNORM(email) LIKE SCORE_STRNORM(:email)"; - $a["email"] = '%' . $_GET['email'] . '%'; - } + if ($user->can('delete_user') && @$_GET['email']) { + $q .= " AND SCORE_STRNORM(email) LIKE SCORE_STRNORM(:email)"; + $a["email"] = '%' . $_GET['email'] . '%'; + } - if(@$_GET['class']) { - $q .= " AND class LIKE :class"; - $a["class"] = $_GET['class']; - } - $where = $database->scoreql_to_sql($q); + if (@$_GET['class']) { + $q .= " AND class LIKE :class"; + $a["class"] = $_GET['class']; + } + $where = $database->scoreql_to_sql($q); - $count = $database->get_one("SELECT count(*) FROM users $where", $a); - $a["offset"] = $offset; - $a["limit"] = $limit; - $rows = $database->get_all("SELECT * FROM users $where LIMIT :limit OFFSET :offset", $a); - $users = array_map("_new_user", $rows); - $this->theme->display_user_list($page, $users, $user, $page_num, $count/$limit); - } - else if($event->get_arg(0) == "logout") { - $this->page_logout(); - } + $count = $database->get_one("SELECT count(*) FROM users $where", $a); + $a["offset"] = $offset; + $a["limit"] = $limit; + $rows = $database->get_all("SELECT * FROM users $where LIMIT :limit OFFSET :offset", $a); + $users = array_map("_new_user", $rows); + $this->theme->display_user_list($page, $users, $user, $page_num, $count/$limit); + } elseif ($event->get_arg(0) == "logout") { + $this->page_logout(); + } - if(!$user->check_auth_token()) { - return; - } + if (!$user->check_auth_token()) { + return; + } elseif ($event->get_arg(0) == "change_name") { + $input = validate_input([ + 'id' => 'user_id,exists', + 'name' => 'user_name', + ]); + $duser = User::by_id($input['id']); + $this->change_name_wrapper($duser, $input['name']); + } elseif ($event->get_arg(0) == "change_pass") { + $input = validate_input([ + 'id' => 'user_id,exists', + 'pass1' => 'password', + 'pass2' => 'password', + ]); + $duser = User::by_id($input['id']); + $this->change_password_wrapper($duser, $input['pass1'], $input['pass2']); + } elseif ($event->get_arg(0) == "change_email") { + $input = validate_input([ + 'id' => 'user_id,exists', + 'address' => 'email', + ]); + $duser = User::by_id($input['id']); + $this->change_email_wrapper($duser, $input['address']); + } elseif ($event->get_arg(0) == "change_class") { + $input = validate_input([ + 'id' => 'user_id,exists', + 'class' => 'user_class', + ]); + $duser = User::by_id($input['id']); + $this->change_class_wrapper($duser, $input['class']); + } elseif ($event->get_arg(0) == "delete_user") { + $this->delete_user($page, isset($_POST["with_images"]), isset($_POST["with_comments"])); + } + } - else if($event->get_arg(0) == "change_name") { - $input = validate_input(array( - 'id' => 'user_id,exists', - 'name' => 'user_name', - )); - $duser = User::by_id($input['id']); - $this->change_name_wrapper($duser, $input['name']); - } - else if($event->get_arg(0) == "change_pass") { - $input = validate_input(array( - 'id' => 'user_id,exists', - 'pass1' => 'password', - 'pass2' => 'password', - )); - $duser = User::by_id($input['id']); - $this->change_password_wrapper($duser, $input['pass1'], $input['pass2']); - } - else if($event->get_arg(0) == "change_email") { - $input = validate_input(array( - 'id' => 'user_id,exists', - 'address' => 'email', - )); - $duser = User::by_id($input['id']); - $this->change_email_wrapper($duser, $input['address']); - } - else if($event->get_arg(0) == "change_class") { - $input = validate_input(array( - 'id' => 'user_id,exists', - 'class' => 'user_class', - )); - $duser = User::by_id($input['id']); - $this->change_class_wrapper($duser, $input['class']); - } - else if($event->get_arg(0) == "delete_user") { - $this->delete_user($page, isset($_POST["with_images"]), isset($_POST["with_comments"])); - } - } + if ($event->page_matches("user")) { + $display_user = ($event->count_args() == 0) ? $user : User::by_name($event->get_arg(0)); + if ($event->count_args() == 0 && $user->is_anonymous()) { + $this->theme->display_error( + 401, + "Not Logged In", + "You aren't logged in. First do that, then you can see your stats." + ); + } elseif (!is_null($display_user) && ($display_user->id != $config->get_int("anon_id"))) { + $e = new UserPageBuildingEvent($display_user); + send_event($e); + $this->display_stats($e); + } else { + $this->theme->display_error( + 404, + "No Such User", + "If you typed the ID by hand, try again; if you came from a link on this ". + "site, it might be bug report time..." + ); + } + } + } - if($event->page_matches("user")) { - $display_user = ($event->count_args() == 0) ? $user : User::by_name($event->get_arg(0)); - if($event->count_args() == 0 && $user->is_anonymous()) { - $this->theme->display_error(401, "Not Logged In", - "You aren't logged in. First do that, then you can see your stats."); - } - else if(!is_null($display_user) && ($display_user->id != $config->get_int("anon_id"))) { - $e = new UserPageBuildingEvent($display_user); - send_event($e); - $this->display_stats($e); - } - else { - $this->theme->display_error(404, "No Such User", - "If you typed the ID by hand, try again; if you came from a link on this ". - "site, it might be bug report time..."); - } - } - } + public function onUserPageBuilding(UserPageBuildingEvent $event) + { + global $user, $config; - public function onUserPageBuilding(UserPageBuildingEvent $event) { - global $user, $config; + $h_join_date = autodate($event->display_user->join_date); + if ($event->display_user->can("hellbanned")) { + $h_class = $event->display_user->class->parent->name; + } else { + $h_class = $event->display_user->class->name; + } - $h_join_date = autodate($event->display_user->join_date); - if($event->display_user->can("hellbanned")) { - $h_class = $event->display_user->class->parent->name; - } - else { - $h_class = $event->display_user->class->name; - } + $event->add_stats("Joined: $h_join_date", 10); + $event->add_stats("Class: $h_class", 90); - $event->add_stats("Joined: $h_join_date", 10); - $event->add_stats("Class: $h_class", 90); + $av = $event->display_user->get_avatar_html(); + if ($av) { + $event->add_stats($av, 0); + } elseif (( + $config->get_string("avatar_host") == "gravatar" + ) && + ($user->id == $event->display_user->id) + ) { + $event->add_stats( + "No avatar? This gallery uses Gravatar for avatar hosting, use the". + "
same email address here and there to have your avatar synced
", + 0 + ); + } + } - $av = $event->display_user->get_avatar_html(); - if($av) { - $event->add_stats($av, 0); - } - else if(( - $config->get_string("avatar_host") == "gravatar") && - ($user->id == $event->display_user->id) - ) { - $event->add_stats( - "No avatar? This gallery uses Gravatar for avatar hosting, use the". - "
same email address here and there to have your avatar synced
", - 0 - ); - } - } + private function display_stats(UserPageBuildingEvent $event) + { + global $user, $page, $config; - private function display_stats(UserPageBuildingEvent $event) { - global $user, $page, $config; + ksort($event->stats); + $this->theme->display_user_page($event->display_user, $event->stats); + if ($user->id == $event->display_user->id) { + $ubbe = new UserBlockBuildingEvent(); + send_event($ubbe); + ksort($ubbe->parts); + $this->theme->display_user_links($page, $user, $ubbe->parts); + } + if ( + ($user->can("view_ip") || ($user->is_logged_in() && $user->id == $event->display_user->id)) && # admin or self-user + ($event->display_user->id != $config->get_int('anon_id')) # don't show anon's IP list, it is le huge + ) { + $this->theme->display_ip_list( + $page, + $this->count_upload_ips($event->display_user), + $this->count_comment_ips($event->display_user), + $this->count_log_ips($event->display_user) + ); + } + } - ksort($event->stats); - $this->theme->display_user_page($event->display_user, $event->stats); - if($user->id == $event->display_user->id) { - $ubbe = new UserBlockBuildingEvent(); - send_event($ubbe); - ksort($ubbe->parts); - $this->theme->display_user_links($page, $user, $ubbe->parts); - } - if( - ($user->can("view_ip") || ($user->is_logged_in() && $user->id == $event->display_user->id)) && # admin or self-user - ($event->display_user->id != $config->get_int('anon_id')) # don't show anon's IP list, it is le huge - ) { - $this->theme->display_ip_list( - $page, - $this->count_upload_ips($event->display_user), - $this->count_comment_ips($event->display_user), - $this->count_log_ips($event->display_user) - ); - } - } + public function onSetupBuilding(SetupBuildingEvent $event) + { + global $config; - public function onSetupBuilding(SetupBuildingEvent $event) { - global $config; + $hosts = [ + "None" => "none", + "Gravatar" => "gravatar" + ]; - $hosts = array( - "None" => "none", - "Gravatar" => "gravatar" - ); + $sb = new SetupBlock("User Options"); + $sb->add_bool_option("login_signup_enabled", "Allow new signups: "); + $sb->add_longtext_option("login_tac", "
Terms & Conditions:
"); + $sb->add_choice_option("avatar_host", $hosts, "
Avatars: "); - $sb = new SetupBlock("User Options"); - $sb->add_bool_option("login_signup_enabled", "Allow new signups: "); - $sb->add_longtext_option("login_tac", "
Terms & Conditions:
"); - $sb->add_choice_option("avatar_host", $hosts, "
Avatars: "); + if ($config->get_string("avatar_host") == "gravatar") { + $sb->add_label("
Gravatar Options"); + $sb->add_choice_option( + "avatar_gravatar_type", + [ + 'Default'=>'default', + 'Wavatar'=>'wavatar', + 'Monster ID'=>'monsterid', + 'Identicon'=>'identicon' + ], + "
Type: " + ); + $sb->add_choice_option( + "avatar_gravatar_rating", + ['G'=>'g', 'PG'=>'pg', 'R'=>'r', 'X'=>'x'], + "
Rating: " + ); + } - if($config->get_string("avatar_host") == "gravatar") { - $sb->add_label("
Gravatar Options"); - $sb->add_choice_option("avatar_gravatar_type", - array( - 'Default'=>'default', - 'Wavatar'=>'wavatar', - 'Monster ID'=>'monsterid', - 'Identicon'=>'identicon' - ), - "
Type: "); - $sb->add_choice_option("avatar_gravatar_rating", - array('G'=>'g', 'PG'=>'pg', 'R'=>'r', 'X'=>'x'), - "
Rating: "); - } + $sb->add_choice_option( + "user_loginshowprofile", + [ + "return to previous page" => 0, // 0 is default + "send to user profile" => 1], + "
When user logs in/out" + ); + $event->panel->add_block($sb); + } - $sb->add_choice_option("user_loginshowprofile", array( - "return to previous page" => 0, // 0 is default - "send to user profile" => 1), - "
When user logs in/out"); - $event->panel->add_block($sb); - } + public function onUserBlockBuilding(UserBlockBuildingEvent $event) + { + global $user; + $event->add_link("My Profile", make_link("user")); + if ($user->can("edit_user_class")) { + $event->add_link("User List", make_link("user_admin/list"), 98); + } + $event->add_link("Log Out", make_link("user_admin/logout"), 99); + } - public function onUserBlockBuilding(UserBlockBuildingEvent $event) { - global $user; - $event->add_link("My Profile", make_link("user")); - if($user->can("edit_user_class")) { - $event->add_link("User List", make_link("user_admin/list"), 98); - } - $event->add_link("Log Out", make_link("user_admin/logout"), 99); - } + public function onUserCreation(UserCreationEvent $event) + { + $this->check_user_creation($event); + $this->create_user($event); + } - public function onUserCreation(UserCreationEvent $event) { - $this->check_user_creation($event); - $this->create_user($event); - } + public function onSearchTermParse(SearchTermParseEvent $event) + { + global $user; - public function onSearchTermParse(SearchTermParseEvent $event) { - global $user; + $matches = []; + if (preg_match("/^(?:poster|user)[=|:](.*)$/i", $event->term, $matches)) { + $duser = User::by_name($matches[1]); + if (!is_null($duser)) { + $user_id = $duser->id; + } else { + $user_id = -1; + } + $event->add_querylet(new Querylet("images.owner_id = $user_id")); + } elseif (preg_match("/^(?:poster|user)_id[=|:]([0-9]+)$/i", $event->term, $matches)) { + $user_id = int_escape($matches[1]); + $event->add_querylet(new Querylet("images.owner_id = $user_id")); + } elseif ($user->can("view_ip") && preg_match("/^(?:poster|user)_ip[=|:]([0-9\.]+)$/i", $event->term, $matches)) { + $user_ip = $matches[1]; // FIXME: ip_escape? + $event->add_querylet(new Querylet("images.owner_ip = '$user_ip'")); + } + } - $matches = array(); - if(preg_match("/^(?:poster|user)[=|:](.*)$/i", $event->term, $matches)) { - $duser = User::by_name($matches[1]); - if(!is_null($duser)) { - $user_id = $duser->id; - } - else { - $user_id = -1; - } - $event->add_querylet(new Querylet("images.owner_id = $user_id")); - } - else if(preg_match("/^(?:poster|user)_id[=|:]([0-9]+)$/i", $event->term, $matches)) { - $user_id = int_escape($matches[1]); - $event->add_querylet(new Querylet("images.owner_id = $user_id")); - } - else if($user->can("view_ip") && preg_match("/^(?:poster|user)_ip[=|:]([0-9\.]+)$/i", $event->term, $matches)) { - $user_ip = $matches[1]; // FIXME: ip_escape? - $event->add_querylet(new Querylet("images.owner_ip = '$user_ip'")); - } - } - - private function show_user_info() { - global $user, $page; - // user info is shown on all pages - if ($user->is_anonymous()) { - $this->theme->display_login_block($page); - } else { - $ubbe = new UserBlockBuildingEvent(); - send_event($ubbe); - ksort($ubbe->parts); - $this->theme->display_user_block($page, $user, $ubbe->parts); - } - } -// }}} -// Things done *with* the user {{{ - private function page_login($name, $pass) { - global $config, $user, $page; + private function show_user_info() + { + global $user, $page; + // user info is shown on all pages + if ($user->is_anonymous()) { + $this->theme->display_login_block($page); + } else { + $ubbe = new UserBlockBuildingEvent(); + send_event($ubbe); + ksort($ubbe->parts); + $this->theme->display_user_block($page, $user, $ubbe->parts); + } + } + // }}} + // Things done *with* the user {{{ + private function page_login($name, $pass) + { + global $config, $user, $page; - if(empty($name) || empty($pass)) { - $this->theme->display_error(400, "Error", "Username or password left blank"); - return; - } + if (empty($name) || empty($pass)) { + $this->theme->display_error(400, "Error", "Username or password left blank"); + return; + } - $duser = User::by_name_and_pass($name, $pass); - if(!is_null($duser)) { - $user = $duser; - $this->set_login_cookie($duser->name, $pass); - $page->set_mode("redirect"); + $duser = User::by_name_and_pass($name, $pass); + if (!is_null($duser)) { + $user = $duser; + $this->set_login_cookie($duser->name, $pass); + $page->set_mode("redirect"); - // Try returning to previous page - if ($config->get_int("user_loginshowprofile",0) == 0 && - isset($_SERVER['HTTP_REFERER']) && - strstr($_SERVER['HTTP_REFERER'], "post/")) - { - $page->set_redirect($_SERVER['HTTP_REFERER']); - } else { - $page->set_redirect(make_link("user")); - } - } - else { - $this->theme->display_error(401, "Error", "No user with those details was found"); - } - } + // Try returning to previous page + if ($config->get_int("user_loginshowprofile", 0) == 0 && + isset($_SERVER['HTTP_REFERER']) && + strstr($_SERVER['HTTP_REFERER'], "post/")) { + $page->set_redirect($_SERVER['HTTP_REFERER']); + } else { + $page->set_redirect(make_link("user")); + } + } else { + $this->theme->display_error(401, "Error", "No user with those details was found"); + } + } - private function page_logout() { - global $page, $config; - $page->add_cookie("session", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/"); - if (CACHE_HTTP || SPEED_HAX) { - # to keep as few versions of content as possible, - # make cookies all-or-nothing - $page->add_cookie("user", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/"); - } - log_info("user", "Logged out"); - $page->set_mode("redirect"); + private function page_logout() + { + global $page, $config; + $page->add_cookie("session", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/"); + if (CACHE_HTTP || SPEED_HAX) { + # to keep as few versions of content as possible, + # make cookies all-or-nothing + $page->add_cookie("user", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/"); + } + log_info("user", "Logged out"); + $page->set_mode("redirect"); - // Try forwarding to same page on logout unless user comes from registration page - if ($config->get_int("user_loginshowprofile", 0) == 0 && - isset($_SERVER['HTTP_REFERER']) && - strstr($_SERVER['HTTP_REFERER'], "post/") - ) { - $page->set_redirect($_SERVER['HTTP_REFERER']); - } else { - $page->set_redirect(make_link()); - } - } + // Try forwarding to same page on logout unless user comes from registration page + if ($config->get_int("user_loginshowprofile", 0) == 0 && + isset($_SERVER['HTTP_REFERER']) && + strstr($_SERVER['HTTP_REFERER'], "post/") + ) { + $page->set_redirect($_SERVER['HTTP_REFERER']); + } else { + $page->set_redirect(make_link()); + } + } - private function page_recover(string $username) { - $user = User::by_name($username); - if (is_null($user)) { - $this->theme->display_error(404, "Error", "There's no user with that name"); - } else if (is_null($user->email)) { - $this->theme->display_error(400, "Error", "That user has no registered email address"); - } else { - // send email - } - } + private function page_recover(string $username) + { + $user = User::by_name($username); + if (is_null($user)) { + $this->theme->display_error(404, "Error", "There's no user with that name"); + } elseif (is_null($user->email)) { + $this->theme->display_error(400, "Error", "That user has no registered email address"); + } else { + // send email + } + } - private function page_create() { - global $config, $page; - if (!$config->get_bool("login_signup_enabled")) { - $this->theme->display_signups_disabled($page); - } else if (!isset($_POST['name'])) { - $this->theme->display_signup_page($page); - } else if ($_POST['pass1'] != $_POST['pass2']) { - $this->theme->display_error(400, "Password Mismatch", "Passwords don't match"); - } else { - try { - if (!captcha_check()) { - throw new UserCreationException("Error in captcha"); - } + private function page_create() + { + global $config, $page; + if (!$config->get_bool("login_signup_enabled")) { + $this->theme->display_signups_disabled($page); + } elseif (!isset($_POST['name'])) { + $this->theme->display_signup_page($page); + } elseif ($_POST['pass1'] != $_POST['pass2']) { + $this->theme->display_error(400, "Password Mismatch", "Passwords don't match"); + } else { + try { + if (!captcha_check()) { + throw new UserCreationException("Error in captcha"); + } - $uce = new UserCreationEvent($_POST['name'], $_POST['pass1'], $_POST['email']); - send_event($uce); - $this->set_login_cookie($uce->username, $uce->password); - $page->set_mode("redirect"); - $page->set_redirect(make_link("user")); - } catch (UserCreationException $ex) { - $this->theme->display_error(400, "User Creation Error", $ex->getMessage()); - } - } - } + $uce = new UserCreationEvent($_POST['name'], $_POST['pass1'], $_POST['email']); + send_event($uce); + $this->set_login_cookie($uce->username, $uce->password); + $page->set_mode("redirect"); + $page->set_redirect(make_link("user")); + } catch (UserCreationException $ex) { + $this->theme->display_error(400, "User Creation Error", $ex->getMessage()); + } + } + } - private function check_user_creation(UserCreationEvent $event) { - $name = $event->username; - //$pass = $event->password; - //$email = $event->email; + private function check_user_creation(UserCreationEvent $event) + { + $name = $event->username; + //$pass = $event->password; + //$email = $event->email; - if(strlen($name) < 1) { - throw new UserCreationException("Username must be at least 1 character"); - } - else if(!preg_match('/^[a-zA-Z0-9-_]+$/', $name)) { - throw new UserCreationException( - "Username contains invalid characters. Allowed characters are ". - "letters, numbers, dash, and underscore"); - } - else if(User::by_name($name)) { - throw new UserCreationException("That username is already taken"); - } - } + if (strlen($name) < 1) { + throw new UserCreationException("Username must be at least 1 character"); + } elseif (!preg_match('/^[a-zA-Z0-9-_]+$/', $name)) { + throw new UserCreationException( + "Username contains invalid characters. Allowed characters are ". + "letters, numbers, dash, and underscore" + ); + } elseif (User::by_name($name)) { + throw new UserCreationException("That username is already taken"); + } + } - private function create_user(UserCreationEvent $event) { - global $database, $user; + private function create_user(UserCreationEvent $event) + { + global $database, $user; - $email = (!empty($event->email)) ? $event->email : null; + $email = (!empty($event->email)) ? $event->email : null; - // if there are currently no admins, the new user should be one - $need_admin = ($database->get_one("SELECT COUNT(*) FROM users WHERE class='admin'") == 0); - $class = $need_admin ? 'admin' : 'user'; + // if there are currently no admins, the new user should be one + $need_admin = ($database->get_one("SELECT COUNT(*) FROM users WHERE class='admin'") == 0); + $class = $need_admin ? 'admin' : 'user'; - $database->Execute( - "INSERT INTO users (name, pass, joindate, email, class) VALUES (:username, :hash, now(), :email, :class)", - array("username"=>$event->username, "hash"=>'', "email"=>$email, "class"=>$class)); - $uid = $database->get_last_insert_id('users_id_seq'); - $user = User::by_name($event->username); - $user->set_password($event->password); - log_info("user", "Created User #$uid ({$event->username})"); - } + $database->Execute( + "INSERT INTO users (name, pass, joindate, email, class) VALUES (:username, :hash, now(), :email, :class)", + ["username"=>$event->username, "hash"=>'', "email"=>$email, "class"=>$class] + ); + $uid = $database->get_last_insert_id('users_id_seq'); + $user = User::by_name($event->username); + $user->set_password($event->password); + log_info("user", "Created User #$uid ({$event->username})"); + } - private function set_login_cookie(string $name, string $pass) { - global $config, $page; + private function set_login_cookie(string $name, string $pass) + { + global $config, $page; - $addr = get_session_ip($config); - $hash = User::by_name($name)->passhash; + $addr = get_session_ip($config); + $hash = User::by_name($name)->passhash; - $page->add_cookie("user", $name, - time()+60*60*24*365, '/'); - $page->add_cookie("session", md5($hash.$addr), - time()+60*60*24*$config->get_int('login_memory'), '/'); - } -//}}} -// Things done *to* the user {{{ - private function user_can_edit_user(User $a, User $b): bool { - if($a->is_anonymous()) { - $this->theme->display_error(401, "Error", "You aren't logged in"); - return false; - } + $page->add_cookie( + "user", + $name, + time()+60*60*24*365, + '/' + ); + $page->add_cookie( + "session", + md5($hash.$addr), + time()+60*60*24*$config->get_int('login_memory'), + '/' + ); + } + //}}} + // Things done *to* the user {{{ + private function user_can_edit_user(User $a, User $b): bool + { + if ($a->is_anonymous()) { + $this->theme->display_error(401, "Error", "You aren't logged in"); + return false; + } - if( - ($a->name == $b->name) || - ($b->can("protected") && $a->class->name == "admin") || - (!$b->can("protected") && $a->can("edit_user_info")) - ) { - return true; - } - else { - $this->theme->display_error(401, "Error", "You need to be an admin to change other people's details"); - return false; - } - } + if ( + ($a->name == $b->name) || + ($b->can("protected") && $a->class->name == "admin") || + (!$b->can("protected") && $a->can("edit_user_info")) + ) { + return true; + } else { + $this->theme->display_error(401, "Error", "You need to be an admin to change other people's details"); + return false; + } + } - private function redirect_to_user(User $duser) { - global $page, $user; + private function redirect_to_user(User $duser) + { + global $page, $user; - if($user->id == $duser->id) { - $page->set_mode("redirect"); - $page->set_redirect(make_link("user")); - } - else { - $page->set_mode("redirect"); - $page->set_redirect(make_link("user/{$duser->name}")); - } - } + if ($user->id == $duser->id) { + $page->set_mode("redirect"); + $page->set_redirect(make_link("user")); + } else { + $page->set_mode("redirect"); + $page->set_redirect(make_link("user/{$duser->name}")); + } + } - private function change_name_wrapper(User $duser, $name) { - global $user; + private function change_name_wrapper(User $duser, $name) + { + global $user; - if($user->can('edit_user_name') && $this->user_can_edit_user($user, $duser)) { - $duser->set_name($name); - flash_message("Username changed"); - // TODO: set login cookie if user changed themselves - $this->redirect_to_user($duser); - } - else { - $this->theme->display_error(400, "Error", "Permission denied"); - } - } + if ($user->can('edit_user_name') && $this->user_can_edit_user($user, $duser)) { + $duser->set_name($name); + flash_message("Username changed"); + // TODO: set login cookie if user changed themselves + $this->redirect_to_user($duser); + } else { + $this->theme->display_error(400, "Error", "Permission denied"); + } + } - private function change_password_wrapper(User $duser, string $pass1, string $pass2) { - global $user; + private function change_password_wrapper(User $duser, string $pass1, string $pass2) + { + global $user; - if($this->user_can_edit_user($user, $duser)) { - if($pass1 != $pass2) { - $this->theme->display_error(400, "Error", "Passwords don't match"); - } - else { - // FIXME: send_event() - $duser->set_password($pass1); + if ($this->user_can_edit_user($user, $duser)) { + if ($pass1 != $pass2) { + $this->theme->display_error(400, "Error", "Passwords don't match"); + } else { + // FIXME: send_event() + $duser->set_password($pass1); - if($duser->id == $user->id) { - $this->set_login_cookie($duser->name, $pass1); - } + if ($duser->id == $user->id) { + $this->set_login_cookie($duser->name, $pass1); + } - flash_message("Password changed"); - $this->redirect_to_user($duser); - } - } - } + flash_message("Password changed"); + $this->redirect_to_user($duser); + } + } + } - private function change_email_wrapper(User $duser, string $address) { - global $user; + private function change_email_wrapper(User $duser, string $address) + { + global $user; - if($this->user_can_edit_user($user, $duser)) { - $duser->set_email($address); + if ($this->user_can_edit_user($user, $duser)) { + $duser->set_email($address); - flash_message("Email changed"); - $this->redirect_to_user($duser); - } - } + flash_message("Email changed"); + $this->redirect_to_user($duser); + } + } - private function change_class_wrapper(User $duser, string $class) { - global $user; + private function change_class_wrapper(User $duser, string $class) + { + global $user; - if($user->class->name == "admin") { - $duser->set_class($class); - flash_message("Class changed"); - $this->redirect_to_user($duser); - } - } -// }}} -// ips {{{ - private function count_upload_ips(User $duser): array { - global $database; - $rows = $database->get_pairs(" + if ($user->class->name == "admin") { + $duser->set_class($class); + flash_message("Class changed"); + $this->redirect_to_user($duser); + } + } + // }}} + // ips {{{ + private function count_upload_ips(User $duser): array + { + global $database; + $rows = $database->get_pairs(" SELECT owner_ip, COUNT(images.id) AS count, @@ -569,13 +610,14 @@ class UserPage extends Extension { FROM images WHERE owner_id=:id GROUP BY owner_ip - ORDER BY most_recent DESC", array("id"=>$duser->id)); - return $rows; - } + ORDER BY most_recent DESC", ["id"=>$duser->id]); + return $rows; + } - private function count_comment_ips(User $duser): array { - global $database; - $rows = $database->get_pairs(" + private function count_comment_ips(User $duser): array + { + global $database; + $rows = $database->get_pairs(" SELECT owner_ip, COUNT(comments.id) AS count, @@ -583,14 +625,17 @@ class UserPage extends Extension { FROM comments WHERE owner_id=:id GROUP BY owner_ip - ORDER BY most_recent DESC", array("id"=>$duser->id)); - return $rows; - } + ORDER BY most_recent DESC", ["id"=>$duser->id]); + return $rows; + } - private function count_log_ips(User $duser): array { - if(!class_exists('LogDatabase')) return array(); - global $database; - $rows = $database->get_pairs(" + private function count_log_ips(User $duser): array + { + if (!class_exists('LogDatabase')) { + return []; + } + global $database; + $rows = $database->get_pairs(" SELECT address, COUNT(id) AS count, @@ -598,66 +643,64 @@ class UserPage extends Extension { FROM score_log WHERE username=:username GROUP BY address - ORDER BY most_recent DESC", array("username"=>$duser->name)); - return $rows; - } + ORDER BY most_recent DESC", ["username"=>$duser->name]); + return $rows; + } - private function delete_user(Page $page, bool $with_images=false, bool $with_comments=false) { - global $user, $config, $database; - - $page->set_title("Error"); - $page->set_heading("Error"); - $page->add_block(new NavBlock()); - - if (!$user->can("delete_user")) { - $page->add_block(new Block("Not Admin", "Only admins can delete accounts")); - } - else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { - $page->add_block(new Block("No ID Specified", - "You need to specify the account number to edit")); - } - else { - log_warning("user", "Deleting user #{$_POST['id']}"); + private function delete_user(Page $page, bool $with_images=false, bool $with_comments=false) + { + global $user, $config, $database; + + $page->set_title("Error"); + $page->set_heading("Error"); + $page->add_block(new NavBlock()); + + if (!$user->can("delete_user")) { + $page->add_block(new Block("Not Admin", "Only admins can delete accounts")); + } elseif (!isset($_POST['id']) || !is_numeric($_POST['id'])) { + $page->add_block(new Block( + "No ID Specified", + "You need to specify the account number to edit" + )); + } else { + log_warning("user", "Deleting user #{$_POST['id']}"); - if($with_images) { - log_warning("user", "Deleting user #{$_POST['id']}'s uploads"); - $rows = $database->get_all("SELECT * FROM images WHERE owner_id = :owner_id", array("owner_id" => $_POST['id'])); - foreach ($rows as $key => $value) { - $image = Image::by_id($value['id']); - if($image) { - send_event(new ImageDeletionEvent($image)); - } - } - } - else { - $database->Execute( - "UPDATE images SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id", - array("new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $_POST['id']) - ); - } + if ($with_images) { + log_warning("user", "Deleting user #{$_POST['id']}'s uploads"); + $rows = $database->get_all("SELECT * FROM images WHERE owner_id = :owner_id", ["owner_id" => $_POST['id']]); + foreach ($rows as $key => $value) { + $image = Image::by_id($value['id']); + if ($image) { + send_event(new ImageDeletionEvent($image)); + } + } + } else { + $database->Execute( + "UPDATE images SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id", + ["new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $_POST['id']] + ); + } - if($with_comments) { - log_warning("user", "Deleting user #{$_POST['id']}'s comments"); - $database->execute("DELETE FROM comments WHERE owner_id = :owner_id", array("owner_id" => $_POST['id'])); - } - else { - $database->Execute( - "UPDATE comments SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id", - array("new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $_POST['id']) - ); - } + if ($with_comments) { + log_warning("user", "Deleting user #{$_POST['id']}'s comments"); + $database->execute("DELETE FROM comments WHERE owner_id = :owner_id", ["owner_id" => $_POST['id']]); + } else { + $database->Execute( + "UPDATE comments SET owner_id = :new_owner_id WHERE owner_id = :old_owner_id", + ["new_owner_id" => $config->get_int('anon_id'), "old_owner_id" => $_POST['id']] + ); + } - send_event(new UserDeletionEvent($_POST['id'])); + send_event(new UserDeletionEvent($_POST['id'])); - $database->execute( - "DELETE FROM users WHERE id = :id", - array("id" => $_POST['id']) - ); - - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/list")); - } - } -// }}} + $database->execute( + "DELETE FROM users WHERE id = :id", + ["id" => $_POST['id']] + ); + + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/list")); + } + } + // }}} } - diff --git a/ext/user/test.php b/ext/user/test.php index 6e72ebc3..9b3d00af 100644 --- a/ext/user/test.php +++ b/ext/user/test.php @@ -1,41 +1,43 @@ get_page('user'); - $this->assert_title("Not Logged In"); - $this->assert_no_text("Options"); - $this->assert_no_text("More Options"); +class UserPageTest extends ShimmiePHPUnitTestCase +{ + public function testUserPage() + { + $this->get_page('user'); + $this->assert_title("Not Logged In"); + $this->assert_no_text("Options"); + $this->assert_no_text("More Options"); - $this->get_page('user/demo'); - $this->assert_title("demo's Page"); - $this->assert_text("Joined:"); + $this->get_page('user/demo'); + $this->assert_title("demo's Page"); + $this->assert_text("Joined:"); - $this->get_page('user/MauMau'); - $this->assert_title("No Such User"); + $this->get_page('user/MauMau'); + $this->assert_title("No Such User"); - $this->log_in_as_user(); - // should be on the user page - $this->get_page('user/test'); - $this->assert_title("test's Page"); - $this->assert_text("Options"); - // FIXME: check class - //$this->assert_no_text("Admin:"); - $this->log_out(); + $this->log_in_as_user(); + // should be on the user page + $this->get_page('user/test'); + $this->assert_title("test's Page"); + $this->assert_text("Options"); + // FIXME: check class + //$this->assert_no_text("Admin:"); + $this->log_out(); - $this->log_in_as_admin(); - // should be on the user page - $this->get_page('user/demo'); - $this->assert_title("demo's Page"); - $this->assert_text("Options"); - // FIXME: check class - //$this->assert_text("Admin:"); - $this->log_out(); + $this->log_in_as_admin(); + // should be on the user page + $this->get_page('user/demo'); + $this->assert_title("demo's Page"); + $this->assert_text("Options"); + // FIXME: check class + //$this->assert_text("Admin:"); + $this->log_out(); - # FIXME: test user creation - # FIXME: test adminifying - # FIXME: test password reset + # FIXME: test user creation + # FIXME: test adminifying + # FIXME: test password reset - $this->get_page('user_admin/list'); - $this->assert_text("demo"); - } + $this->get_page('user_admin/list'); + $this->assert_text("demo"); + } } diff --git a/ext/user/theme.php b/ext/user/theme.php index b53ac92d..45f6f08f 100644 --- a/ext/user/theme.php +++ b/ext/user/theme.php @@ -1,114 +1,137 @@ set_title("Login"); - $page->set_heading("Login"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Login There", - "There should be a login box to the left")); - } +class UserPageTheme extends Themelet +{ + public function display_login_page(Page $page) + { + $page->set_title("Login"); + $page->set_heading("Login"); + $page->add_block(new NavBlock()); + $page->add_block(new Block( + "Login There", + "There should be a login box to the left" + )); + } - /** - * #param User[] $users - */ - public function display_user_list(Page $page, array $users, User $user, int $page_num, int $page_total) { - $page->set_title("User List"); - $page->set_heading("User List"); - $page->add_block(new NavBlock()); + /** + * #param User[] $users + */ + public function display_user_list(Page $page, array $users, User $user, int $page_num, int $page_total) + { + $page->set_title("User List"); + $page->set_heading("User List"); + $page->add_block(new NavBlock()); - $html = ""; + $html = "
"; - $page->add_block(new Block("Users", $html)); - $this->display_paginator($page, "user_admin/list", $this->get_args(), $page_num, $page_total); - } + $page->add_block(new Block("Users", $html)); + $this->display_paginator($page, "user_admin/list", $this->get_args(), $page_num, $page_total); + } - protected function ueie($var) { - if(isset($_GET[$var])) return $var."=".url_escape($_GET[$var]); - else return ""; - } - protected function get_args() { - $args = ""; - // Check if each arg is actually empty and skip it if so - if(strlen($this->ueie("username"))) - $args .= $this->ueie("username")."&"; - if(strlen($this->ueie("email"))) - $args .= $this->ueie("email")."&"; - if(strlen($this->ueie("class"))) - $args .= $this->ueie("class")."&"; - // If there are no args at all, set $args to null to prevent an unnecessary ? at the end of the paginator url - if(strlen($args) == 0) - $args = null; - return $args; - } + protected function ueie($var) + { + if (isset($_GET[$var])) { + return $var."=".url_escape($_GET[$var]); + } else { + return ""; + } + } + protected function get_args() + { + $args = ""; + // Check if each arg is actually empty and skip it if so + if (strlen($this->ueie("username"))) { + $args .= $this->ueie("username")."&"; + } + if (strlen($this->ueie("email"))) { + $args .= $this->ueie("email")."&"; + } + if (strlen($this->ueie("class"))) { + $args .= $this->ueie("class")."&"; + } + // If there are no args at all, set $args to null to prevent an unnecessary ? at the end of the paginator url + if (strlen($args) == 0) { + $args = null; + } + return $args; + } - public function display_user_links(Page $page, User $user, $parts) { - # $page->add_block(new Block("User Links", join(", ", $parts), "main", 10)); - } + public function display_user_links(Page $page, User $user, $parts) + { + # $page->add_block(new Block("User Links", join(", ", $parts), "main", 10)); + } - public function display_user_block(Page $page, User $user, $parts) { - $h_name = html_escape($user->name); - $html = 'Logged in as '.$h_name; - foreach($parts as $part) { - $html .= '"; - $html .= "
"; + $html .= ""; - $html .= " "; + $html .= "Name "; - if($user->can('delete_user')) - $html .= "Class "; - $html .= "Action "; - $html .= ""; + $html .= " "; - $h_username = html_escape(@$_GET['username']); - $h_email = html_escape(@$_GET['email']); - $h_class = html_escape(@$_GET['class']); + $h_username = html_escape(@$_GET['username']); + $h_email = html_escape(@$_GET['email']); + $h_class = html_escape(@$_GET['class']); - $html .= "Name "; + if ($user->can('delete_user')) { + $html .= "Class "; + $html .= "Action "; + $html .= "" . make_form("user_admin/list", "GET"); - $html .= " "; + $html .= ""; - if($user->can('delete_user')) - $html .= " "; - $html .= " "; - $html .= " "; - $html .= " " . make_form("user_admin/list", "GET"); + $html .= " "; - foreach($users as $duser) { - $h_name = html_escape($duser->name); - $h_email = html_escape($duser->email); - $h_class = html_escape($duser->class->name); - $u_link = make_link("user/" . url_escape($duser->name)); - $u_posts = make_link("post/list/user_id=" . url_escape($duser->id) . "/1"); + foreach ($users as $duser) { + $h_name = html_escape($duser->name); + $h_email = html_escape($duser->email); + $h_class = html_escape($duser->class->name); + $u_link = make_link("user/" . url_escape($duser->name)); + $u_posts = make_link("post/list/user_id=" . url_escape($duser->id) . "/1"); - $html .= ""; + if ($user->can('delete_user')) { + $html .= " "; + } + $html .= " "; + $html .= " "; + $html .= " "; - $html .= " "; - } + $html .= "$h_name "; - if($user->can('delete_user')) - $html .= "$h_email "; - $html .= "$h_class "; - $html .= "Show Posts "; - $html .= ""; + $html .= " "; + } - $html .= "$h_name "; + if ($user->can('delete_user')) { + $html .= "$h_email "; + } + $html .= "$h_class "; + $html .= "Show Posts "; + $html .= "
'.$part["name"].''; - } - $page->add_block(new Block("User Links", $html, "left", 90)); - } + public function display_user_block(Page $page, User $user, $parts) + { + $h_name = html_escape($user->name); + $html = 'Logged in as '.$h_name; + foreach ($parts as $part) { + $html .= '
'.$part["name"].''; + } + $page->add_block(new Block("User Links", $html, "left", 90)); + } - public function display_signup_page(Page $page) { - global $config; - $tac = $config->get_string("login_tac", ""); + public function display_signup_page(Page $page) + { + global $config; + $tac = $config->get_string("login_tac", ""); - if($config->get_bool("login_tac_bbcode")) { - $tfe = new TextFormattingEvent($tac); - send_event($tfe); - $tac = $tfe->formatted; - } + if ($config->get_bool("login_tac_bbcode")) { + $tfe = new TextFormattingEvent($tac); + send_event($tfe); + $tac = $tfe->formatted; + } - if(empty($tac)) {$html = "";} - else {$html = ''.$tac.'
';} + if (empty($tac)) { + $html = ""; + } else { + $html = ''.$tac.'
'; + } - $h_reca = ""; + $h_reca = " ".captcha_get_html()." "; - $html .= ' + $html .= ' '.make_form(make_link("user_admin/create"))." ".captcha_get_html()." @@ -125,23 +148,27 @@ class UserPageTheme extends Themelet { "; - $page->set_title("Create Account"); - $page->set_heading("Create Account"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Signup", $html)); - } + $page->set_title("Create Account"); + $page->set_heading("Create Account"); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Signup", $html)); + } - public function display_signups_disabled(Page $page) { - $page->set_title("Signups Disabled"); - $page->set_heading("Signups Disabled"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Signups Disabled", - "The board admin has disabled the ability to create new accounts~")); - } + public function display_signups_disabled(Page $page) + { + $page->set_title("Signups Disabled"); + $page->set_heading("Signups Disabled"); + $page->add_block(new NavBlock()); + $page->add_block(new Block( + "Signups Disabled", + "The board admin has disabled the ability to create new accounts~" + )); + } - public function display_login_block(Page $page) { - global $config; - $html = ' + public function display_login_block(Page $page) + { + global $config; + $html = ' '.make_form(make_link("user_admin/login"))."
@@ -160,74 +187,77 @@ class UserPageTheme extends Themelet {
"; - if($config->get_bool("login_signup_enabled")) { - $html .= "Create Account"; - } - $page->add_block(new Block("Login", $html, "left", 90)); - } + if ($config->get_bool("login_signup_enabled")) { + $html .= "Create Account"; + } + $page->add_block(new Block("Login", $html, "left", 90)); + } - public function display_ip_list(Page $page, array $uploads, array $comments, array $events) { - $html = ""; - $html .= "
"; - $page->add_block(new Block("IPs", $html, "main", 70)); - } + $page->add_block(new Block("IPs", $html, "main", 70)); + } - public function display_user_page(User $duser, $stats) { - global $page, $user; - assert(is_array($stats)); - $stats[] = 'User ID: '.$duser->id; + public function display_user_page(User $duser, $stats) + { + global $page, $user; + assert(is_array($stats)); + $stats[] = 'User ID: '.$duser->id; - $page->set_title(html_escape($duser->name)."'s Page"); - $page->set_heading(html_escape($duser->name)."'s Page"); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Stats", join(""; + $html .= " Uploaded from: "; - $n = 0; - foreach($uploads as $ip => $count) { - $html .= '
'.$ip.' ('.$count.')'; - if(++$n >= 20) { - $html .= "
..."; - break; - } - } + public function display_ip_list(Page $page, array $uploads, array $comments, array $events) + { + $html = ""; + $html .= "
"; + $html .= ""; - $html .= " Uploaded from: "; + $n = 0; + foreach ($uploads as $ip => $count) { + $html .= '
'.$ip.' ('.$count.')'; + if (++$n >= 20) { + $html .= "
..."; + break; + } + } - $html .= "Commented from:"; - $n = 0; - foreach($comments as $ip => $count) { - $html .= '
'.$ip.' ('.$count.')'; - if(++$n >= 20) { - $html .= "
..."; - break; - } - } + $html .= "Commented from:"; + $n = 0; + foreach ($comments as $ip => $count) { + $html .= '
'.$ip.' ('.$count.')'; + if (++$n >= 20) { + $html .= "
..."; + break; + } + } - $html .= "Logged Events:"; - $n = 0; - foreach($events as $ip => $count) { - $html .= '
'.$ip.' ('.$count.')'; - if(++$n >= 20) { - $html .= "
..."; - break; - } - } + $html .= "Logged Events:"; + $n = 0; + foreach ($events as $ip => $count) { + $html .= '
'.$ip.' ('.$count.')'; + if (++$n >= 20) { + $html .= "
..."; + break; + } + } - $html .= "(Most recent at top) (Most recent at top)
", $stats), "main", 10)); + $page->set_title(html_escape($duser->name)."'s Page"); + $page->set_heading(html_escape($duser->name)."'s Page"); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Stats", join("
", $stats), "main", 10)); - if(!$user->is_anonymous()) { - if($user->id == $duser->id || $user->can("edit_user_info")) { - $page->add_block(new Block("Options", $this->build_options($duser), "main", 60)); - } - } - } + if (!$user->is_anonymous()) { + if ($user->id == $duser->id || $user->can("edit_user_info")) { + $page->add_block(new Block("Options", $this->build_options($duser), "main", 60)); + } + } + } - protected function build_options(User $duser) { - global $config, $user; - $html = ""; - if($duser->id != $config->get_int('anon_id')){ //justa fool-admin protection so they dont mess around with anon users. - - if($user->can('edit_user_name')) { - $html .= " + protected function build_options(User $duser) + { + global $config, $user; + $html = ""; + if ($duser->id != $config->get_int('anon_id')) { //justa fool-admin protection so they dont mess around with anon users. + + if ($user->can('edit_user_name')) { + $html .= "".make_form(make_link("user_admin/change_name"))."
@@ -237,9 +267,9 @@ class UserPageTheme extends Themelet {
"; - } + } - $html .= " + $html .= "".make_form(make_link("user_admin/change_pass"))."
@@ -266,18 +296,18 @@ class UserPageTheme extends Themelet { "; - $i_user_id = int_escape($duser->id); + $i_user_id = int_escape($duser->id); - if($user->can("edit_user_class")) { - global $_shm_user_classes; - $class_html = ""; - foreach($_shm_user_classes as $name => $values) { - $h_name = html_escape($name); - $h_title = html_escape(ucwords($name)); - $h_selected = ($name == $duser->class->name ? " selected" : ""); - $class_html .= "\n"; - } - $html .= " + if ($user->can("edit_user_class")) { + global $_shm_user_classes; + $class_html = ""; + foreach ($_shm_user_classes as $name => $values) { + $h_name = html_escape($name); + $h_title = html_escape(ucwords($name)); + $h_selected = ($name == $duser->class->name ? " selected" : ""); + $class_html .= "\n"; + } + $html .= "
".make_form(make_link("user_admin/change_class"))."
@@ -287,10 +317,10 @@ class UserPageTheme extends Themelet {
"; - } + } - if($user->can("delete_user")) { - $html .= " + if ($user->can("delete_user")) { + $html .= "".make_form(make_link("user_admin/delete_user"))."
@@ -308,10 +338,9 @@ class UserPageTheme extends Themelet {
"; - } - } - return $html; - } -// }}} + } + } + return $html; + } + // }}} } - diff --git a/ext/varnish/main.php b/ext/varnish/main.php index 6ac7831a..a90c4e13 100644 --- a/ext/varnish/main.php +++ b/ext/varnish/main.php @@ -7,33 +7,43 @@ * Description: Sends PURGE requests when a /post/view is updated */ -class VarnishPurger extends Extension { - private function curl_purge($path) { - // waiting for curl timeout adds ~5 minutes to unit tests - if(defined("UNITTEST")) return; +class VarnishPurger extends Extension +{ + private function curl_purge($path) + { + // waiting for curl timeout adds ~5 minutes to unit tests + if (defined("UNITTEST")) { + return; + } - $url = make_http(make_link($path)); - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PURGE"); - curl_setopt($ch, CURLOPT_TIMEOUT, 5); - $result = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - curl_close($ch); - //return $result; - } + $url = make_http(make_link($path)); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PURGE"); + curl_setopt($ch, CURLOPT_TIMEOUT, 5); + $result = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + //return $result; + } - public function onCommentPosting(CommentPostingEvent $event) { - $this->curl_purge("post/view/{$event->image_id}"); - } + public function onCommentPosting(CommentPostingEvent $event) + { + $this->curl_purge("post/view/{$event->image_id}"); + } - public function onImageInfoSet(ImageInfoSetEvent $event) { - $this->curl_purge("post/view/{$event->image->id}"); - } + public function onImageInfoSet(ImageInfoSetEvent $event) + { + $this->curl_purge("post/view/{$event->image->id}"); + } - public function onImageDeletion(ImageDeletionEvent $event) { - $this->curl_purge("post/view/{$event->image->id}"); - } + public function onImageDeletion(ImageDeletionEvent $event) + { + $this->curl_purge("post/view/{$event->image->id}"); + } - public function get_priority(): int {return 99;} + public function get_priority(): int + { + return 99; + } } diff --git a/ext/view/main.php b/ext/view/main.php index 7fe0c2a6..85415878 100644 --- a/ext/view/main.php +++ b/ext/view/main.php @@ -14,138 +14,152 @@ * wish to appear on the "view" page should listen for this, * which only appears when an image actually exists. */ -class DisplayingImageEvent extends Event { - /** @var \Image */ - public $image; +class DisplayingImageEvent extends Event +{ + /** @var \Image */ + public $image; - public function __construct(Image $image) { - $this->image = $image; - } + public function __construct(Image $image) + { + $this->image = $image; + } - public function get_image(): Image { - return $this->image; - } + public function get_image(): Image + { + return $this->image; + } } -class ImageInfoBoxBuildingEvent extends Event { - /** @var array */ - public $parts = array(); - /** @var \Image */ - public $image; - /** @var \User */ - public $user; +class ImageInfoBoxBuildingEvent extends Event +{ + /** @var array */ + public $parts = []; + /** @var \Image */ + public $image; + /** @var \User */ + public $user; - public function __construct(Image $image, User $user) { - $this->image = $image; - $this->user = $user; - } + public function __construct(Image $image, User $user) + { + $this->image = $image; + $this->user = $user; + } - public function add_part(string $html, int $position=50) { - while(isset($this->parts[$position])) $position++; - $this->parts[$position] = $html; - } + public function add_part(string $html, int $position=50) + { + while (isset($this->parts[$position])) { + $position++; + } + $this->parts[$position] = $html; + } } -class ImageInfoSetEvent extends Event { - /** @var \Image */ - public $image; +class ImageInfoSetEvent extends Event +{ + /** @var \Image */ + public $image; - public function __construct(Image $image) { - $this->image = $image; - } + public function __construct(Image $image) + { + $this->image = $image; + } } -class ImageAdminBlockBuildingEvent extends Event { - /** @var string[] */ - public $parts = array(); - /** @var \Image|null */ - public $image = null; - /** @var null|\User */ - public $user = null; +class ImageAdminBlockBuildingEvent extends Event +{ + /** @var string[] */ + public $parts = []; + /** @var \Image|null */ + public $image = null; + /** @var null|\User */ + public $user = null; - public function __construct(Image $image, User $user) { - $this->image = $image; - $this->user = $user; - } + public function __construct(Image $image, User $user) + { + $this->image = $image; + $this->user = $user; + } - public function add_part(string $html, int $position=50) { - while(isset($this->parts[$position])) $position++; - $this->parts[$position] = $html; - } + public function add_part(string $html, int $position=50) + { + while (isset($this->parts[$position])) { + $position++; + } + $this->parts[$position] = $html; + } } -class ViewImage extends Extension { - public function onPageRequest(PageRequestEvent $event) { - global $page, $user; +class ViewImage extends Extension +{ + public function onPageRequest(PageRequestEvent $event) + { + global $page, $user; - if($event->page_matches("post/prev") || $event->page_matches("post/next")) { - $image_id = int_escape($event->get_arg(0)); + if ($event->page_matches("post/prev") || $event->page_matches("post/next")) { + $image_id = int_escape($event->get_arg(0)); - if(isset($_GET['search'])) { - $search_terms = explode(' ', $_GET['search']); - $query = "#search=".url_escape($_GET['search']); - } - else { - $search_terms = array(); - $query = null; - } + if (isset($_GET['search'])) { + $search_terms = explode(' ', $_GET['search']); + $query = "#search=".url_escape($_GET['search']); + } else { + $search_terms = []; + $query = null; + } - $image = Image::by_id($image_id); - if(is_null($image)) { - $this->theme->display_error(404, "Image not found", "Image $image_id could not be found"); - return; - } + $image = Image::by_id($image_id); + if (is_null($image)) { + $this->theme->display_error(404, "Image not found", "Image $image_id could not be found"); + return; + } - if($event->page_matches("post/next")) { - $image = $image->get_next($search_terms); - } - else { - $image = $image->get_prev($search_terms); - } + if ($event->page_matches("post/next")) { + $image = $image->get_next($search_terms); + } else { + $image = $image->get_prev($search_terms); + } - if(is_null($image)) { - $this->theme->display_error(404, "Image not found", "No more images"); - return; - } + if (is_null($image)) { + $this->theme->display_error(404, "Image not found", "No more images"); + return; + } - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/view/{$image->id}", $query)); - } - else if($event->page_matches("post/view")) { - $image_id = int_escape($event->get_arg(0)); + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/view/{$image->id}", $query)); + } elseif ($event->page_matches("post/view")) { + $image_id = int_escape($event->get_arg(0)); - $image = Image::by_id($image_id); + $image = Image::by_id($image_id); - if(!is_null($image)) { - send_event(new DisplayingImageEvent($image)); - $iabbe = new ImageAdminBlockBuildingEvent($image, $user); - send_event($iabbe); - ksort($iabbe->parts); - $this->theme->display_admin_block($page, $iabbe->parts); - } - else { - $this->theme->display_error(404, "Image not found", "No image in the database has the ID #$image_id"); - } - } - else if($event->page_matches("post/set")) { - if(!isset($_POST['image_id'])) return; + if (!is_null($image)) { + send_event(new DisplayingImageEvent($image)); + $iabbe = new ImageAdminBlockBuildingEvent($image, $user); + send_event($iabbe); + ksort($iabbe->parts); + $this->theme->display_admin_block($page, $iabbe->parts); + } else { + $this->theme->display_error(404, "Image not found", "No image in the database has the ID #$image_id"); + } + } elseif ($event->page_matches("post/set")) { + if (!isset($_POST['image_id'])) { + return; + } - $image_id = int_escape($_POST['image_id']); + $image_id = int_escape($_POST['image_id']); - send_event(new ImageInfoSetEvent(Image::by_id($image_id))); + send_event(new ImageInfoSetEvent(Image::by_id($image_id))); - $page->set_mode("redirect"); - $page->set_redirect(make_link("post/view/$image_id", url_escape(@$_POST['query']))); - } - } + $page->set_mode("redirect"); + $page->set_redirect(make_link("post/view/$image_id", url_escape(@$_POST['query']))); + } + } - public function onDisplayingImage(DisplayingImageEvent $event) { - global $user; - $iibbe = new ImageInfoBoxBuildingEvent($event->get_image(), $user); - send_event($iibbe); - ksort($iibbe->parts); - $this->theme->display_meta_headers($event->get_image()); - $this->theme->display_page($event->get_image(), $iibbe->parts); - } + public function onDisplayingImage(DisplayingImageEvent $event) + { + global $user; + $iibbe = new ImageInfoBoxBuildingEvent($event->get_image(), $user); + send_event($iibbe); + ksort($iibbe->parts); + $this->theme->display_meta_headers($event->get_image()); + $this->theme->display_page($event->get_image(), $iibbe->parts); + } } - diff --git a/ext/view/test.php b/ext/view/test.php index d4ae305c..d3d118f0 100644 --- a/ext/view/test.php +++ b/ext/view/test.php @@ -1,66 +1,71 @@ log_in_as_user(); - $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); - $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); - $image_id_3 = $this->post_image("tests/favicon.png", "test"); - $idp1 = $image_id_3 + 1; + public function testViewPage() + { + $this->log_in_as_user(); + $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); + $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); + $image_id_3 = $this->post_image("tests/favicon.png", "test"); + $idp1 = $image_id_3 + 1; - $this->get_page("post/view/$image_id_1"); - $this->assert_title("Image $image_id_1: test"); - } + $this->get_page("post/view/$image_id_1"); + $this->assert_title("Image $image_id_1: test"); + } - public function testPrevNext() { - $this->markTestIncomplete(); + public function testPrevNext() + { + $this->markTestIncomplete(); - $this->log_in_as_user(); - $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); - $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); - $image_id_3 = $this->post_image("tests/favicon.png", "test"); + $this->log_in_as_user(); + $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); + $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); + $image_id_3 = $this->post_image("tests/favicon.png", "test"); - $this->click("Prev"); - $this->assert_title("Image $image_id_2: test2"); + $this->click("Prev"); + $this->assert_title("Image $image_id_2: test2"); - $this->click("Next"); - $this->assert_title("Image $image_id_1: test"); + $this->click("Next"); + $this->assert_title("Image $image_id_1: test"); - $this->click("Next"); - $this->assert_title("Image not found"); - } + $this->click("Next"); + $this->assert_title("Image not found"); + } - public function testView404() { - $this->log_in_as_user(); - $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); - $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); - $image_id_3 = $this->post_image("tests/favicon.png", "test"); - $idp1 = $image_id_3 + 1; + public function testView404() + { + $this->log_in_as_user(); + $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); + $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); + $image_id_3 = $this->post_image("tests/favicon.png", "test"); + $idp1 = $image_id_3 + 1; - $this->get_page("post/view/$idp1"); - $this->assert_title('Image not found'); + $this->get_page("post/view/$idp1"); + $this->assert_title('Image not found'); - $this->get_page('post/view/-1'); - $this->assert_title('Image not found'); - } + $this->get_page('post/view/-1'); + $this->assert_title('Image not found'); + } - public function testNextSearchResult() { - $this->markTestIncomplete(); + public function testNextSearchResult() + { + $this->markTestIncomplete(); - $this->log_in_as_user(); - $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); - $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); - $image_id_3 = $this->post_image("tests/favicon.png", "test"); + $this->log_in_as_user(); + $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test"); + $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2"); + $image_id_3 = $this->post_image("tests/favicon.png", "test"); - // FIXME: this assumes Nice URLs. - # note: skips image #2 - $this->get_page("post/view/$image_id_1?search=test"); // FIXME: assumes niceurls - $this->click("Prev"); - $this->assert_title("Image $image_id_3: test"); - } + // FIXME: this assumes Nice URLs. + # note: skips image #2 + $this->get_page("post/view/$image_id_1?search=test"); // FIXME: assumes niceurls + $this->click("Prev"); + $this->assert_title("Image $image_id_3: test"); + } } - diff --git a/ext/view/theme.php b/ext/view/theme.php index 8c16712c..82bd51f4 100644 --- a/ext/view/theme.php +++ b/ext/view/theme.php @@ -1,55 +1,60 @@ get_tag_list())); - $page->add_html_header(""); - $page->add_html_header(""); - $page->add_html_header(""); - $page->add_html_header("get_thumb_link())."\">"); - $page->add_html_header("id}"))."\">"); - } + $h_metatags = str_replace(" ", ", ", html_escape($image->get_tag_list())); + $page->add_html_header(""); + $page->add_html_header(""); + $page->add_html_header(""); + $page->add_html_header("get_thumb_link())."\">"); + $page->add_html_header("id}"))."\">"); + } - /* - * Build a page showing $image and some info about it - */ - public function display_page(Image $image, $editor_parts) { - global $page; + /* + * Build a page showing $image and some info about it + */ + public function display_page(Image $image, $editor_parts) + { + global $page; - $page->set_title("Image {$image->id}: ".html_escape($image->get_tag_list())); - $page->set_heading(html_escape($image->get_tag_list())); - $page->add_block(new Block("Navigation", $this->build_navigation($image), "left", 0)); - $page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 20)); - //$page->add_block(new Block(null, $this->build_pin($image), "main", 11)); - } + $page->set_title("Image {$image->id}: ".html_escape($image->get_tag_list())); + $page->set_heading(html_escape($image->get_tag_list())); + $page->add_block(new Block("Navigation", $this->build_navigation($image), "left", 0)); + $page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 20)); + //$page->add_block(new Block(null, $this->build_pin($image), "main", 11)); + } - public function display_admin_block(Page $page, $parts) { - if(count($parts) > 0) { - $page->add_block(new Block("Image Controls", join("
", $parts), "left", 50)); - } - } + public function display_admin_block(Page $page, $parts) + { + if (count($parts) > 0) { + $page->add_block(new Block("Image Controls", join("
", $parts), "left", 50)); + } + } - protected function build_pin(Image $image) { - if(isset($_GET['search'])) { - $query = "search=".url_escape($_GET['search']); - } - else { - $query = null; - } + protected function build_pin(Image $image) + { + if (isset($_GET['search'])) { + $query = "search=".url_escape($_GET['search']); + } else { + $query = null; + } - $h_prev = "Prev"; - $h_index = "Index"; - $h_next = "Next"; + $h_prev = "Prev"; + $h_index = "Index"; + $h_next = "Next"; - return "$h_prev | $h_index | $h_next"; - } + return "$h_prev | $h_index | $h_next"; + } - protected function build_navigation(Image $image): string { - $h_pin = $this->build_pin($image); - $h_search = " + protected function build_navigation(Image $image): string + { + $h_pin = $this->build_pin($image); + $h_search = "@@ -57,37 +62,39 @@ class ViewImageTheme extends Themelet { "; - return "$h_pin
$h_search"; - } + return "$h_pin
$h_search"; + } - protected function build_info(Image $image, $editor_parts) { - global $user; + protected function build_info(Image $image, $editor_parts) + { + global $user; - if(count($editor_parts) == 0) return ($image->is_locked() ? "
[Image Locked]" : ""); + if (count($editor_parts) == 0) { + return ($image->is_locked() ? "
[Image Locked]" : ""); + } - $html = make_form(make_link("post/set"))." + $html = make_form(make_link("post/set")).""; - foreach($editor_parts as $part) { - $html .= $part; - } - if( - (!$image->is_locked() || $user->can("edit_image_lock")) && - $user->can("edit_image_tag") - ) { - $html .= " + foreach ($editor_parts as $part) { + $html .= $part; + } + if ( + (!$image->is_locked() || $user->can("edit_image_lock")) && + $user->can("edit_image_tag") + ) { + $html .= "
"; - return $html; - } + return $html; + } } - diff --git a/ext/wiki/main.php b/ext/wiki/main.php index b85ab7c1..e0e14c8b 100644 --- a/ext/wiki/main.php +++ b/ext/wiki/main.php @@ -8,76 +8,85 @@ * Standard formatting APIs are used (This will be BBCode by default) */ -class WikiUpdateEvent extends Event { - /** @var \User */ - public $user; - /** @var \WikiPage */ - public $wikipage; +class WikiUpdateEvent extends Event +{ + /** @var \User */ + public $user; + /** @var \WikiPage */ + public $wikipage; - public function __construct(User $user, WikiPage $wikipage) { - $this->user = $user; - $this->wikipage = $wikipage; - } + public function __construct(User $user, WikiPage $wikipage) + { + $this->user = $user; + $this->wikipage = $wikipage; + } } -class WikiUpdateException extends SCoreException { +class WikiUpdateException extends SCoreException +{ } -class WikiPage { - /** @var int|string */ - public $id; +class WikiPage +{ + /** @var int|string */ + public $id; - /** @var int */ - public $owner_id; + /** @var int */ + public $owner_id; - /** @var string */ - public $owner_ip; + /** @var string */ + public $owner_ip; - /** @var string */ - public $date; + /** @var string */ + public $date; - /** @var string */ - public $title; + /** @var string */ + public $title; - /** @var int */ - public $revision; + /** @var int */ + public $revision; - /** @var bool */ - public $locked; + /** @var bool */ + public $locked; - /** @var string */ - public $body; + /** @var string */ + public $body; - public function __construct(array $row=null) { - //assert(!empty($row)); + public function __construct(array $row=null) + { + //assert(!empty($row)); - if (!is_null($row)) { - $this->id = $row['id']; - $this->owner_id = $row['owner_id']; - $this->owner_ip = $row['owner_ip']; - $this->date = $row['date']; - $this->title = $row['title']; - $this->revision = $row['revision']; - $this->locked = ($row['locked'] == 'Y'); - $this->body = $row['body']; - } - } + if (!is_null($row)) { + $this->id = $row['id']; + $this->owner_id = $row['owner_id']; + $this->owner_ip = $row['owner_ip']; + $this->date = $row['date']; + $this->title = $row['title']; + $this->revision = $row['revision']; + $this->locked = ($row['locked'] == 'Y'); + $this->body = $row['body']; + } + } - public function get_owner(): User { - return User::by_id($this->owner_id); - } + public function get_owner(): User + { + return User::by_id($this->owner_id); + } - public function is_locked(): bool { - return $this->locked; - } + public function is_locked(): bool + { + return $this->locked; + } } -class Wiki extends Extension { - public function onInitExt(InitExtEvent $event) { - global $database, $config; +class Wiki extends Extension +{ + public function onInitExt(InitExtEvent $event) + { + global $database, $config; - if($config->get_int("ext_wiki_version", 0) < 1) { - $database->create_table("wiki_pages", " + if ($config->get_int("ext_wiki_version", 0) < 1) { + $database->create_table("wiki_pages", " id SCORE_AIPK, owner_id INTEGER NOT NULL, owner_ip SCORE_INET NOT NULL, @@ -89,412 +98,399 @@ class Wiki extends Extension { UNIQUE (title, revision), FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT "); - $config->set_int("ext_wiki_version", 2); - } - if($config->get_int("ext_wiki_version") < 2) { - $database->Execute("ALTER TABLE wiki_pages ADD COLUMN + $config->set_int("ext_wiki_version", 2); + } + if ($config->get_int("ext_wiki_version") < 2) { + $database->Execute("ALTER TABLE wiki_pages ADD COLUMN locked ENUM('Y', 'N') DEFAULT 'N' NOT NULL AFTER REVISION"); - $config->set_int("ext_wiki_version", 2); - } - } + $config->set_int("ext_wiki_version", 2); + } + } - public function onPageRequest(PageRequestEvent $event) { - global $page, $user; - if($event->page_matches("wiki")) { - if(is_null($event->get_arg(0)) || strlen(trim($event->get_arg(0))) === 0) { - $title = "Index"; - } - else { - $title = $event->get_arg(0); - } + public function onPageRequest(PageRequestEvent $event) + { + global $page, $user; + if ($event->page_matches("wiki")) { + if (is_null($event->get_arg(0)) || strlen(trim($event->get_arg(0))) === 0) { + $title = "Index"; + } else { + $title = $event->get_arg(0); + } - $content = $this->get_page($title); - $this->theme->display_page($page, $content, $this->get_page("wiki:sidebar")); - } - else if($event->page_matches("wiki_admin/edit")) { - $content = $this->get_page($_POST['title']); - $this->theme->display_page_editor($page, $content); - } - else if($event->page_matches("wiki_admin/save")) { - $title = $_POST['title']; - $rev = int_escape($_POST['revision']); - $body = $_POST['body']; - $lock = $user->is_admin() && isset($_POST['lock']) && ($_POST['lock'] == "on"); + $content = $this->get_page($title); + $this->theme->display_page($page, $content, $this->get_page("wiki:sidebar")); + } elseif ($event->page_matches("wiki_admin/edit")) { + $content = $this->get_page($_POST['title']); + $this->theme->display_page_editor($page, $content); + } elseif ($event->page_matches("wiki_admin/save")) { + $title = $_POST['title']; + $rev = int_escape($_POST['revision']); + $body = $_POST['body']; + $lock = $user->is_admin() && isset($_POST['lock']) && ($_POST['lock'] == "on"); - if($this->can_edit($user, $this->get_page($title))) { - $wikipage = $this->get_page($title); - $wikipage->revision = $rev; - $wikipage->body = $body; - $wikipage->locked = $lock; - try { - send_event(new WikiUpdateEvent($user, $wikipage)); + if ($this->can_edit($user, $this->get_page($title))) { + $wikipage = $this->get_page($title); + $wikipage->revision = $rev; + $wikipage->body = $body; + $wikipage->locked = $lock; + try { + send_event(new WikiUpdateEvent($user, $wikipage)); - $u_title = url_escape($title); - $page->set_mode("redirect"); - $page->set_redirect(make_link("wiki/$u_title")); - } - catch(WikiUpdateException $e) { - $original = $this->get_page($title); - // @ because arr_diff is full of warnings - $original->body = @$this->arr_diff( - explode("\n", $original->body), - explode("\n", $wikipage->body) - ); - $this->theme->display_page_editor($page, $original); - } - } - else { - $this->theme->display_permission_denied(); - } - } - else if($event->page_matches("wiki_admin/delete_revision")) { - if($user->is_admin()) { - global $database; - $database->Execute( - "DELETE FROM wiki_pages WHERE title=:title AND revision=:rev", - array("title"=>$_POST["title"], "rev"=>$_POST["revision"])); - $u_title = url_escape($_POST["title"]); - $page->set_mode("redirect"); - $page->set_redirect(make_link("wiki/$u_title")); - } - } - else if($event->page_matches("wiki_admin/delete_all")) { - if($user->is_admin()) { - global $database; - $database->Execute( - "DELETE FROM wiki_pages WHERE title=:title", - array("title"=>$_POST["title"])); - $u_title = url_escape($_POST["title"]); - $page->set_mode("redirect"); - $page->set_redirect(make_link("wiki/$u_title")); - } - } - } + $u_title = url_escape($title); + $page->set_mode("redirect"); + $page->set_redirect(make_link("wiki/$u_title")); + } catch (WikiUpdateException $e) { + $original = $this->get_page($title); + // @ because arr_diff is full of warnings + $original->body = @$this->arr_diff( + explode("\n", $original->body), + explode("\n", $wikipage->body) + ); + $this->theme->display_page_editor($page, $original); + } + } else { + $this->theme->display_permission_denied(); + } + } elseif ($event->page_matches("wiki_admin/delete_revision")) { + if ($user->is_admin()) { + global $database; + $database->Execute( + "DELETE FROM wiki_pages WHERE title=:title AND revision=:rev", + ["title"=>$_POST["title"], "rev"=>$_POST["revision"]] + ); + $u_title = url_escape($_POST["title"]); + $page->set_mode("redirect"); + $page->set_redirect(make_link("wiki/$u_title")); + } + } elseif ($event->page_matches("wiki_admin/delete_all")) { + if ($user->is_admin()) { + global $database; + $database->Execute( + "DELETE FROM wiki_pages WHERE title=:title", + ["title"=>$_POST["title"]] + ); + $u_title = url_escape($_POST["title"]); + $page->set_mode("redirect"); + $page->set_redirect(make_link("wiki/$u_title")); + } + } + } - public function onWikiUpdate(WikiUpdateEvent $event) { - global $database; - $wpage = $event->wikipage; - try { - $database->Execute(" + public function onWikiUpdate(WikiUpdateEvent $event) + { + global $database; + $wpage = $event->wikipage; + try { + $database->Execute(" INSERT INTO wiki_pages(owner_id, owner_ip, date, title, revision, locked, body) - VALUES (?, ?, now(), ?, ?, ?, ?)", array($event->user->id, $_SERVER['REMOTE_ADDR'], - $wpage->title, $wpage->revision, $wpage->locked?'Y':'N', $wpage->body)); - } - catch(Exception $e) { - throw new WikiUpdateException("Somebody else edited that page at the same time :-("); - } - } + VALUES (?, ?, now(), ?, ?, ?, ?)", [$event->user->id, $_SERVER['REMOTE_ADDR'], + $wpage->title, $wpage->revision, $wpage->locked?'Y':'N', $wpage->body]); + } catch (Exception $e) { + throw new WikiUpdateException("Somebody else edited that page at the same time :-("); + } + } - /** - * See if the given user is allowed to edit the given page. - */ - public static function can_edit(User $user, WikiPage $page): bool { - // admins can edit everything - if($user->is_admin()) return true; + /** + * See if the given user is allowed to edit the given page. + */ + public static function can_edit(User $user, WikiPage $page): bool + { + // admins can edit everything + if ($user->is_admin()) { + return true; + } - // anon / user can't ever edit locked pages - if($page->is_locked()) return false; + // anon / user can't ever edit locked pages + if ($page->is_locked()) { + return false; + } - // anon / user can edit if allowed by config - if($user->can("edit_wiki_page")) return true; + // anon / user can edit if allowed by config + if ($user->can("edit_wiki_page")) { + return true; + } - return false; - } + return false; + } - private function get_page(string $title, int $revision=-1): WikiPage { - global $database; - // first try and get the actual page - $row = $database->get_row($database->scoreql_to_sql(" + private function get_page(string $title, int $revision=-1): WikiPage + { + global $database; + // first try and get the actual page + $row = $database->get_row( + $database->scoreql_to_sql(" SELECT * FROM wiki_pages WHERE SCORE_STRNORM(title) LIKE SCORE_STRNORM(:title) ORDER BY revision DESC"), - array("title"=>$title)); + ["title"=>$title] + ); - // fall back to wiki:default - if(empty($row)) { - $row = $database->get_row(" + // fall back to wiki:default + if (empty($row)) { + $row = $database->get_row(" SELECT * FROM wiki_pages WHERE title LIKE :title - ORDER BY revision DESC", array("title"=>"wiki:default")); + ORDER BY revision DESC", ["title"=>"wiki:default"]); - // fall further back to manual - if(empty($row)) { - $row = array( - "id" => -1, - "owner_ip" => "0.0.0.0", - "date" => "", - "revision" => 0, - "locked" => false, - "body" => "This is a default page for when a page is empty, ". - "it can be edited by editing [[wiki:default]].", - ); - } + // fall further back to manual + if (empty($row)) { + $row = [ + "id" => -1, + "owner_ip" => "0.0.0.0", + "date" => "", + "revision" => 0, + "locked" => false, + "body" => "This is a default page for when a page is empty, ". + "it can be edited by editing [[wiki:default]].", + ]; + } - // correct the default - global $config; - $row["title"] = $title; - $row["owner_id"] = $config->get_int("anon_id", 0); - } + // correct the default + global $config; + $row["title"] = $title; + $row["owner_id"] = $config->get_int("anon_id", 0); + } - assert(!empty($row)); + assert(!empty($row)); - return new WikiPage($row); - } + return new WikiPage($row); + } -// php-diff {{{ - /** - Diff implemented in pure php, written from scratch. - Copyright (C) 2003 Daniel Unterberger"; - } - $html .= " + } + $html .= " - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - http://www.gnu.org/licenses/gpl.html + // php-diff {{{ + /** + Diff implemented in pure php, written from scratch. + Copyright (C) 2003 Daniel Unterberger - About: - I searched a function to compare arrays and the array_diff() - was not specific enough. It ignores the order of the array-values. - So I reimplemented the diff-function which is found on unix-systems - but this you can use directly in your code and adopt for your needs. - Simply adopt the formatline-function. with the third-parameter of arr_diff() - you can hide matching lines. Hope someone has use for this. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. - Contact: d.u.diff@holomind.de - **/ + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - private function arr_diff( $f1 , $f2 , $show_equal = 0 ) - { + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - $c1 = 0 ; # current line of left - $c2 = 0 ; # current line of right - $max1 = count( $f1 ) ; # maximal lines of left - $max2 = count( $f2 ) ; # maximal lines of right - $outcount = 0; # output counter - $hit1 = "" ; # hit in left - $hit2 = "" ; # hit in right - $stop = 0; - $out = ""; + http://www.gnu.org/licenses/gpl.html - while ( - $c1 < $max1 # have next line in left - and - $c2 < $max2 # have next line in right - and - ($stop++) < 1000 # don-t have more then 1000 ( loop-stopper ) - and - $outcount < 20 # output count is less then 20 - ) - { - /** - * is the trimmed line of the current left and current right line - * the same ? then this is a hit (no difference) - */ - if ( trim( $f1[$c1] ) == trim ( $f2[$c2]) ) - { - /** - * add to output-string, if "show_equal" is enabled - */ - $out .= ($show_equal==1) - ? formatline ( ($c1) , ($c2), "=", $f1[ $c1 ] ) - : "" ; - /** - * increase the out-putcounter, if "show_equal" is enabled - * this ist more for demonstration purpose - */ - if ( $show_equal == 1 ) - { - $outcount++ ; - } + About: + I searched a function to compare arrays and the array_diff() + was not specific enough. It ignores the order of the array-values. + So I reimplemented the diff-function which is found on unix-systems + but this you can use directly in your code and adopt for your needs. + Simply adopt the formatline-function. with the third-parameter of arr_diff() + you can hide matching lines. Hope someone has use for this. + + Contact: d.u.diff@holomind.de + **/ + + private function arr_diff($f1, $f2, $show_equal = 0) + { + $c1 = 0 ; # current line of left + $c2 = 0 ; # current line of right + $max1 = count($f1) ; # maximal lines of left + $max2 = count($f2) ; # maximal lines of right + $outcount = 0; # output counter + $hit1 = "" ; # hit in left + $hit2 = "" ; # hit in right + $stop = 0; + $out = ""; + + while ( + $c1 < $max1 # have next line in left + and + $c2 < $max2 # have next line in right + and + ($stop++) < 1000 # don-t have more then 1000 ( loop-stopper ) + and + $outcount < 20 # output count is less then 20 + ) { + /** + * is the trimmed line of the current left and current right line + * the same ? then this is a hit (no difference) + */ + if (trim($f1[$c1]) == trim($f2[$c2])) { + /** + * add to output-string, if "show_equal" is enabled + */ + $out .= ($show_equal==1) + ? formatline(($c1), ($c2), "=", $f1[ $c1 ]) + : "" ; + /** + * increase the out-putcounter, if "show_equal" is enabled + * this ist more for demonstration purpose + */ + if ($show_equal == 1) { + $outcount++ ; + } - /** - * move the current-pointer in the left and right side - */ - $c1 ++; - $c2 ++; - } + /** + * move the current-pointer in the left and right side + */ + $c1 ++; + $c2 ++; + } - /** - * the current lines are different so we search in parallel - * on each side for the next matching pair, we walk on both - * sided at the same time comparing with the current-lines - * this should be most probable to find the next matching pair - * we only search in a distance of 10 lines, because then it - * is not the same function most of the time. other algos - * would be very complicated, to detect 'real' block movements. - */ - else - { - - $b = "" ; - $s1 = 0 ; # search on left - $s2 = 0 ; # search on right - $found = 0 ; # flag, found a matching pair - $b1 = "" ; - $b2 = "" ; - $fstop = 0 ; # distance of maximum search + /** + * the current lines are different so we search in parallel + * on each side for the next matching pair, we walk on both + * sided at the same time comparing with the current-lines + * this should be most probable to find the next matching pair + * we only search in a distance of 10 lines, because then it + * is not the same function most of the time. other algos + * would be very complicated, to detect 'real' block movements. + */ + else { + $b = "" ; + $s1 = 0 ; # search on left + $s2 = 0 ; # search on right + $found = 0 ; # flag, found a matching pair + $b1 = "" ; + $b2 = "" ; + $fstop = 0 ; # distance of maximum search - #fast search in on both sides for next match. - while ( - $found == 0 # search until we find a pair - and - ( $c1 + $s1 <= $max1 ) # and we are inside of the left lines - and - ( $c2 + $s2 <= $max2 ) # and we are inside of the right lines - and - $fstop++ < 10 # and the distance is lower than 10 lines - ) - { + #fast search in on both sides for next match. + while ( + $found == 0 # search until we find a pair + and + ($c1 + $s1 <= $max1) # and we are inside of the left lines + and + ($c2 + $s2 <= $max2) # and we are inside of the right lines + and + $fstop++ < 10 # and the distance is lower than 10 lines + ) { - /** - * test the left side for a hit - * - * comparing current line with the searching line on the left - * b1 is a buffer, which collects the line which not match, to - * show the differences later, if one line hits, this buffer will - * be used, else it will be discarded later - */ - #hit - if ( trim( $f1[$c1+$s1] ) == trim( $f2[$c2] ) ) - { - $found = 1 ; # set flag to stop further search - $s2 = 0 ; # reset right side search-pointer - $c2-- ; # move back the current right, so next loop hits - $b = $b1 ; # set b=output (b)uffer - } - #no hit: move on - else - { - /** - * prevent finding a line again, which would show wrong results - * - * add the current line to leftbuffer, if this will be the hit - */ - if ( $hit1[ ($c1 + $s1) . "_" . ($c2) ] != 1 ) - { - /** - * add current search-line to diffence-buffer - */ - $b1 .= $this->formatline( ($c1 + $s1) , ($c2), "-", $f1[ $c1+$s1 ] ); + /** + * test the left side for a hit + * + * comparing current line with the searching line on the left + * b1 is a buffer, which collects the line which not match, to + * show the differences later, if one line hits, this buffer will + * be used, else it will be discarded later + */ + #hit + if (trim($f1[$c1+$s1]) == trim($f2[$c2])) { + $found = 1 ; # set flag to stop further search + $s2 = 0 ; # reset right side search-pointer + $c2-- ; # move back the current right, so next loop hits + $b = $b1 ; # set b=output (b)uffer + } + #no hit: move on + else { + /** + * prevent finding a line again, which would show wrong results + * + * add the current line to leftbuffer, if this will be the hit + */ + if ($hit1[ ($c1 + $s1) . "_" . ($c2) ] != 1) { + /** + * add current search-line to diffence-buffer + */ + $b1 .= $this->formatline(($c1 + $s1), ($c2), "-", $f1[ $c1+$s1 ]); - /** - * mark this line as 'searched' to prevent doubles. - */ - $hit1[ ($c1 + $s1) . "_" . $c2 ] = 1 ; - } - } + /** + * mark this line as 'searched' to prevent doubles. + */ + $hit1[ ($c1 + $s1) . "_" . $c2 ] = 1 ; + } + } - /** - * test the right side for a hit - * - * comparing current line with the searching line on the right - */ - if ( trim ( $f1[$c1] ) == trim ( $f2[$c2+$s2]) ) - { - $found = 1 ; # flag to stop search - $s1 = 0 ; # reset pointer for search - $c1-- ; # move current line back, so we hit next loop - $b = $b2 ; # get the buffered difference - } - else - { - /** - * prevent to find line again - */ - if ( $hit2[ ($c1) . "_" . ( $c2 + $s2) ] != 1 ) - { - /** - * add current searchline to buffer - */ - $b2 .= $this->formatline ( ($c1) , ($c2 + $s2), "+", $f2[ $c2+$s2 ] ); + /** + * test the right side for a hit + * + * comparing current line with the searching line on the right + */ + if (trim($f1[$c1]) == trim($f2[$c2+$s2])) { + $found = 1 ; # flag to stop search + $s1 = 0 ; # reset pointer for search + $c1-- ; # move current line back, so we hit next loop + $b = $b2 ; # get the buffered difference + } else { + /** + * prevent to find line again + */ + if ($hit2[ ($c1) . "_" . ($c2 + $s2) ] != 1) { + /** + * add current searchline to buffer + */ + $b2 .= $this->formatline(($c1), ($c2 + $s2), "+", $f2[ $c2+$s2 ]); - /** - * mark current line to prevent double-hits - */ - $hit2[ ($c1) . "_" . ($c2 + $s2) ] = 1; - } + /** + * mark current line to prevent double-hits + */ + $hit2[ ($c1) . "_" . ($c2 + $s2) ] = 1; + } + } - } + /** + * search in bigger distance + * + * increase the search-pointers (satelites) and try again + */ + $s1++ ; # increase left search-pointer + $s2++ ; # increase right search-pointer + } - /** - * search in bigger distance - * - * increase the search-pointers (satelites) and try again - */ - $s1++ ; # increase left search-pointer - $s2++ ; # increase right search-pointer - } + /** + * add line as different on both arrays (no match found) + */ + if ($found == 0) { + $b .= $this->formatline(($c1), ($c2), "-", $f1[ $c1 ]); + $b .= $this->formatline(($c1), ($c2), "+", $f2[ $c2 ]); + } - /** - * add line as different on both arrays (no match found) - */ - if ( $found == 0 ) - { - $b .= $this->formatline ( ($c1) , ($c2), "-", $f1[ $c1 ] ); - $b .= $this->formatline ( ($c1) , ($c2), "+", $f2[ $c2 ] ); - } + /** + * add current buffer to outputstring + */ + $out .= $b; + $outcount++ ; #increase outcounter - /** - * add current buffer to outputstring - */ - $out .= $b; - $outcount++ ; #increase outcounter + $c1++ ; #move currentline forward + $c2++ ; #move currentline forward - $c1++ ; #move currentline forward - $c2++ ; #move currentline forward + /** + * comment the lines are tested quite fast, because + * the current line always moves forward + */ + } /*endif*/ + }/*endwhile*/ - /** - * comment the lines are tested quite fast, because - * the current line always moves forward - */ + return $out; + }/*end func*/ - } /*endif*/ + /** + * callback function to format the diffence-lines with your 'style' + */ + private function formatline(int $nr1, int $nr2, string $stat, &$value): string + { #change to $value if problems + if (trim($value) == "") { + return ""; + } - }/*endwhile*/ + switch ($stat) { + case "=": + // return $nr1. " : $nr2 : = ".htmlentities( $value ) ."
"; + return "$value\n"; + break; - return $out; + case "+": + //return $nr1. " : $nr2 : + ".htmlentities( $value ) ."
"; + return "+++ $value\n"; + break; - }/*end func*/ - - /** - * callback function to format the diffence-lines with your 'style' - */ - private function formatline(int $nr1, int $nr2, string $stat, &$value ): string { #change to $value if problems - if(trim($value) == "") { - return ""; - } - - switch($stat) { - case "=": - // return $nr1. " : $nr2 : = ".htmlentities( $value ) ."
"; - return "$value\n"; - break; - - case "+": - //return $nr1. " : $nr2 : + ".htmlentities( $value ) ."
"; - return "+++ $value\n"; - break; - - case "-": - //return $nr1. " : $nr2 : - ".htmlentities( $value ) ."
"; - return "--- $value\n"; - break; - } - } -// }}} + case "-": + //return $nr1. " : $nr2 : - ".htmlentities( $value ) ."
"; + return "--- $value\n"; + break; + } + } + // }}} } - diff --git a/ext/wiki/test.php b/ext/wiki/test.php index 8d6e9bb2..dfd6d71b 100644 --- a/ext/wiki/test.php +++ b/ext/wiki/test.php @@ -1,122 +1,130 @@ get_page("wiki"); - $this->assert_title("Index"); - $this->assert_text("This is a default page"); - } +class WikiTest extends ShimmiePHPUnitTestCase +{ + public function testIndex() + { + $this->get_page("wiki"); + $this->assert_title("Index"); + $this->assert_text("This is a default page"); + } - public function testAccess() { - $this->markTestIncomplete(); + public function testAccess() + { + $this->markTestIncomplete(); - global $config; - foreach(array("anon", "user", "admin") as $user) { - foreach(array(false, true) as $allowed) { - // admin has no settings to set - if($user != "admin") { - $config->set_bool("wiki_edit_$user", $allowed); - } + global $config; + foreach (["anon", "user", "admin"] as $user) { + foreach ([false, true] as $allowed) { + // admin has no settings to set + if ($user != "admin") { + $config->set_bool("wiki_edit_$user", $allowed); + } - if($user == "user") {$this->log_in_as_user();} - if($user == "admin") {$this->log_in_as_admin();} + if ($user == "user") { + $this->log_in_as_user(); + } + if ($user == "admin") { + $this->log_in_as_admin(); + } - $this->get_page("wiki/test"); - $this->assert_title("test"); - $this->assert_text("This is a default page"); + $this->get_page("wiki/test"); + $this->assert_title("test"); + $this->assert_text("This is a default page"); - if($allowed || $user == "admin") { - $this->get_page("wiki/test", array('edit'=>'on')); - $this->assert_text("Editor"); - } - else { - $this->get_page("wiki/test", array('edit'=>'on')); - $this->assert_no_text("Editor"); - } + if ($allowed || $user == "admin") { + $this->get_page("wiki/test", ['edit'=>'on']); + $this->assert_text("Editor"); + } else { + $this->get_page("wiki/test", ['edit'=>'on']); + $this->assert_no_text("Editor"); + } - if($user == "user" || $user == "admin") { - $this->log_out(); - } - } - } - } + if ($user == "user" || $user == "admin") { + $this->log_out(); + } + } + } + } - public function testLock() { - $this->markTestIncomplete(); + public function testLock() + { + $this->markTestIncomplete(); - global $config; - $config->set_bool("wiki_edit_anon", true); - $config->set_bool("wiki_edit_user", false); + global $config; + $config->set_bool("wiki_edit_anon", true); + $config->set_bool("wiki_edit_user", false); - $this->log_in_as_admin(); + $this->log_in_as_admin(); - $this->get_page("wiki/test_locked"); - $this->assert_title("test_locked"); - $this->assert_text("This is a default page"); - $this->click("Edit"); - $this->set_field("body", "test_locked content"); - $this->set_field("lock", true); - $this->click("Save"); - $this->log_out(); + $this->get_page("wiki/test_locked"); + $this->assert_title("test_locked"); + $this->assert_text("This is a default page"); + $this->click("Edit"); + $this->set_field("body", "test_locked content"); + $this->set_field("lock", true); + $this->click("Save"); + $this->log_out(); - $this->log_in_as_user(); - $this->get_page("wiki/test_locked"); - $this->assert_title("test_locked"); - $this->assert_text("test_locked content"); - $this->assert_no_text("Edit"); - $this->log_out(); + $this->log_in_as_user(); + $this->get_page("wiki/test_locked"); + $this->assert_title("test_locked"); + $this->assert_text("test_locked content"); + $this->assert_no_text("Edit"); + $this->log_out(); - $this->get_page("wiki/test_locked"); - $this->assert_title("test_locked"); - $this->assert_text("test_locked content"); - $this->assert_no_text("Edit"); + $this->get_page("wiki/test_locked"); + $this->assert_title("test_locked"); + $this->assert_text("test_locked content"); + $this->assert_no_text("Edit"); - $this->log_in_as_admin(); - $this->get_page("wiki/test_locked"); - $this->click("Delete All"); - $this->log_out(); - } + $this->log_in_as_admin(); + $this->get_page("wiki/test_locked"); + $this->click("Delete All"); + $this->log_out(); + } - public function testDefault() { - $this->markTestIncomplete(); + public function testDefault() + { + $this->markTestIncomplete(); - $this->log_in_as_admin(); - $this->get_page("wiki/wiki:default"); - $this->assert_title("wiki:default"); - $this->assert_text("This is a default page"); - $this->click("Edit"); - $this->set_field("body", "Empty page! Fill it!"); - $this->click("Save"); + $this->log_in_as_admin(); + $this->get_page("wiki/wiki:default"); + $this->assert_title("wiki:default"); + $this->assert_text("This is a default page"); + $this->click("Edit"); + $this->set_field("body", "Empty page! Fill it!"); + $this->click("Save"); - $this->get_page("wiki/something"); - $this->assert_text("Empty page! Fill it!"); + $this->get_page("wiki/something"); + $this->assert_text("Empty page! Fill it!"); - $this->get_page("wiki/wiki:default"); - $this->click("Delete All"); - $this->log_out(); - } + $this->get_page("wiki/wiki:default"); + $this->click("Delete All"); + $this->log_out(); + } - public function testRevisions() { - $this->markTestIncomplete(); + public function testRevisions() + { + $this->markTestIncomplete(); - $this->log_in_as_admin(); - $this->get_page("wiki/test"); - $this->assert_title("test"); - $this->assert_text("This is a default page"); - $this->click("Edit"); - $this->set_field("body", "Mooooo 1"); - $this->click("Save"); - $this->assert_text("Mooooo 1"); - $this->assert_text("Revision 1"); - $this->click("Edit"); - $this->set_field("body", "Mooooo 2"); - $this->click("Save"); - $this->assert_text("Mooooo 2"); - $this->assert_text("Revision 2"); - $this->click("Delete This Version"); - $this->assert_text("Mooooo 1"); - $this->assert_text("Revision 1"); - $this->click("Delete All"); - $this->log_out(); - } + $this->log_in_as_admin(); + $this->get_page("wiki/test"); + $this->assert_title("test"); + $this->assert_text("This is a default page"); + $this->click("Edit"); + $this->set_field("body", "Mooooo 1"); + $this->click("Save"); + $this->assert_text("Mooooo 1"); + $this->assert_text("Revision 1"); + $this->click("Edit"); + $this->set_field("body", "Mooooo 2"); + $this->click("Save"); + $this->assert_text("Mooooo 2"); + $this->assert_text("Revision 2"); + $this->click("Delete This Version"); + $this->assert_text("Mooooo 1"); + $this->assert_text("Revision 1"); + $this->click("Delete All"); + $this->log_out(); + } } - diff --git a/ext/wiki/theme.php b/ext/wiki/theme.php index 5a00982a..f67c9d8f 100644 --- a/ext/wiki/theme.php +++ b/ext/wiki/theme.php @@ -1,55 +1,58 @@ title and ->body - * $nav_page A wiki page object with navigation, has ->body - */ - public function display_page(Page $page, WikiPage $wiki_page, ?WikiPage $nav_page=null) { - global $user; +class WikiTheme extends Themelet +{ + /** + * Show a page. + * + * $wiki_page The wiki page, has ->title and ->body + * $nav_page A wiki page object with navigation, has ->body + */ + public function display_page(Page $page, WikiPage $wiki_page, ?WikiPage $nav_page=null) + { + global $user; - if(is_null($nav_page)) { - $nav_page = new WikiPage(); - $nav_page->body = ""; - } + if (is_null($nav_page)) { + $nav_page = new WikiPage(); + $nav_page->body = ""; + } - $tfe = new TextFormattingEvent($nav_page->body); - send_event($tfe); + $tfe = new TextFormattingEvent($nav_page->body); + send_event($tfe); - // only the admin can edit the sidebar - if($user->is_admin()) { - $tfe->formatted .= "(Edit)"; - } + // only the admin can edit the sidebar + if ($user->is_admin()) { + $tfe->formatted .= "
(Edit)"; + } - $page->set_title(html_escape($wiki_page->title)); - $page->set_heading(html_escape($wiki_page->title)); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Wiki Index", $tfe->formatted, "left", 20)); - $page->add_block(new Block(html_escape($wiki_page->title), $this->create_display_html($wiki_page))); - } + $page->set_title(html_escape($wiki_page->title)); + $page->set_heading(html_escape($wiki_page->title)); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Wiki Index", $tfe->formatted, "left", 20)); + $page->add_block(new Block(html_escape($wiki_page->title), $this->create_display_html($wiki_page))); + } - public function display_page_editor(Page $page, WikiPage $wiki_page) { - $page->set_title(html_escape($wiki_page->title)); - $page->set_heading(html_escape($wiki_page->title)); - $page->add_block(new NavBlock()); - $page->add_block(new Block("Editor", $this->create_edit_html($wiki_page))); - } + public function display_page_editor(Page $page, WikiPage $wiki_page) + { + $page->set_title(html_escape($wiki_page->title)); + $page->set_heading(html_escape($wiki_page->title)); + $page->add_block(new NavBlock()); + $page->add_block(new Block("Editor", $this->create_edit_html($wiki_page))); + } - protected function create_edit_html(WikiPage $page) { - $h_title = html_escape($page->title); - $i_revision = int_escape($page->revision) + 1; + protected function create_edit_html(WikiPage $page) + { + $h_title = html_escape($page->title); + $i_revision = int_escape($page->revision) + 1; - global $user; - if($user->is_admin()) { - $val = $page->is_locked() ? " checked" : ""; - $lock = "
Lock page: "; - } - else { - $lock = ""; - } - return " + global $user; + if ($user->is_admin()) { + $val = $page->is_locked() ? " checked" : ""; + $lock = "
Lock page: "; + } else { + $lock = ""; + } + return " ".make_form(make_link("wiki_admin/save"))." @@ -58,28 +61,29 @@ class WikiTheme extends Themelet {
"; - } + } - protected function create_display_html(WikiPage $page) { - global $user; + protected function create_display_html(WikiPage $page) + { + global $user; - $owner = $page->get_owner(); + $owner = $page->get_owner(); - $tfe = new TextFormattingEvent($page->body); - send_event($tfe); + $tfe = new TextFormattingEvent($page->body); + send_event($tfe); - $edit = ""; - return " + return "
"; - $edit .= Wiki::can_edit($user, $page) ? - " + $edit = " "; + } + $edit .= "
"; + $edit .= Wiki::can_edit($user, $page) ? + " ".make_form(make_link("wiki_admin/edit"))." " : - ""; - if($user->is_admin()) { - $edit .= " + ""; + if ($user->is_admin()) { + $edit .= "".make_form(make_link("wiki_admin/delete_revision"))." @@ -90,10 +94,10 @@ class WikiTheme extends Themelet { "; - } - $edit .= "$tfe->formatted"; - } + } } - diff --git a/ext/word_filter/main.php b/ext/word_filter/main.php index f858f3a6..d6933383 100644 --- a/ext/word_filter/main.php +++ b/ext/word_filter/main.php @@ -7,53 +7,59 @@ * Description: Simple search and replace */ -class WordFilter extends Extension { - // before emoticon filter - public function get_priority(): int {return 40;} +class WordFilter extends Extension +{ + // before emoticon filter + public function get_priority(): int + { + return 40; + } - public function onTextFormatting(TextFormattingEvent $event) { - $event->formatted = $this->filter($event->formatted); - $event->stripped = $this->filter($event->stripped); - } + public function onTextFormatting(TextFormattingEvent $event) + { + $event->formatted = $this->filter($event->formatted); + $event->stripped = $this->filter($event->stripped); + } - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Word Filter"); - $sb->add_longtext_option("word_filter"); - $sb->add_label("
@@ -105,6 +109,5 @@ class WikiTheme extends Themelet {
(each line should be search term and replace term, separated by a comma)"); - $event->panel->add_block($sb); - } + public function onSetupBuilding(SetupBuildingEvent $event) + { + $sb = new SetupBlock("Word Filter"); + $sb->add_longtext_option("word_filter"); + $sb->add_label("
(each line should be search term and replace term, separated by a comma)"); + $event->panel->add_block($sb); + } - private function filter(string $text): string { - $map = $this->get_map(); - foreach($map as $search => $replace) { - $search = trim($search); - $replace = trim($replace); - if($search[0] == '/') { - $text = preg_replace($search, $replace, $text); - } - else { - $search = "/\\b" . str_replace("/", "\\/", $search) . "\\b/i"; - $text = preg_replace($search, $replace, $text); - } - } - return $text; - } + private function filter(string $text): string + { + $map = $this->get_map(); + foreach ($map as $search => $replace) { + $search = trim($search); + $replace = trim($replace); + if ($search[0] == '/') { + $text = preg_replace($search, $replace, $text); + } else { + $search = "/\\b" . str_replace("/", "\\/", $search) . "\\b/i"; + $text = preg_replace($search, $replace, $text); + } + } + return $text; + } - /** - * #return string[] - */ - private function get_map(): array { - global $config; - $raw = $config->get_string("word_filter"); - $lines = explode("\n", $raw); - $map = array(); - foreach($lines as $line) { - $parts = explode(",", $line); - if(count($parts) == 2) { - $map[$parts[0]] = $parts[1]; - } - } - return $map; - } + /** + * #return string[] + */ + private function get_map(): array + { + global $config; + $raw = $config->get_string("word_filter"); + $lines = explode("\n", $raw); + $map = []; + foreach ($lines as $line) { + $parts = explode(",", $line); + if (count($parts) == 2) { + $map[$parts[0]] = $parts[1]; + } + } + return $map; + } } - diff --git a/ext/word_filter/test.php b/ext/word_filter/test.php index 4ac1748d..c75069b2 100644 --- a/ext/word_filter/test.php +++ b/ext/word_filter/test.php @@ -1,67 +1,76 @@ set_string("word_filter", "whore,nice lady\na duck,a kitten\n white ,\tspace\ninvalid"); - } +class WordFilterTest extends ShimmiePHPUnitTestCase +{ + public function setUp() + { + global $config; + parent::setUp(); + $config->set_string("word_filter", "whore,nice lady\na duck,a kitten\n white ,\tspace\ninvalid"); + } - public function _doThings($in, $out) { - global $user; - $this->log_in_as_user(); - $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); - send_event(new CommentPostingEvent($image_id, $user, $in)); - $this->get_page("post/view/$image_id"); - $this->assert_text($out); - } + public function _doThings($in, $out) + { + global $user; + $this->log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + send_event(new CommentPostingEvent($image_id, $user, $in)); + $this->get_page("post/view/$image_id"); + $this->assert_text($out); + } - public function testRegular() { - $this->_doThings( - "posted by a whore", - "posted by a nice lady" - ); - } + public function testRegular() + { + $this->_doThings( + "posted by a whore", + "posted by a nice lady" + ); + } - public function testReplaceAll() { - $this->_doThings( - "a whore is a whore is a whore", - "a nice lady is a nice lady is a nice lady" - ); - } + public function testReplaceAll() + { + $this->_doThings( + "a whore is a whore is a whore", + "a nice lady is a nice lady is a nice lady" + ); + } - public function testMixedCase() { - $this->_doThings( - "monkey WhorE", - "monkey nice lady" - ); - } + public function testMixedCase() + { + $this->_doThings( + "monkey WhorE", + "monkey nice lady" + ); + } - public function testOnlyWholeWords() { - $this->_doThings( - "my name is whoretta", - "my name is whoretta" - ); - } + public function testOnlyWholeWords() + { + $this->_doThings( + "my name is whoretta", + "my name is whoretta" + ); + } - public function testMultipleWords() { - $this->_doThings( - "I would like a duck", - "I would like a kitten" - ); - } + public function testMultipleWords() + { + $this->_doThings( + "I would like a duck", + "I would like a kitten" + ); + } - public function testWhitespace() { - $this->_doThings( - "A colour is white", - "A colour is space" - ); - } + public function testWhitespace() + { + $this->_doThings( + "A colour is white", + "A colour is space" + ); + } - public function testIgnoreInvalid() { - $this->_doThings( - "The word was invalid", - "The word was invalid" - ); - } + public function testIgnoreInvalid() + { + $this->_doThings( + "The word was invalid", + "The word was invalid" + ); + } } - diff --git a/index.php b/index.php index 7c9ee6b9..b9c0b824 100644 --- a/index.php +++ b/index.php @@ -43,18 +43,18 @@ * Each of these can be imported at the start of a function with eg "global $page, $user;" */ -if(!file_exists("data/config/shimmie.conf.php")) { - require_once "core/_install.php"; - exit; +if (!file_exists("data/config/shimmie.conf.php")) { + require_once "core/_install.php"; + exit; } -if(file_exists("images") && !file_exists("data/images")) { - die("As of Shimmie 2.7 images and thumbs should be moved to data/images and data/thumbs"); +if (file_exists("images") && !file_exists("data/images")) { + die("As of Shimmie 2.7 images and thumbs should be moved to data/images and data/thumbs"); } -if(!file_exists("vendor/")) { - //CHECK: Should we just point to install.php instead? Seems unsafe though. - print <<@@ -79,33 +79,34 @@ if(!file_exists("vendor/")) { EOD; - http_response_code(500); - exit; + http_response_code(500); + exit; } try { - require_once "core/_bootstrap.php"; - $_shm_ctx->log_start(@$_SERVER["REQUEST_URI"], true, true); + require_once "core/_bootstrap.php"; + $_shm_ctx->log_start(@$_SERVER["REQUEST_URI"], true, true); - // start the page generation waterfall - $user = _get_user(); - if(PHP_SAPI === 'cli' || PHP_SAPI == 'phpdbg') { - send_event(new CommandEvent($argv)); - } - else { - send_event(new PageRequestEvent(_get_query())); - $page->display(); - } + // start the page generation waterfall + $user = _get_user(); + if (PHP_SAPI === 'cli' || PHP_SAPI == 'phpdbg') { + send_event(new CommandEvent($argv)); + } else { + send_event(new PageRequestEvent(_get_query())); + $page->display(); + } - // saving cache data and profiling data to disk can happen later - if(function_exists("fastcgi_finish_request")) fastcgi_finish_request(); - $database->commit(); - $_shm_ctx->log_endok(); -} -catch(Exception $e) { - if($database) $database->rollback(); - _fatal_error($e); - $_shm_ctx->log_ender(); + // saving cache data and profiling data to disk can happen later + if (function_exists("fastcgi_finish_request")) { + fastcgi_finish_request(); + } + $database->commit(); + $_shm_ctx->log_endok(); +} catch (Exception $e) { + if ($database) { + $database->rollback(); + } + _fatal_error($e); + $_shm_ctx->log_ender(); } log_slow(); - diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 62275c63..28539364 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,144 +10,165 @@ $_SERVER['QUERY_STRING'] = '/'; chdir(dirname(dirname(__FILE__))); require_once "core/_bootstrap.php"; -if(is_null(User::by_name("demo"))) { - $userPage = new UserPage(); - $userPage->onUserCreation(new UserCreationEvent("demo", "demo", "")); - $userPage->onUserCreation(new UserCreationEvent("test", "test", "")); +if (is_null(User::by_name("demo"))) { + $userPage = new UserPage(); + $userPage->onUserCreation(new UserCreationEvent("demo", "demo", "")); + $userPage->onUserCreation(new UserCreationEvent("test", "test", "")); } -abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase { - private $images = array(); +abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase +{ + private $images = []; - public function setUp() { - $class = str_replace("Test", "", get_class($this)); - if(!class_exists($class)) { - $this->markTestSkipped("$class not loaded"); - } - elseif(!ext_is_live($class)) { - $this->markTestSkipped("$class not supported with this database"); - } + public function setUp() + { + $class = str_replace("Test", "", get_class($this)); + if (!class_exists($class)) { + $this->markTestSkipped("$class not loaded"); + } elseif (!ext_is_live($class)) { + $this->markTestSkipped("$class not supported with this database"); + } - // things to do after bootstrap and before request - // log in as anon - $this->log_out(); - } + // things to do after bootstrap and before request + // log in as anon + $this->log_out(); + } - public function tearDown() { - foreach($this->images as $image_id) { - $this->delete_image($image_id); - } - } + public function tearDown() + { + foreach ($this->images as $image_id) { + $this->delete_image($image_id); + } + } - protected function get_page($page_name, $args=null) { - // use a fresh page - global $page; - if(!$args) $args = array(); - $_GET = $args; - $_POST = array(); - $page = class_exists("CustomPage") ? new CustomPage() : new Page(); - send_event(new PageRequestEvent($page_name)); - if($page->mode == "redirect") { - $page->code = 302; - } - } + protected function get_page($page_name, $args=null) + { + // use a fresh page + global $page; + if (!$args) { + $args = []; + } + $_GET = $args; + $_POST = []; + $page = class_exists("CustomPage") ? new CustomPage() : new Page(); + send_event(new PageRequestEvent($page_name)); + if ($page->mode == "redirect") { + $page->code = 302; + } + } - protected function post_page($page_name, $args=null) { - // use a fresh page - global $page; - if(!$args) $args = array(); - $_GET = array(); - $_POST = $args; - $page = class_exists("CustomPage") ? new CustomPage() : new Page(); - send_event(new PageRequestEvent($page_name)); - if($page->mode == "redirect") { - $page->code = 302; - } - } + protected function post_page($page_name, $args=null) + { + // use a fresh page + global $page; + if (!$args) { + $args = []; + } + $_GET = []; + $_POST = $args; + $page = class_exists("CustomPage") ? new CustomPage() : new Page(); + send_event(new PageRequestEvent($page_name)); + if ($page->mode == "redirect") { + $page->code = 302; + } + } - // page things - protected function assert_title(string $title) { - global $page; - $this->assertContains($title, $page->title); - } + // page things + protected function assert_title(string $title) + { + global $page; + $this->assertContains($title, $page->title); + } - protected function assert_no_title(string $title) { - global $page; - $this->assertNotContains($title, $page->title); - } + protected function assert_no_title(string $title) + { + global $page; + $this->assertNotContains($title, $page->title); + } - protected function assert_response(int $code) { - global $page; - $this->assertEquals($code, $page->code); - } + protected function assert_response(int $code) + { + global $page; + $this->assertEquals($code, $page->code); + } - protected function page_to_text(string $section=null) { - global $page; - $text = $page->title . "\n"; - foreach($page->blocks as $block) { - if(is_null($section) || $section == $block->section) { - $text .= $block->header . "\n"; - $text .= $block->body . "\n\n"; - } - } - return $text; - } + protected function page_to_text(string $section=null) + { + global $page; + $text = $page->title . "\n"; + foreach ($page->blocks as $block) { + if (is_null($section) || $section == $block->section) { + $text .= $block->header . "\n"; + $text .= $block->body . "\n\n"; + } + } + return $text; + } - protected function assert_text(string $text, string $section=null) { - $this->assertContains($text, $this->page_to_text($section)); - } + protected function assert_text(string $text, string $section=null) + { + $this->assertContains($text, $this->page_to_text($section)); + } - protected function assert_no_text(string $text, string $section=null) { - $this->assertNotContains($text, $this->page_to_text($section)); - } + protected function assert_no_text(string $text, string $section=null) + { + $this->assertNotContains($text, $this->page_to_text($section)); + } - protected function assert_content(string $content) { - global $page; - $this->assertContains($content, $page->data); - } + protected function assert_content(string $content) + { + global $page; + $this->assertContains($content, $page->data); + } - protected function assert_no_content(string $content) { - global $page; - $this->assertNotContains($content, $page->data); - } + protected function assert_no_content(string $content) + { + global $page; + $this->assertNotContains($content, $page->data); + } - // user things - protected function log_in_as_admin() { - global $user; - $user = User::by_name('demo'); - $this->assertNotNull($user); - } + // user things + protected function log_in_as_admin() + { + global $user; + $user = User::by_name('demo'); + $this->assertNotNull($user); + } - protected function log_in_as_user() { - global $user; - $user = User::by_name('test'); - $this->assertNotNull($user); - } + protected function log_in_as_user() + { + global $user; + $user = User::by_name('test'); + $this->assertNotNull($user); + } - protected function log_out() { - global $user, $config; - $user = User::by_id($config->get_int("anon_id", 0)); - $this->assertNotNull($user); - } + protected function log_out() + { + global $user, $config; + $user = User::by_id($config->get_int("anon_id", 0)); + $this->assertNotNull($user); + } - // post things - protected function post_image(string $filename, string $tags): int { - $dae = new DataUploadEvent($filename, array( - "filename" => $filename, - "extension" => pathinfo($filename, PATHINFO_EXTENSION), - "tags" => Tag::explode($tags), - "source" => null, - )); - send_event($dae); - $this->images[] = $dae->image_id; - return $dae->image_id; - } + // post things + protected function post_image(string $filename, string $tags): int + { + $dae = new DataUploadEvent($filename, [ + "filename" => $filename, + "extension" => pathinfo($filename, PATHINFO_EXTENSION), + "tags" => Tag::explode($tags), + "source" => null, + ]); + send_event($dae); + $this->images[] = $dae->image_id; + return $dae->image_id; + } - protected function delete_image(int $image_id) { - $img = Image::by_id($image_id); - if($img) { - $ide = new ImageDeletionEvent($img); - send_event($ide); - } - } + protected function delete_image(int $image_id) + { + $img = Image::by_id($image_id); + if ($img) { + $ide = new ImageDeletionEvent($img); + send_event($ide); + } + } } diff --git a/tests/router.php b/tests/router.php index a2255eaa..dc35c942 100644 --- a/tests/router.php +++ b/tests/router.php @@ -1,19 +1,21 @@ disable_left(); + $page->disable_left(); - // parts for the whole page - $prev = $page_number - 1; - $next = $page_number + 1; + // parts for the whole page + $prev = $page_number - 1; + $next = $page_number + 1; - $h_prev = ($page_number <= 1) ? "Prev" : - "Prev"; - $h_index = "Index"; - $h_next = ($page_number >= $total_pages) ? "Next" : - "Next"; + $h_prev = ($page_number <= 1) ? "Prev" : + "Prev"; + $h_index = "Index"; + $h_next = ($page_number >= $total_pages) ? "Next" : + "Next"; - $nav = "$h_prev | $h_index | $h_next"; + $nav = "$h_prev | $h_index | $h_next"; - $page->set_title("Comments"); - $page->set_heading("Comments"); - $page->add_block(new Block("Navigation", $nav, "left")); - $this->display_paginator($page, "comment/list", null, $page_number, $total_pages); + $page->set_title("Comments"); + $page->set_heading("Comments"); + $page->add_block(new Block("Navigation", $nav, "left")); + $this->display_paginator($page, "comment/list", null, $page_number, $total_pages); - // parts for each image - $position = 10; - - $comment_captcha = $config->get_bool('comment_captcha'); - $comment_limit = $config->get_int("comment_list_count", 10); - - foreach($images as $pair) { - $image = $pair[0]; - $comments = $pair[1]; + // parts for each image + $position = 10; + + $comment_captcha = $config->get_bool('comment_captcha'); + $comment_limit = $config->get_int("comment_list_count", 10); + + foreach ($images as $pair) { + $image = $pair[0]; + $comments = $pair[1]; - $thumb_html = $this->build_thumb_html($image); + $thumb_html = $this->build_thumb_html($image); - $s = " "; - $un = $image->get_owner()->name; - $t = ""; - foreach($image->get_tag_array() as $tag) { - $u_tag = url_escape($tag); - $t .= "".html_escape($tag)." "; - } - $p = autodate($image->posted); + $s = " "; + $un = $image->get_owner()->name; + $t = ""; + foreach ($image->get_tag_array() as $tag) { + $u_tag = url_escape($tag); + $t .= "".html_escape($tag)." "; + } + $p = autodate($image->posted); - $r = ext_is_live("Ratings") ? "Rating ".Ratings::rating_to_human($image->rating) : ""; - $comment_html = "Date $p $s User $un $s $r
Tags $t"; + $r = ext_is_live("Ratings") ? "Rating ".Ratings::rating_to_human($image->rating) : ""; + $comment_html = "Date $p $s User $un $s $r
Tags $t"; - $comment_count = count($comments); - if($comment_limit > 0 && $comment_count > $comment_limit) { - //$hidden = $comment_count - $comment_limit; - $comment_html .= "
showing $comment_limit of $comment_count comments
"; - $comments = array_slice($comments, -$comment_limit); - } - foreach($comments as $comment) { - $comment_html .= $this->comment_to_html($comment); - } - if($can_post) { - if(!$user->is_anonymous()) { - $comment_html .= $this->build_postbox($image->id); - } - else { - if(!$comment_captcha) { - $comment_html .= $this->build_postbox($image->id); - } - else { - $comment_html .= "Add Comment"; - } - } - } + $comment_count = count($comments); + if ($comment_limit > 0 && $comment_count > $comment_limit) { + //$hidden = $comment_count - $comment_limit; + $comment_html .= "showing $comment_limit of $comment_count comments
"; + $comments = array_slice($comments, -$comment_limit); + } + foreach ($comments as $comment) { + $comment_html .= $this->comment_to_html($comment); + } + if ($can_post) { + if (!$user->is_anonymous()) { + $comment_html .= $this->build_postbox($image->id); + } else { + if (!$comment_captcha) { + $comment_html .= $this->build_postbox($image->id); + } else { + $comment_html .= "Add Comment"; + } + } + } - $html = " + $html = "
$thumb_html $comment_html @@ -78,49 +78,49 @@ class CustomCommentListTheme extends CommentListTheme { "; - $page->add_block(new Block(" ", $html, "main", $position++)); - } - } + $page->add_block(new Block(" ", $html, "main", $position++)); + } + } - public function display_recent_comments(array $comments) { - // no recent comments in this theme - } + public function display_recent_comments(array $comments) + { + // no recent comments in this theme + } - protected function comment_to_html(Comment $comment, bool $trim=false): string { - global $user; + protected function comment_to_html(Comment $comment, bool $trim=false): string + { + global $user; - $tfe = new TextFormattingEvent($comment->comment); - send_event($tfe); + $tfe = new TextFormattingEvent($comment->comment); + send_event($tfe); - //$i_uid = int_escape($comment->owner_id); - $h_name = html_escape($comment->owner_name); - //$h_poster_ip = html_escape($comment->poster_ip); - $h_comment = ($trim ? substr($tfe->stripped, 0, 50)."..." : $tfe->formatted); - $i_comment_id = int_escape($comment->comment_id); - $i_image_id = int_escape($comment->image_id); - $h_posted = autodate($comment->posted); + //$i_uid = int_escape($comment->owner_id); + $h_name = html_escape($comment->owner_name); + //$h_poster_ip = html_escape($comment->poster_ip); + $h_comment = ($trim ? substr($tfe->stripped, 0, 50)."..." : $tfe->formatted); + $i_comment_id = int_escape($comment->comment_id); + $i_image_id = int_escape($comment->image_id); + $h_posted = autodate($comment->posted); - $h_userlink = "$h_name"; - $h_del = ""; - if ($user->can("delete_comment")) { - $comment_preview = substr(html_unescape($tfe->stripped), 0, 50); - $j_delete_confirm_message = json_encode("Delete comment by {$comment->owner_name}:\n$comment_preview"); - $h_delete_script = html_escape("return confirm($j_delete_confirm_message);"); - $h_delete_link = make_link("comment/delete/$i_comment_id/$i_image_id"); - $h_del = " - Del"; - } - //$h_imagelink = $trim ? ">>>\n" : ""; - if($trim) { - return "$h_userlink $h_del
"; - } - else { - return " + $h_userlink = "$h_name"; + $h_del = ""; + if ($user->can("delete_comment")) { + $comment_preview = substr(html_unescape($tfe->stripped), 0, 50); + $j_delete_confirm_message = json_encode("Delete comment by {$comment->owner_name}:\n$comment_preview"); + $h_delete_script = html_escape("return confirm($j_delete_confirm_message);"); + $h_delete_link = make_link("comment/delete/$i_comment_id/$i_image_id"); + $h_del = " - Del"; + } + //$h_imagelink = $trim ? ">>>\n" : ""; + if ($trim) { + return "
$h_posted
$h_comment$h_userlink $h_del
"; + } else { + return "
$h_posted
$h_comment"; - } - } + } + } } - diff --git a/themes/danbooru/custompage.class.php b/themes/danbooru/custompage.class.php index 4b36216c..f5641dc6 100644 --- a/themes/danbooru/custompage.class.php +++ b/themes/danbooru/custompage.class.php @@ -1,11 +1,12 @@ left_enabled = false; - } + public function disable_left() + { + $this->left_enabled = false; + } } - diff --git a/themes/danbooru/index.theme.php b/themes/danbooru/index.theme.php index 154b23d8..ffff72ac 100644 --- a/themes/danbooru/index.theme.php +++ b/themes/danbooru/index.theme.php @@ -1,48 +1,48 @@ search_terms) == 0) { - $query = null; - $page_title = $config->get_string('title'); - } - else { - $search_string = implode(' ', $this->search_terms); - $query = url_escape($search_string); - $page_title = html_escape($search_string); - } + if (count($this->search_terms) == 0) { + $query = null; + $page_title = $config->get_string('title'); + } else { + $search_string = implode(' ', $this->search_terms); + $query = url_escape($search_string); + $page_title = html_escape($search_string); + } - $nav = $this->build_navigation($this->page_number, $this->total_pages, $this->search_terms); - $page->set_title($page_title); - $page->set_heading($page_title); - $page->add_block(new Block("Search", $nav, "left", 0)); - if(count($images) > 0) { - if($query) { - $page->add_block(new Block("Images", $this->build_table($images, "search=$query"), "main", 10)); - $this->display_paginator($page, "post/list/$query", null, $this->page_number, $this->total_pages); - } - else { - $page->add_block(new Block("Images", $this->build_table($images, null), "main", 10)); - $this->display_paginator($page, "post/list", null, $this->page_number, $this->total_pages); - } - } - else { - $page->add_block(new Block("No Images Found", "No images were found to match the search criteria")); - } - } + $nav = $this->build_navigation($this->page_number, $this->total_pages, $this->search_terms); + $page->set_title($page_title); + $page->set_heading($page_title); + $page->add_block(new Block("Search", $nav, "left", 0)); + if (count($images) > 0) { + if ($query) { + $page->add_block(new Block("Images", $this->build_table($images, "search=$query"), "main", 10)); + $this->display_paginator($page, "post/list/$query", null, $this->page_number, $this->total_pages); + } else { + $page->add_block(new Block("Images", $this->build_table($images, null), "main", 10)); + $this->display_paginator($page, "post/list", null, $this->page_number, $this->total_pages); + } + } else { + $page->add_block(new Block("No Images Found", "No images were found to match the search criteria")); + } + } - /** - * #param string[] $search_terms - */ - protected function build_navigation(int $page_number, int $total_pages, array $search_terms): string { - $h_search_string = count($search_terms) == 0 ? "" : html_escape(implode(" ", $search_terms)); - $h_search_link = make_link(); - $h_search = " + /** + * #param string[] $search_terms + */ + protected function build_navigation(int $page_number, int $total_pages, array $search_terms): string + { + $h_search_string = count($search_terms) == 0 ? "" : html_escape(implode(" ", $search_terms)); + $h_search_link = make_link(); + $h_search = "
$h_userlink
$h_posted$h_del$h_comment @@ -50,17 +50,17 @@ class CustomIndexTheme extends IndexTheme { "; - return $h_search; - } + return $h_search; + } - protected function build_table(array $images, string $query): string { - $h_query = html_escape($query); - $table = ""; - foreach($images as $image) { - $table .= "\t" . $this->build_thumb_html($image) . "\n"; - } - $table .= ""; - return $table; - } + protected function build_table(array $images, string $query): string + { + $h_query = html_escape($query); + $table = ""; + foreach ($images as $image) { + $table .= "\t" . $this->build_thumb_html($image) . "\n"; + } + $table .= ""; + return $table; + } } - diff --git a/themes/danbooru/layout.class.php b/themes/danbooru/layout.class.php index 048d3de8..6076a30f 100644 --- a/themes/danbooru/layout.class.php +++ b/themes/danbooru/layout.class.php @@ -26,12 +26,12 @@ Changes in this theme include - $site_name and $front_name retreival from config added. - $custom_link and $title_link preparation just before html is outputed. - Altered outputed html to include the custom links and removed heading - from being displayed (subheading is still displayed) + from being displayed (subheading is still displayed) - Note that only the sidebar has been left aligned. Could not properly left align the main block because blocks without headers currently do not have ids on there div elements. (this was a problem because paginator block must be centered and everything else left aligned) - + Tips - You can change custom links to point to whatever pages you want as well as adding more custom links. @@ -42,154 +42,164 @@ Tips * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -class Layout { - public function display_page(Page $page) { - global $config, $user; +class Layout +{ + public function display_page(Page $page) + { + global $config, $user; - $theme_name = $config->get_string('theme'); - //$base_href = $config->get_string('base_href'); - $data_href = get_base_href(); - $contact_link = contact_link(); - $header_html = $page->get_all_html_headers(); + $theme_name = $config->get_string('theme'); + //$base_href = $config->get_string('base_href'); + $data_href = get_base_href(); + $contact_link = contact_link(); + $header_html = $page->get_all_html_headers(); - $left_block_html = ""; - $user_block_html = ""; - $main_block_html = ""; - $sub_block_html = ""; + $left_block_html = ""; + $user_block_html = ""; + $main_block_html = ""; + $sub_block_html = ""; - foreach($page->blocks as $block) { - switch($block->section) { - case "left": - $left_block_html .= $block->get_html(true); - break; - case "user": - $user_block_html .= $block->body; // $this->block_to_html($block, true); - break; - case "subheading": - $sub_block_html .= $block->body; // $this->block_to_html($block, true); - break; - case "main": - if($block->header == "Images") { - $block->header = " "; - } - $main_block_html .= $block->get_html(false); - break; - default: - print "error: {$block->header} using an unknown section ({$block->section})"; - break; - } - } + foreach ($page->blocks as $block) { + switch ($block->section) { + case "left": + $left_block_html .= $block->get_html(true); + break; + case "user": + $user_block_html .= $block->body; // $this->block_to_html($block, true); + break; + case "subheading": + $sub_block_html .= $block->body; // $this->block_to_html($block, true); + break; + case "main": + if ($block->header == "Images") { + $block->header = " "; + } + $main_block_html .= $block->get_html(false); + break; + default: + print "
error: {$block->header} using an unknown section ({$block->section})"; + break; + } + } - $debug = get_debug_info(); + $debug = get_debug_info(); - $contact = empty($contact_link) ? "" : "
Contact"; + $contact = empty($contact_link) ? "" : "
Contact"; - if(empty($this->subheading)) { - $subheading = ""; - } - else { - $subheading = "{$this->subheading}"; - } + if (empty($this->subheading)) { + $subheading = ""; + } else { + $subheading = "{$this->subheading}"; + } - $site_name = $config->get_string('title'); // bzchan: change from normal default to get title for top of page - $main_page = $config->get_string('main_page'); // bzchan: change from normal default to get main page for top of page + $site_name = $config->get_string('title'); // bzchan: change from normal default to get title for top of page + $main_page = $config->get_string('main_page'); // bzchan: change from normal default to get main page for top of page - // bzchan: CUSTOM LINKS are prepared here, change these to whatever you like - $custom_links = ""; - if($user->is_anonymous()) { - $custom_links .= $this->navlinks(make_link('user_admin/login'), "My Account", array("user", "user_admin", "setup", "admin")); - } - else { - $custom_links .= $this->navlinks(make_link('user'), "My Account", array("user", "user_admin", "setup", "admin")); - } - $custom_links .= $this->navlinks(make_link('post/list'), "Posts", array("post")); - $custom_links .= $this->navlinks(make_link('comment/list'), "Comments", array("comment")); - $custom_links .= $this->navlinks(make_link('tags'), "Tags", array("tags")); - if(class_exists("Pools")) { - $custom_links .= $this->navlinks(make_link('pool/list'), "Pools", array("pool")); - } - $custom_links .= $this->navlinks(make_link('upload'), "Upload", array("upload")); - if(class_exists("Wiki")) { - $custom_links .= $this->navlinks(make_link('wiki'), "Wiki", array("wiki")); - $custom_links .= $this->navlinks(make_link('wiki/more'), "More »", array("wiki/more")); - } + // bzchan: CUSTOM LINKS are prepared here, change these to whatever you like + $custom_links = ""; + if ($user->is_anonymous()) { + $custom_links .= $this->navlinks(make_link('user_admin/login'), "My Account", ["user", "user_admin", "setup", "admin"]); + } else { + $custom_links .= $this->navlinks(make_link('user'), "My Account", ["user", "user_admin", "setup", "admin"]); + } + $custom_links .= $this->navlinks(make_link('post/list'), "Posts", ["post"]); + $custom_links .= $this->navlinks(make_link('comment/list'), "Comments", ["comment"]); + $custom_links .= $this->navlinks(make_link('tags'), "Tags", ["tags"]); + if (class_exists("Pools")) { + $custom_links .= $this->navlinks(make_link('pool/list'), "Pools", ["pool"]); + } + $custom_links .= $this->navlinks(make_link('upload'), "Upload", ["upload"]); + if (class_exists("Wiki")) { + $custom_links .= $this->navlinks(make_link('wiki'), "Wiki", ["wiki"]); + $custom_links .= $this->navlinks(make_link('wiki/more'), "More »", ["wiki/more"]); + } - $custom_sublinks = ""; - // hack - $username = url_escape($user->name); - // hack - $qp = explode("/", ltrim(_get_query(), "/")); - // php sucks - switch($qp[0]) { - default: - $custom_sublinks .= $user_block_html; - break; - case "": - # FIXME: this assumes that the front page is - # post/list; in 99% of case it will either be - # post/list or home, and in the latter case - # the subnav links aren't shown, but it would - # be nice to be correct - case "post": - case "upload": - if(class_exists("NumericScore")){ $custom_sublinks .= "Popular by Day/Month/Year ";} - $custom_sublinks .= "All "; - if(class_exists("Favorites")){ $custom_sublinks .= "My Favorites ";} - if(class_exists("RSS_Images")){ $custom_sublinks .= "Feed ";} - if(class_exists("RandomImage")){ $custom_sublinks .= "Random Image ";} - if(class_exists("Wiki")){ $custom_sublinks .= "Help "; - }else{ $custom_sublinks .= "Help ";} - break; - case "comment": - $custom_sublinks .= "All "; - $custom_sublinks .= "Help "; - break; - case "pool": - $custom_sublinks .= "List "; - $custom_sublinks .= "Create "; - $custom_sublinks .= "Changes "; - $custom_sublinks .= "Help "; - break; - case "wiki": - $custom_sublinks .= "Index "; - $custom_sublinks .= "Rules "; - $custom_sublinks .= "Help "; - break; - case "tags": - case "alias": - $custom_sublinks .= "Map "; - $custom_sublinks .= "Alphabetic "; - $custom_sublinks .= "Popularity "; - $custom_sublinks .= "Categories "; - $custom_sublinks .= "Aliases "; - $custom_sublinks .= "Help "; - break; - } + $custom_sublinks = ""; + // hack + $username = url_escape($user->name); + // hack + $qp = explode("/", ltrim(_get_query(), "/")); + // php sucks + switch ($qp[0]) { + default: + $custom_sublinks .= $user_block_html; + break; + case "": + # FIXME: this assumes that the front page is + # post/list; in 99% of case it will either be + # post/list or home, and in the latter case + # the subnav links aren't shown, but it would + # be nice to be correct + case "post": + case "upload": + if (class_exists("NumericScore")) { + $custom_sublinks .= "Popular by Day/Month/Year "; + } + $custom_sublinks .= "All "; + if (class_exists("Favorites")) { + $custom_sublinks .= "My Favorites "; + } + if (class_exists("RSS_Images")) { + $custom_sublinks .= "Feed "; + } + if (class_exists("RandomImage")) { + $custom_sublinks .= "Random Image "; + } + if (class_exists("Wiki")) { + $custom_sublinks .= "Help "; + } else { + $custom_sublinks .= "Help "; + } + break; + case "comment": + $custom_sublinks .= "All "; + $custom_sublinks .= "Help "; + break; + case "pool": + $custom_sublinks .= "List "; + $custom_sublinks .= "Create "; + $custom_sublinks .= "Changes "; + $custom_sublinks .= "Help "; + break; + case "wiki": + $custom_sublinks .= "Index "; + $custom_sublinks .= "Rules "; + $custom_sublinks .= "Help "; + break; + case "tags": + case "alias": + $custom_sublinks .= "Map "; + $custom_sublinks .= "Alphabetic "; + $custom_sublinks .= "Popularity "; + $custom_sublinks .= "Categories "; + $custom_sublinks .= "Aliases "; + $custom_sublinks .= "Help "; + break; + } - // bzchan: failed attempt to add heading after title_link (failure was it looked bad) - //if($this->heading==$site_name)$this->heading = ''; - //$title_link = "$site_name/$this->heading
"; + // bzchan: failed attempt to add heading after title_link (failure was it looked bad) + //if($this->heading==$site_name)$this->heading = ''; + //$title_link = "$site_name/$this->heading
"; - // bzchan: prepare main title link - $title_link = "$site_name
"; + // bzchan: prepare main title link + $title_link = "$site_name
"; - if($page->left_enabled) { - $left = ""; - $withleft = "withleft"; - } - else { - $left = ""; - $withleft = "noleft"; - } + if ($page->left_enabled) { + $left = ""; + $withleft = "withleft"; + } else { + $left = ""; + $withleft = "noleft"; + } - $flash = $page->get_cookie("flash_message"); - $flash_html = ""; - if($flash) { - $flash_html = "".nl2br(html_escape($flash))." [X]"; - } + $flash = $page->get_cookie("flash_message"); + $flash_html = ""; + if ($flash) { + $flash_html = "".nl2br(html_escape($flash))." [X]"; + } - print <<@@ -231,34 +241,36 @@ $header_html EOD; - } - - /** - * #param string[] $pages_matched - */ - private function navlinks(string $link, string $desc, array $pages_matched): string { - /** - * Woo! We can actually SEE THE CURRENT PAGE!! (well... see it highlighted in the menu.) - */ - $html = null; - $url = ltrim(_get_query(), "/"); + } + + /** + * #param string[] $pages_matched + */ + private function navlinks(string $link, string $desc, array $pages_matched): string + { + /** + * Woo! We can actually SEE THE CURRENT PAGE!! (well... see it highlighted in the menu.) + */ + $html = null; + $url = ltrim(_get_query(), "/"); - $re1='.*?'; - $re2='((?:[a-z][a-z_]+))'; + $re1='.*?'; + $re2='((?:[a-z][a-z_]+))'; - if (preg_match_all("/".$re1.$re2."/is", $url, $matches)) { - $url=$matches[1][0]; - } - - $count_pages_matched = count($pages_matched); - - for($i=0; $i < $count_pages_matched; $i++) { - if($url == $pages_matched[$i]) { - $html = " $desc "; - } - } - if(is_null($html)) {$html = "$desc ";} - return $html; - } + if (preg_match_all("/".$re1.$re2."/is", $url, $matches)) { + $url=$matches[1][0]; + } + + $count_pages_matched = count($pages_matched); + + for ($i=0; $i < $count_pages_matched; $i++) { + if ($url == $pages_matched[$i]) { + $html = "$desc "; + } + } + if (is_null($html)) { + $html = "$desc "; + } + return $html; + } } - diff --git a/themes/danbooru/tag_list.theme.php b/themes/danbooru/tag_list.theme.php index 6628ca29..780c4d1f 100644 --- a/themes/danbooru/tag_list.theme.php +++ b/themes/danbooru/tag_list.theme.php @@ -1,9 +1,10 @@ disable_left(); - parent::display_page($page); - } +class CustomTagListTheme extends TagListTheme +{ + public function display_page(Page $page) + { + $page->disable_left(); + parent::display_page($page); + } } - diff --git a/themes/danbooru/themelet.class.php b/themes/danbooru/themelet.class.php index 54321c64..a00a75d4 100644 --- a/themes/danbooru/themelet.class.php +++ b/themes/danbooru/themelet.class.php @@ -1,51 +1,66 @@ build_paginator($page_number, $total_pages, $base, $query); - $page->add_block(new Block(null, $body, "main", 90)); - } +class Themelet extends BaseThemelet +{ + public function display_paginator(Page $page, string $base, ?string $query, int $page_number, int $total_pages, bool $show_random = false) + { + if ($total_pages == 0) { + $total_pages = 1; + } + $body = $this->build_paginator($page_number, $total_pages, $base, $query); + $page->add_block(new Block(null, $body, "main", 90)); + } - private function gen_page_link(string $base_url, string $query, string $page, string $name): string { - $link = make_link("$base_url/$page", $query); - return "$name"; - } + private function gen_page_link(string $base_url, string $query, string $page, string $name): string + { + $link = make_link("$base_url/$page", $query); + return "$name"; + } - private function gen_page_link_block(string $base_url, string $query, int $page, int $current_page, string $name): string { - $paginator = ""; - if($page == $current_page) $paginator .= "$page"; - else $paginator .= $this->gen_page_link($base_url, $query, $page, $name); - return $paginator; - } + private function gen_page_link_block(string $base_url, string $query, int $page, int $current_page, string $name): string + { + $paginator = ""; + if ($page == $current_page) { + $paginator .= "$page"; + } else { + $paginator .= $this->gen_page_link($base_url, $query, $page, $name); + } + return $paginator; + } - private function build_paginator(int $current_page, int $total_pages, string $base_url, string $query): string { - $next = $current_page + 1; - $prev = $current_page - 1; + private function build_paginator(int $current_page, int $total_pages, string $base_url, string $query): string + { + $next = $current_page + 1; + $prev = $current_page - 1; - $at_start = ($current_page <= 3 || $total_pages <= 3); - $at_end = ($current_page >= $total_pages -2); + $at_start = ($current_page <= 3 || $total_pages <= 3); + $at_end = ($current_page >= $total_pages -2); - $first_html = $at_start ? "" : $this->gen_page_link($base_url, $query, 1, "1"); - $prev_html = $at_start ? "" : $this->gen_page_link($base_url, $query, $prev, "<<"); - $next_html = $at_end ? "" : $this->gen_page_link($base_url, $query, $next, ">>"); - $last_html = $at_end ? "" : $this->gen_page_link($base_url, $query, $total_pages, "$total_pages"); + $first_html = $at_start ? "" : $this->gen_page_link($base_url, $query, 1, "1"); + $prev_html = $at_start ? "" : $this->gen_page_link($base_url, $query, $prev, "<<"); + $next_html = $at_end ? "" : $this->gen_page_link($base_url, $query, $next, ">>"); + $last_html = $at_end ? "" : $this->gen_page_link($base_url, $query, $total_pages, "$total_pages"); - $start = $current_page-2 > 1 ? $current_page-2 : 1; - $end = $current_page+2 <= $total_pages ? $current_page+2 : $total_pages; + $start = $current_page-2 > 1 ? $current_page-2 : 1; + $end = $current_page+2 <= $total_pages ? $current_page+2 : $total_pages; - $pages = array(); - foreach(range($start, $end) as $i) { - $pages[] = $this->gen_page_link_block($base_url, $query, $i, $current_page, $i); - } - $pages_html = implode(" ", $pages); + $pages = []; + foreach (range($start, $end) as $i) { + $pages[] = $this->gen_page_link_block($base_url, $query, $i, $current_page, $i); + } + $pages_html = implode(" ", $pages); - if(strlen($first_html) > 0) $pdots = "..."; - else $pdots = ""; + if (strlen($first_html) > 0) { + $pdots = "..."; + } else { + $pdots = ""; + } - if(strlen($last_html) > 0) $ndots = "..."; - else $ndots = ""; + if (strlen($last_html) > 0) { + $ndots = "..."; + } else { + $ndots = ""; + } - return "$prev_html $first_html $pdots $pages_html $ndots $last_html $next_html"; - } + return "$prev_html $first_html $pdots $pages_html $ndots $last_html $next_html"; + } } - diff --git a/themes/danbooru/upload.theme.php b/themes/danbooru/upload.theme.php index a7047cf3..818702cd 100644 --- a/themes/danbooru/upload.theme.php +++ b/themes/danbooru/upload.theme.php @@ -1,14 +1,16 @@ add_block(new Block("Upload", $this->build_upload_block(), "left", 20)); - } +class CustomUploadTheme extends UploadTheme +{ + public function display_block(Page $page) + { + // this theme links to /upload + // $page->add_block(new Block("Upload", $this->build_upload_block(), "left", 20)); + } - public function display_page(Page $page) { - $page->disable_left(); - parent::display_page($page); - } + public function display_page(Page $page) + { + $page->disable_left(); + parent::display_page($page); + } } - diff --git a/themes/danbooru/user.theme.php b/themes/danbooru/user.theme.php index d1fa8682..4ba40100 100644 --- a/themes/danbooru/user.theme.php +++ b/themes/danbooru/user.theme.php @@ -1,12 +1,14 @@ set_title("Login"); - $page->set_heading("Login"); - $page->disable_left(); - $html = " +class CustomUserPageTheme extends UserPageTheme +{ + public function display_login_page(Page $page) + { + global $config; + $page->set_title("Login"); + $page->set_heading("Login"); + $page->disable_left(); + $html = ""; - if($config->get_bool("login_signup_enabled")) { - $html .= "Create Account"; - } - $page->add_block(new Block("Login", $html, "main", 90)); - } + if ($config->get_bool("login_signup_enabled")) { + $html .= "Create Account"; + } + $page->add_block(new Block("Login", $html, "main", 90)); + } - public function display_user_links(Page $page, User $user, $parts) { - // no block in this theme - } - public function display_login_block(Page $page) { - // no block in this theme - } + public function display_user_links(Page $page, User $user, $parts) + { + // no block in this theme + } + public function display_login_block(Page $page) + { + // no block in this theme + } - public function display_user_block(Page $page, User $user, $parts) { - $html = ""; - $blocked = array("Pools", "Pool Changes", "Alias Editor", "My Profile"); - foreach($parts as $part) { - if(in_array($part["name"], $blocked)) continue; - $html .= "
@@ -21,43 +23,52 @@ class CustomUserPageTheme extends UserPageTheme { {$part["name"]}"; - } - $page->add_block(new Block("User Links", $html, "user", 90)); - } + public function display_user_block(Page $page, User $user, $parts) + { + $html = ""; + $blocked = ["Pools", "Pool Changes", "Alias Editor", "My Profile"]; + foreach ($parts as $part) { + if (in_array($part["name"], $blocked)) { + continue; + } + $html .= " {$part["name"]}"; + } + $page->add_block(new Block("User Links", $html, "user", 90)); + } - public function display_signup_page(Page $page) { - global $config; - $tac = $config->get_string("login_tac", ""); + public function display_signup_page(Page $page) + { + global $config; + $tac = $config->get_string("login_tac", ""); - $tfe = new TextFormattingEvent($tac); - send_event($tfe); - $tac = $tfe->formatted; - - $reca = " "; + $tfe = new TextFormattingEvent($tac); + send_event($tfe); + $tac = $tfe->formatted; + + $reca = " ".captcha_get_html()." "; - if(empty($tac)) {$html = "";} - else {$html = " ".captcha_get_html()." $tac
";} + if (empty($tac)) { + $html = ""; + } else { + $html = "$tac
"; + } - $html .= " + $html .= "
@@ -70,32 +81,33 @@ class CustomUserPageTheme extends UserPageTheme { "; - $page->set_title("Create Account"); - $page->set_heading("Create Account"); - $page->disable_left(); - $page->add_block(new Block("Signup", $html)); - } + $page->set_title("Create Account"); + $page->set_heading("Create Account"); + $page->disable_left(); + $page->add_block(new Block("Signup", $html)); + } - public function display_ip_list(Page $page, array $uploads, array $comments) { - $html = " Name "; - $html .= "
"; + public function display_ip_list(Page $page, array $uploads, array $comments) + { + $html = ""; - $html .= " Uploaded from: "; - foreach($uploads as $ip => $count) { - $html .= "
$ip ($count)"; - } - $html .= "Commented from:"; - foreach($comments as $ip => $count) { - $html .= "
$ip ($count)"; - } - $html .= "(Most recent at top) "; + $html .= "
"; - $page->add_block(new Block("IPs", $html)); - } + $page->add_block(new Block("IPs", $html)); + } - public function display_user_page(User $duser, $stats) { - global $page; - $page->disable_left(); - parent::display_user_page($duser, $stats); - } + public function display_user_page(User $duser, $stats) + { + global $page; + $page->disable_left(); + parent::display_user_page($duser, $stats); + } } - diff --git a/themes/danbooru/view.theme.php b/themes/danbooru/view.theme.php index d7b5aae6..62f67c3b 100644 --- a/themes/danbooru/view.theme.php +++ b/themes/danbooru/view.theme.php @@ -1,52 +1,54 @@ set_title("Image {$image->id}: ".html_escape($image->get_tag_list())); - $page->set_heading(html_escape($image->get_tag_list())); - $page->add_block(new Block("Navigation", $this->build_navigation($image), "left", 0)); - $page->add_block(new Block("Statistics", $this->build_stats($image), "left", 15)); - $page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 10)); - $page->add_block(new Block(null, $this->build_pin($image), "main", 11)); - } - - private function build_stats(Image $image) { - $h_owner = html_escape($image->get_owner()->name); - $h_ownerlink = "$h_owner"; - $h_ip = html_escape($image->owner_ip); - $h_date = autodate($image->posted); - $h_filesize = to_shorthand_int($image->filesize); +class CustomViewImageTheme extends ViewImageTheme +{ + public function display_page(Image $image, $editor_parts) + { + global $page; + $page->set_title("Image {$image->id}: ".html_escape($image->get_tag_list())); + $page->set_heading(html_escape($image->get_tag_list())); + $page->add_block(new Block("Navigation", $this->build_navigation($image), "left", 0)); + $page->add_block(new Block("Statistics", $this->build_stats($image), "left", 15)); + $page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 10)); + $page->add_block(new Block(null, $this->build_pin($image), "main", 11)); + } + + private function build_stats(Image $image) + { + $h_owner = html_escape($image->get_owner()->name); + $h_ownerlink = "$h_owner"; + $h_ip = html_escape($image->owner_ip); + $h_date = autodate($image->posted); + $h_filesize = to_shorthand_int($image->filesize); - global $user; - if($user->can("view_ip")) { - $h_ownerlink .= " ($h_ip)"; - } + global $user; + if ($user->can("view_ip")) { + $h_ownerlink .= " ($h_ip)"; + } - $html = " + $html = " Id: {$image->id}"; + $html .= " Uploaded from: "; + foreach ($uploads as $ip => $count) { + $html .= "
$ip ($count)"; + } + $html .= "Commented from:"; + foreach ($comments as $ip => $count) { + $html .= "
$ip ($count)"; + } + $html .= "(Most recent at top)
Posted: $h_date by $h_ownerlink
Size: {$image->width}x{$image->height}
Filesize: $h_filesize "; - if(!is_null($image->source)) { - $h_source = html_escape($image->source); - if(substr($image->source, 0, 7) != "http://" && substr($image->source, 0, 8) != "https://") { - $h_source = "http://" . $h_source; - } - $html .= "
Source: link"; - } + if (!is_null($image->source)) { + $h_source = html_escape($image->source); + if (substr($image->source, 0, 7) != "http://" && substr($image->source, 0, 8) != "https://") { + $h_source = "http://" . $h_source; + } + $html .= "
Source: link"; + } - if(ext_is_live("Ratings")) { - if($image->rating == null || $image->rating == "u"){ - $image->rating = "u"; - } - $h_rating = Ratings::rating_to_human($image->rating); - $html .= "
Rating: $h_rating"; - } + if (ext_is_live("Ratings")) { + if ($image->rating == null || $image->rating == "u") { + $image->rating = "u"; + } + $h_rating = Ratings::rating_to_human($image->rating); + $html .= "
Rating: $h_rating"; + } - return $html; - } + return $html; + } } - diff --git a/themes/danbooru2/admin.theme.php b/themes/danbooru2/admin.theme.php index b46694de..ef4dbe00 100644 --- a/themes/danbooru2/admin.theme.php +++ b/themes/danbooru2/admin.theme.php @@ -1,11 +1,11 @@ disable_left(); - parent::display_page(); - } +class CustomAdminPageTheme extends AdminPageTheme +{ + public function display_page() + { + global $page; + $page->disable_left(); + parent::display_page(); + } } - - diff --git a/themes/danbooru2/comment.theme.php b/themes/danbooru2/comment.theme.php index a9fef1dd..c817fa09 100644 --- a/themes/danbooru2/comment.theme.php +++ b/themes/danbooru2/comment.theme.php @@ -1,76 +1,76 @@ disable_left(); + $page->disable_left(); - // parts for the whole page - $prev = $page_number - 1; - $next = $page_number + 1; + // parts for the whole page + $prev = $page_number - 1; + $next = $page_number + 1; - $h_prev = ($page_number <= 1) ? "Prev" : - "Prev"; - $h_index = "Index"; - $h_next = ($page_number >= $total_pages) ? "Next" : - "Next"; + $h_prev = ($page_number <= 1) ? "Prev" : + "Prev"; + $h_index = "Index"; + $h_next = ($page_number >= $total_pages) ? "Next" : + "Next"; - $nav = "$h_prev | $h_index | $h_next"; + $nav = "$h_prev | $h_index | $h_next"; - $page->set_title("Comments"); - $page->set_heading("Comments"); - $page->add_block(new Block("Navigation", $nav, "left")); - $this->display_paginator($page, "comment/list", null, $page_number, $total_pages); + $page->set_title("Comments"); + $page->set_heading("Comments"); + $page->add_block(new Block("Navigation", $nav, "left")); + $this->display_paginator($page, "comment/list", null, $page_number, $total_pages); - // parts for each image - $position = 10; - - $comment_captcha = $config->get_bool('comment_captcha'); - $comment_limit = $config->get_int("comment_list_count", 10); - - foreach($images as $pair) { - $image = $pair[0]; - $comments = $pair[1]; + // parts for each image + $position = 10; + + $comment_captcha = $config->get_bool('comment_captcha'); + $comment_limit = $config->get_int("comment_list_count", 10); + + foreach ($images as $pair) { + $image = $pair[0]; + $comments = $pair[1]; - $thumb_html = $this->build_thumb_html($image); + $thumb_html = $this->build_thumb_html($image); - $s = " "; - $un = $image->get_owner()->name; - $t = ""; - foreach($image->get_tag_array() as $tag) { - $u_tag = url_escape($tag); - $t .= "".html_escape($tag)." "; - } - $p = autodate($image->posted); + $s = " "; + $un = $image->get_owner()->name; + $t = ""; + foreach ($image->get_tag_array() as $tag) { + $u_tag = url_escape($tag); + $t .= "".html_escape($tag)." "; + } + $p = autodate($image->posted); - $r = ext_is_live("Ratings") ? "Rating ".Ratings::rating_to_human($image->rating) : ""; - $comment_html = "Date $p $s User $un $s $r
Tags $t"; + $r = ext_is_live("Ratings") ? "Rating ".Ratings::rating_to_human($image->rating) : ""; + $comment_html = "Date $p $s User $un $s $r
Tags $t"; - $comment_count = count($comments); - if($comment_limit > 0 && $comment_count > $comment_limit) { - //$hidden = $comment_count - $comment_limit; - $comment_html .= "
showing $comment_limit of $comment_count comments
"; - $comments = array_slice($comments, -$comment_limit); - } - foreach($comments as $comment) { - $comment_html .= $this->comment_to_html($comment); - } - if($can_post) { - if(!$user->is_anonymous()) { - $comment_html .= $this->build_postbox($image->id); - } - else { - if(!$comment_captcha) { - $comment_html .= $this->build_postbox($image->id); - } - else { - $comment_html .= "Add Comment"; - } - } - } + $comment_count = count($comments); + if ($comment_limit > 0 && $comment_count > $comment_limit) { + //$hidden = $comment_count - $comment_limit; + $comment_html .= "showing $comment_limit of $comment_count comments
"; + $comments = array_slice($comments, -$comment_limit); + } + foreach ($comments as $comment) { + $comment_html .= $this->comment_to_html($comment); + } + if ($can_post) { + if (!$user->is_anonymous()) { + $comment_html .= $this->build_postbox($image->id); + } else { + if (!$comment_captcha) { + $comment_html .= $this->build_postbox($image->id); + } else { + $comment_html .= "Add Comment"; + } + } + } - $html = " + $html = "
$thumb_html $comment_html @@ -78,50 +78,50 @@ class CustomCommentListTheme extends CommentListTheme { "; - $page->add_block(new Block(" ", $html, "main", $position++)); - } - } + $page->add_block(new Block(" ", $html, "main", $position++)); + } + } - public function display_recent_comments($comments) { - // no recent comments in this theme - } + public function display_recent_comments($comments) + { + // no recent comments in this theme + } - protected function comment_to_html(Comment $comment, $trim=false) { - global $user; + protected function comment_to_html(Comment $comment, $trim=false) + { + global $user; - $tfe = new TextFormattingEvent($comment->comment); - send_event($tfe); + $tfe = new TextFormattingEvent($comment->comment); + send_event($tfe); - //$i_uid = int_escape($comment->owner_id); - $h_name = html_escape($comment->owner_name); - //$h_poster_ip = html_escape($comment->poster_ip); - $h_comment = ($trim ? substr($tfe->stripped, 0, 50)."..." : $tfe->formatted); - $i_comment_id = int_escape($comment->comment_id); - $i_image_id = int_escape($comment->image_id); - $h_posted = autodate($comment->posted); + //$i_uid = int_escape($comment->owner_id); + $h_name = html_escape($comment->owner_name); + //$h_poster_ip = html_escape($comment->poster_ip); + $h_comment = ($trim ? substr($tfe->stripped, 0, 50)."..." : $tfe->formatted); + $i_comment_id = int_escape($comment->comment_id); + $i_image_id = int_escape($comment->image_id); + $h_posted = autodate($comment->posted); - $h_userlink = "$h_name"; - $h_del = ""; - if ($user->can("delete_comment")) { - $comment_preview = substr(html_unescape($tfe->stripped), 0, 50); - $j_delete_confirm_message = json_encode("Delete comment by {$comment->owner_name}:\n$comment_preview"); - $h_delete_script = html_escape("return confirm($j_delete_confirm_message);"); - $h_delete_link = make_link("comment/delete/$i_comment_id/$i_image_id"); - $h_del = " - Del"; - } - //$h_imagelink = $trim ? ">>>\n" : ""; - if($trim) { - return "$h_userlink $h_del
"; - } - else { - return " + $h_userlink = "$h_name"; + $h_del = ""; + if ($user->can("delete_comment")) { + $comment_preview = substr(html_unescape($tfe->stripped), 0, 50); + $j_delete_confirm_message = json_encode("Delete comment by {$comment->owner_name}:\n$comment_preview"); + $h_delete_script = html_escape("return confirm($j_delete_confirm_message);"); + $h_delete_link = make_link("comment/delete/$i_comment_id/$i_image_id"); + $h_del = " - Del"; + } + //$h_imagelink = $trim ? ">>>\n" : ""; + if ($trim) { + return "
$h_posted
$h_comment$h_userlink $h_del
"; + } else { + return "
$h_posted
$h_comment"; - } - } + } + } } - diff --git a/themes/danbooru2/custompage.class.php b/themes/danbooru2/custompage.class.php index d8aca86c..1087bfd2 100644 --- a/themes/danbooru2/custompage.class.php +++ b/themes/danbooru2/custompage.class.php @@ -1,9 +1,10 @@ left_enabled = false; - } +class CustomPage extends Page +{ + public $left_enabled = true; + public function disable_left() + { + $this->left_enabled = false; + } } - diff --git a/themes/danbooru2/ext_manager.theme.php b/themes/danbooru2/ext_manager.theme.php index 23925a0c..247406c8 100644 --- a/themes/danbooru2/ext_manager.theme.php +++ b/themes/danbooru2/ext_manager.theme.php @@ -1,15 +1,16 @@ disable_left(); - parent::display_table($page, $extensions, $editable); - } +class CustomExtManagerTheme extends ExtManagerTheme +{ + public function display_table(Page $page, array $extensions, bool $editable) + { + $page->disable_left(); + parent::display_table($page, $extensions, $editable); + } - public function display_doc(Page $page, ExtensionInfo $info) { - $page->disable_left(); - parent::display_doc($page, $info); - } + public function display_doc(Page $page, ExtensionInfo $info) + { + $page->disable_left(); + parent::display_doc($page, $info); + } } - - diff --git a/themes/danbooru2/index.theme.php b/themes/danbooru2/index.theme.php index cc6b5596..e14202e9 100644 --- a/themes/danbooru2/index.theme.php +++ b/themes/danbooru2/index.theme.php @@ -1,48 +1,48 @@ search_terms) == 0) { - $query = null; - $page_title = $config->get_string('title'); - } - else { - $search_string = implode(' ', $this->search_terms); - $query = url_escape($search_string); - $page_title = html_escape($search_string); - } + if (count($this->search_terms) == 0) { + $query = null; + $page_title = $config->get_string('title'); + } else { + $search_string = implode(' ', $this->search_terms); + $query = url_escape($search_string); + $page_title = html_escape($search_string); + } - $nav = $this->build_navigation($this->page_number, $this->total_pages, $this->search_terms); - $page->set_title($page_title); - $page->set_heading($page_title); - $page->add_block(new Block("Search", $nav, "left", 0)); - if(count($images) > 0) { - if($query) { - $page->add_block(new Block("Images", $this->build_table($images, "search=$query"), "main", 10)); - $this->display_paginator($page, "post/list/$query", null, $this->page_number, $this->total_pages); - } - else { - $page->add_block(new Block("Images", $this->build_table($images, null), "main", 10)); - $this->display_paginator($page, "post/list", null, $this->page_number, $this->total_pages); - } - } - else { - $page->add_block(new Block("No Images Found", "No images were found to match the search criteria")); - } - } + $nav = $this->build_navigation($this->page_number, $this->total_pages, $this->search_terms); + $page->set_title($page_title); + $page->set_heading($page_title); + $page->add_block(new Block("Search", $nav, "left", 0)); + if (count($images) > 0) { + if ($query) { + $page->add_block(new Block("Images", $this->build_table($images, "search=$query"), "main", 10)); + $this->display_paginator($page, "post/list/$query", null, $this->page_number, $this->total_pages); + } else { + $page->add_block(new Block("Images", $this->build_table($images, null), "main", 10)); + $this->display_paginator($page, "post/list", null, $this->page_number, $this->total_pages); + } + } else { + $page->add_block(new Block("No Images Found", "No images were found to match the search criteria")); + } + } - /** - * #param string[] $search_terms - */ - protected function build_navigation(int $page_number, int $total_pages, array $search_terms): string { - $h_search_string = count($search_terms) == 0 ? "" : html_escape(implode(" ", $search_terms)); - $h_search_link = make_link(); - $h_search = " + /** + * #param string[] $search_terms + */ + protected function build_navigation(int $page_number, int $total_pages, array $search_terms): string + { + $h_search_string = count($search_terms) == 0 ? "" : html_escape(implode(" ", $search_terms)); + $h_search_link = make_link(); + $h_search = "
$h_userlink
$h_posted$h_del$h_comment @@ -50,20 +50,20 @@ class CustomIndexTheme extends IndexTheme { "; - return $h_search; - } + return $h_search; + } - /** - * #param Image[] $images - */ - protected function build_table(array $images, string $query): string { - $h_query = html_escape($query); - $table = ""; - foreach($images as $image) { - $table .= "\t" . $this->build_thumb_html($image) . "\n"; - } - $table .= ""; - return $table; - } + /** + * #param Image[] $images + */ + protected function build_table(array $images, string $query): string + { + $h_query = html_escape($query); + $table = ""; + foreach ($images as $image) { + $table .= "\t" . $this->build_thumb_html($image) . "\n"; + } + $table .= ""; + return $table; + } } - diff --git a/themes/danbooru2/layout.class.php b/themes/danbooru2/layout.class.php index 7c1fa3f6..b78d5f93 100644 --- a/themes/danbooru2/layout.class.php +++ b/themes/danbooru2/layout.class.php @@ -26,12 +26,12 @@ Changes in this theme include - $site_name and $front_name retreival from config added. - $custom_link and $title_link preparation just before html is outputed. - Altered outputed html to include the custom links and removed heading - from being displayed (subheading is still displayed) + from being displayed (subheading is still displayed) - Note that only the sidebar has been left aligned. Could not properly left align the main block because blocks without headers currently do not have ids on there div elements. (this was a problem because paginator block must be centered and everything else left aligned) - + Tips - You can change custom links to point to whatever pages you want as well as adding more custom links. @@ -42,180 +42,190 @@ Tips * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -class Layout { - public function display_page($page) { - global $config, $user; +class Layout +{ + public function display_page($page) + { + global $config, $user; - //$theme_name = $config->get_string('theme'); - //$base_href = $config->get_string('base_href'); - //$data_href = get_base_href(); - $contact_link = contact_link(); - $header_html = $page->get_all_html_headers(); + //$theme_name = $config->get_string('theme'); + //$base_href = $config->get_string('base_href'); + //$data_href = get_base_href(); + $contact_link = contact_link(); + $header_html = $page->get_all_html_headers(); - $left_block_html = ""; - $user_block_html = ""; - $main_block_html = ""; - $sub_block_html = ""; + $left_block_html = ""; + $user_block_html = ""; + $main_block_html = ""; + $sub_block_html = ""; - foreach($page->blocks as $block) { - switch($block->section) { - case "left": - $left_block_html .= $block->get_html(true); - break; - case "user": - $user_block_html .= $block->body; // $this->block_to_html($block, true); - break; - case "subheading": - $sub_block_html .= $block->body; // $this->block_to_html($block, true); - break; - case "main": - if($block->header == "Images") { - $block->header = " "; - } - $main_block_html .= $block->get_html(false); - break; - default: - print "error: {$block->header} using an unknown section ({$block->section})"; - break; - } - } + foreach ($page->blocks as $block) { + switch ($block->section) { + case "left": + $left_block_html .= $block->get_html(true); + break; + case "user": + $user_block_html .= $block->body; // $this->block_to_html($block, true); + break; + case "subheading": + $sub_block_html .= $block->body; // $this->block_to_html($block, true); + break; + case "main": + if ($block->header == "Images") { + $block->header = " "; + } + $main_block_html .= $block->get_html(false); + break; + default: + print "
error: {$block->header} using an unknown section ({$block->section})"; + break; + } + } - $debug = get_debug_info(); + $debug = get_debug_info(); - $contact = empty($contact_link) ? "" : "
Contact"; + $contact = empty($contact_link) ? "" : "
Contact"; - if(empty($this->subheading)) { - $subheading = ""; - } - else { - $subheading = "{$this->subheading}"; - } + if (empty($this->subheading)) { + $subheading = ""; + } else { + $subheading = "{$this->subheading}"; + } - $site_name = $config->get_string('title'); // bzchan: change from normal default to get title for top of page - $main_page = $config->get_string('main_page'); // bzchan: change from normal default to get main page for top of page + $site_name = $config->get_string('title'); // bzchan: change from normal default to get title for top of page + $main_page = $config->get_string('main_page'); // bzchan: change from normal default to get main page for top of page - // bzchan: CUSTOM LINKS are prepared here, change these to whatever you like - $custom_links = ""; - if($user->is_anonymous()) { - $custom_links .= $this->navlinks(make_link('user_admin/login'), "Sign in", array("user", "user_admin", "setup", "admin")); - } - else { - $custom_links .= $this->navlinks(make_link('user'), "My Account", array("user", "user_admin")); - } - if($user->is_admin()) { - $custom_links .= $this->navlinks(make_link('admin'), "Admin", array("admin", "ext_manager", "setup")); - } - $custom_links .= $this->navlinks(make_link('post/list'), "Posts", array("post", "upload", "", "random_image")); - $custom_links .= $this->navlinks(make_link('comment/list'), "Comments", array("comment")); - $custom_links .= $this->navlinks(make_link('tags'), "Tags", array("tags", "alias")); - if(class_exists("Pools")) { - $custom_links .= $this->navlinks(make_link('pool/list'), "Pools", array("pool")); - } - if(class_exists("Wiki")) { - $custom_links .= $this->navlinks(make_link('wiki'), "Wiki", array("wiki")); - $custom_links .= $this->navlinks(make_link('wiki/more'), "More »", array("wiki/more")); - } + // bzchan: CUSTOM LINKS are prepared here, change these to whatever you like + $custom_links = ""; + if ($user->is_anonymous()) { + $custom_links .= $this->navlinks(make_link('user_admin/login'), "Sign in", ["user", "user_admin", "setup", "admin"]); + } else { + $custom_links .= $this->navlinks(make_link('user'), "My Account", ["user", "user_admin"]); + } + if ($user->is_admin()) { + $custom_links .= $this->navlinks(make_link('admin'), "Admin", ["admin", "ext_manager", "setup"]); + } + $custom_links .= $this->navlinks(make_link('post/list'), "Posts", ["post", "upload", "", "random_image"]); + $custom_links .= $this->navlinks(make_link('comment/list'), "Comments", ["comment"]); + $custom_links .= $this->navlinks(make_link('tags'), "Tags", ["tags", "alias"]); + if (class_exists("Pools")) { + $custom_links .= $this->navlinks(make_link('pool/list'), "Pools", ["pool"]); + } + if (class_exists("Wiki")) { + $custom_links .= $this->navlinks(make_link('wiki'), "Wiki", ["wiki"]); + $custom_links .= $this->navlinks(make_link('wiki/more'), "More »", ["wiki/more"]); + } - $custom_sublinks = ""; - // hack - $username = url_escape($user->name); - // hack - $qp = explode("/", ltrim(_get_query(), "/")); - // php sucks - switch($qp[0]) { - default: - case "ext_doc": - $custom_sublinks .= $user_block_html; - break; - case "user": - case "user_admin": - if($user->is_anonymous()) { - $custom_sublinks .= "Sign up "; - // $custom_sublinks .= "Reset Password "; - // $custom_sublinks .= "Login Reminder "; - } else { - $custom_sublinks .= "Sign out "; - } - break; - case "": - # FIXME: this assumes that the front page is - # post/list; in 99% of case it will either be - # post/list or home, and in the latter case - # the subnav links aren't shown, but it would - # be nice to be correct - case "random_image": - case "post": - case "upload": - if(class_exists("NumericScore")){ $custom_sublinks .= "Popular by Day/Month/Year ";} - $custom_sublinks .= "Listing "; - if(class_exists("Favorites")){ $custom_sublinks .= "My Favorites ";} - if(class_exists("RSS_Images")){ $custom_sublinks .= "Feed ";} - if(class_exists("RandomImage")){ $custom_sublinks .= "Random ";} - $custom_sublinks .= "Upload "; - if(class_exists("Wiki")){ $custom_sublinks .= "Help "; - }else{ $custom_sublinks .= "Help ";} - break; - case "comment": - $custom_sublinks .= "All "; - $custom_sublinks .= "Help "; - break; - case "pool": - $custom_sublinks .= "List "; - $custom_sublinks .= "Create "; - $custom_sublinks .= "Changes "; - $custom_sublinks .= "Help "; - break; - case "wiki": - $custom_sublinks .= "Index "; - $custom_sublinks .= "Rules "; - $custom_sublinks .= "Help "; - break; - case "tags": - case "alias": - $custom_sublinks .= "Map "; - $custom_sublinks .= "Alphabetic "; - $custom_sublinks .= "Popularity "; - $custom_sublinks .= "Categories "; - $custom_sublinks .= "Aliases "; - $custom_sublinks .= "Help "; - break; - case "admin": - case "ext_manager": - case "setup": - if($user->is_admin()) { - $custom_sublinks .= "Extension Manager "; - $custom_sublinks .= "Board Config "; - $custom_sublinks .= "Alias Editor "; - } else { - $custom_sublinks .= "I think you might be lost "; - } - break; - } + $custom_sublinks = ""; + // hack + $username = url_escape($user->name); + // hack + $qp = explode("/", ltrim(_get_query(), "/")); + // php sucks + switch ($qp[0]) { + default: + case "ext_doc": + $custom_sublinks .= $user_block_html; + break; + case "user": + case "user_admin": + if ($user->is_anonymous()) { + $custom_sublinks .= "Sign up "; + // $custom_sublinks .= "Reset Password "; + // $custom_sublinks .= "Login Reminder "; + } else { + $custom_sublinks .= "Sign out "; + } + break; + case "": + # FIXME: this assumes that the front page is + # post/list; in 99% of case it will either be + # post/list or home, and in the latter case + # the subnav links aren't shown, but it would + # be nice to be correct + case "random_image": + case "post": + case "upload": + if (class_exists("NumericScore")) { + $custom_sublinks .= "Popular by Day/Month/Year "; + } + $custom_sublinks .= "Listing "; + if (class_exists("Favorites")) { + $custom_sublinks .= "My Favorites "; + } + if (class_exists("RSS_Images")) { + $custom_sublinks .= "Feed "; + } + if (class_exists("RandomImage")) { + $custom_sublinks .= "Random "; + } + $custom_sublinks .= "Upload "; + if (class_exists("Wiki")) { + $custom_sublinks .= "Help "; + } else { + $custom_sublinks .= "Help "; + } + break; + case "comment": + $custom_sublinks .= "All "; + $custom_sublinks .= "Help "; + break; + case "pool": + $custom_sublinks .= "List "; + $custom_sublinks .= "Create "; + $custom_sublinks .= "Changes "; + $custom_sublinks .= "Help "; + break; + case "wiki": + $custom_sublinks .= "Index "; + $custom_sublinks .= "Rules "; + $custom_sublinks .= "Help "; + break; + case "tags": + case "alias": + $custom_sublinks .= "Map "; + $custom_sublinks .= "Alphabetic "; + $custom_sublinks .= "Popularity "; + $custom_sublinks .= "Categories "; + $custom_sublinks .= "Aliases "; + $custom_sublinks .= "Help "; + break; + case "admin": + case "ext_manager": + case "setup": + if ($user->is_admin()) { + $custom_sublinks .= "Extension Manager "; + $custom_sublinks .= "Board Config "; + $custom_sublinks .= "Alias Editor "; + } else { + $custom_sublinks .= "I think you might be lost "; + } + break; + } - // bzchan: failed attempt to add heading after title_link (failure was it looked bad) - //if($this->heading==$site_name)$this->heading = ''; - //$title_link = "$site_name/$this->heading
"; + // bzchan: failed attempt to add heading after title_link (failure was it looked bad) + //if($this->heading==$site_name)$this->heading = ''; + //$title_link = "$site_name/$this->heading
"; - // bzchan: prepare main title link - $title_link = "$site_name
"; + // bzchan: prepare main title link + $title_link = "$site_name
"; - if($page->left_enabled) { - $left = ""; - $withleft = "withleft"; - } - else { - $left = ""; - $withleft = "noleft"; - } + if ($page->left_enabled) { + $left = ""; + $withleft = "withleft"; + } else { + $left = ""; + $withleft = "noleft"; + } - $flash = $page->get_cookie("flash_message"); - $flash_html = ""; - if($flash) { - $flash_html = "".nl2br(html_escape($flash))." [X]"; - } + $flash = $page->get_cookie("flash_message"); + $flash_html = ""; + if ($flash) { + $flash_html = "".nl2br(html_escape($flash))." [X]"; + } - print <<@@ -257,28 +267,30 @@ $header_html