diff --git a/README.txt b/README.txt index 799d93bf..da0df9fd 100644 --- a/README.txt +++ b/README.txt @@ -74,6 +74,14 @@ new UserClass("anonymous", "base", array( "create_image_report" => True, )); +For a moderator class, being a regular user who can delete images and +comments: + +new UserClass("moderator", "user", array( + "delete_image" => True, + "delete_comment" => True, +)); + For a list of permissions, see core/userclass.class.php diff --git a/core/config.class.php b/core/config.class.php index 7e76b66c..8fc7b4d9 100644 --- a/core/config.class.php +++ b/core/config.class.php @@ -103,7 +103,7 @@ abstract class BaseConfig implements Config { return $this->get($name, $default); } public function get_bool(/*string*/ $name, $default=null) { - return undb_bool($this->get($name, $default)); + return bool_escape($this->get($name, $default)); } public function get_array(/*string*/ $name, $default=array()) { return explode(",", $this->get($name, "")); diff --git a/core/database.class.php b/core/database.class.php index ecd617fd..9b254f31 100644 --- a/core/database.class.php +++ b/core/database.class.php @@ -412,12 +412,34 @@ class Database { } } - /** * Create a table from pseudo-SQL */ public function create_table($name, $data) { $this->execute($this->engine->create_table_sql($name, $data)); } + + /** + * Returns the number of tables present in the current database. + */ + public function count_tables() { + 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(".tables") + ); + } else { + // Hard to find a universal way to do this... + return NULL; + } + } + } ?> diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php index cd356513..4e2b8cda 100644 --- a/core/imageboard.pack.php +++ b/core/imageboard.pack.php @@ -56,7 +56,7 @@ class Image { $this->$name = $value; // hax } $this->posted_timestamp = strtotime($this->posted); // pray - $this->locked = undb_bool($this->locked); + $this->locked = bool_escape($this->locked); assert(is_numeric($this->id)); assert(is_numeric($this->height)); @@ -385,16 +385,66 @@ class Image { /** * Get the image's mime type * - * FIXME: now we handle more than just images - * * @retval string */ public function get_mime_type() { - $type = strtolower($this->ext); - if($type === "jpg") $type = "jpeg"; - return 'image/'.$type; + return __getMimeType( get_image_filename() ); } + /** + * Get MIME type for file + * + * The contents of this function are taken from the __getMimeType() function + * from the "Amazon S3 PHP class" which is Copyright (c) 2008, Donovan Sch�nknecht + * and released under the 'Simplified BSD License'. + * + * @internal Used to get mime types + * @param string &$file File path + * @return string + */ + public static function __getMimeType(&$file) + { + $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 ($type !== false && strlen($type) > 0) return $type; + + // Otherwise do it the old fashioned way + static $exts = array( + 'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', + 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon', + 'swf' => 'application/x-shockwave-flash', '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' + ); + $ext = strtolower(pathInfo($file, PATHINFO_EXTENSION)); + return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream'; + } + /** * Get the image's filename extension * @@ -439,7 +489,7 @@ class Image { $sln = $database->engine->scoreql_to_sql('SCORE_BOOL_'.$ln); $sln = str_replace("'", "", $sln); $sln = str_replace('"', "", $sln); - if(undb_bool($sln) !== $this->locked) { + 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"); } diff --git a/core/util.inc.php b/core/util.inc.php index dd815671..0505a228 100644 --- a/core/util.inc.php +++ b/core/util.inc.php @@ -34,6 +34,24 @@ function int_escape($input) { * @retval string */ function url_escape($input) { + /* + 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); + + /* 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 ""; } @@ -61,16 +79,32 @@ function sql_escape($input) { * @retval boolean */ function bool_escape($input) { - $input = strtolower($input); - return ( - $input === "y" || - $input === "yes" || - $input === "t" || - $input === "true" || - $input === "on" || - $input === 1 || - $input === true - ); + /* + 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" + ); + } + } } /** @@ -205,15 +239,6 @@ function show_ip($ip, $ban_reason) { return $ip; } -/** - * Different databases have different ways to represent booleans; this - * will try and standardise them - */ -function undb_bool($val) { - if($val === true || $val == 'Y' || $val == 'y' || $val == 'T' || $val == 't' || $val === 1) return true; - if($val === false || $val == 'N' || $val == 'n' || $val == 'F' || $val == 'f' || $val === 0) return false; -} - /** * Checks if a given string contains another at the beginning. * diff --git a/ext/ban_words/main.php b/ext/ban_words/main.php index f17b76bf..88fe247a 100644 --- a/ext/ban_words/main.php +++ b/ext/ban_words/main.php @@ -54,9 +54,29 @@ xanax } public function onCommentPosting(CommentPostingEvent $event) { + $this->test_text($event->comment, new CommentPostingException("Comment contains banned terms")); + } + + public function onSourceSet(SourceSetEvent $event) { + $this->test_text($event->source, new SCoreException("Source contains banned terms")); + } + + public function onTagSet(TagSetEvent $event) { + $this->test_text(Tag::implode($event->tags), new SCoreException("Tags contain banned terms")); + } + + public function onSetupBuilding(SetupBuildingEvent $event) { + $sb = new SetupBlock("Banned Phrases"); + $sb->add_label("One per line, lines that start with slashes are treated as regex<br/>"); + $sb->add_longtext_option("banned_words"); + $event->panel->add_block($sb); + } + + private function test_text($comment, $ex) { global $config; + $banned = $config->get_string("banned_words"); - $comment = strtolower($event->comment); + $comment = strtolower($comment); foreach(explode("\n", $banned) as $word) { $word = trim(strtolower($word)); @@ -67,25 +87,18 @@ xanax else if($word[0] == '/') { // lines that start with slash are regex if(preg_match($word, $comment)) { - throw new CommentPostingException("Comment contains banned terms"); + throw $ex; } } else { // other words are literal if(strpos($comment, $word) !== false) { - throw new CommentPostingException("Comment contains banned terms"); + throw $ex; } } } } - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = new SetupBlock("Banned Phrases"); - $sb->add_label("One per line, lines that start with slashes are treated as regex<br/>"); - $sb->add_longtext_option("banned_words"); - $event->panel->add_block($sb); - } - public function get_priority() {return 30;} } ?> diff --git a/ext/et/main.php b/ext/et/main.php index 44245c6a..6b087d57 100644 --- a/ext/et/main.php +++ b/ext/et/main.php @@ -49,6 +49,12 @@ class ET extends Extension { $info['sys_disk'] = to_shorthand_int(disk_total_space("./") - disk_free_space("./")) . " / " . to_shorthand_int(disk_total_space("./")); $info['sys_server'] = $_SERVER["SERVER_SOFTWARE"]; + + $info['thumb_engine'] = $config->get_string("thumb_engine"); + $info['thumb_quality'] = $config->get_int('thumb_quality'); + $info['thumb_width'] = $config->get_int('thumb_width'); + $info['thumb_height'] = $config->get_int('thumb_height'); + $info['thumb_mem'] = $config->get_int("thumb_max_memory"); $info['stat_images'] = $database->get_one("SELECT COUNT(*) FROM images"); $info['stat_comments'] = $database->get_one("SELECT COUNT(*) FROM comments"); diff --git a/ext/et/theme.php b/ext/et/theme.php index 1c5b00ae..265b019a 100644 --- a/ext/et/theme.php +++ b/ext/et/theme.php @@ -32,6 +32,13 @@ Database: {$info['sys_db']} Server: {$info['sys_server']} Disk use: {$info['sys_disk']} +Thumbnail Generation: +Engine: {$info['thumb_engine']} +Memory: {$info['thumb_mem']} +Quality: {$info['thumb_quality']} +Width: {$info['thumb_width']} +Height: {$info['thumb_height']} + Shimmie stats: Images: {$info['stat_images']} Comments: {$info['stat_comments']} diff --git a/ext/featured/main.php b/ext/featured/main.php index dda66100..57c9f4f8 100644 --- a/ext/featured/main.php +++ b/ext/featured/main.php @@ -42,7 +42,7 @@ class Featured extends Extension { $image = Image::by_id($config->get_int("featured_id")); if(!is_null($image)) { $page->set_mode("data"); - $page->set_type("image/jpeg"); + $page->set_type($image->get_mime_type()); $page->set_data(file_get_contents($image->get_image_filename())); } } diff --git a/ext/handle_archive/main.php b/ext/handle_archive/main.php index 2fb2498b..5f0ea3fa 100644 --- a/ext/handle_archive/main.php +++ b/ext/handle_archive/main.php @@ -35,6 +35,7 @@ class ArchiveFileHandler extends Extension { exec($cmd); $this->add_dir($tmpdir); deltree($tmpdir); + $event->image_id = -2; // default -1 = upload wasn't handled } } diff --git a/ext/index/main.php b/ext/index/main.php index ce3dbbce..f5244d54 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -129,6 +129,8 @@ class PostListBuildingEvent extends Event { } class Index extends Extension { + var $val_id = 0; + public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_int("index_images", 24); @@ -206,10 +208,11 @@ class Index extends Extension { $event->add_querylet(new Querylet('width / height '.$cmp.' :width / :height', $args)); } else if(preg_match("/^(filesize|id)(<|>|<=|>=|=)(\d+[kmg]?b?)$/i", $event->term, $matches)) { + $this->val_id++; $col = $matches[1]; $cmp = $matches[2]; $val = parse_shorthand_int($matches[3]); - $event->add_querylet(new Querylet("images.$col $cmp :val", array("val"=>$val))); + $event->add_querylet(new Querylet("images.$col $cmp :val{$this->val_id}", array("val{$this->val_id}"=>$val))); } else if(preg_match("/^(hash|md5)=([0-9a-fA-F]*)$/i", $event->term, $matches)) { $hash = strtolower($matches[2]); diff --git a/ext/index/script.js b/ext/index/script.js index 459118fb..6c3078c0 100644 --- a/ext/index/script.js +++ b/ext/index/script.js @@ -1,13 +1,15 @@ $(function() { var blocked_tags = ($.cookie("ui-blocked-tags") || $.cookie("blocked-tags") || "").split(" "); - var themecheck = $(".thumb[data-tags~='tagme']").parent().attr('class'); + var themecheck = $(".thumb[data-tags]").parent().attr('class'); var needs_refresh = false; - for(i in blocked_tags) { + for(i=0; i<blocked_tags.length; i++) { var tag = blocked_tags[i]; if(tag) { - $(".thumb[data-tags~='"+tag+"']").hide(); if(themecheck == "thumbblock") { - $(".thumb[data-tags~='tagme']").parent().height(0); //required for lite theme + $(".thumb[data-tags~='"+tag+"']").parent().hide(); + $(".thumb[data-tags~='"+tag+"']").parent().height(0); //required for lite theme + }else{ + $(".thumb[data-tags~='"+tag+"']").hide(); } needs_refresh = true; } @@ -16,8 +18,13 @@ $(function() { // text-align: justify with element margins and doesn't recalculate // these margins when part of the line disappears... if(needs_refresh) { - $('#image-list').hide(); - $('#image-list').show(); + if(themecheck == "thumbblock") { + $('.blockbody').hide(); + $('.blockbody').show(); + }else{ + $('#image-list').hide(); + $('#image-list').show(); + } } }); diff --git a/ext/mass_tagger/script.js b/ext/mass_tagger/script.js index 77b7c2e7..91ae12f5 100644 --- a/ext/mass_tagger/script.js +++ b/ext/mass_tagger/script.js @@ -2,10 +2,14 @@ function find_thumb_link_containers () { var post_link = "a[href*='/post/view/']"; var has_thumb_img = ":has(img[src*='/thumb/'])"; - var list = $( post_link + has_thumb_img ).parent(); - return list; + if (list) { return list; } + + has_thumb_img = ":has(img[src*='_thumbs/'])"; + list = $( post_link + has_thumb_img ).parent(); + + return list; } function toggle_tag( button, id ) { diff --git a/ext/numeric_score/main.php b/ext/numeric_score/main.php index d8226f8b..5ce8640e 100644 --- a/ext/numeric_score/main.php +++ b/ext/numeric_score/main.php @@ -192,6 +192,8 @@ class NumericScore extends Extension { $image_ids = $database->get_col("SELECT image_id FROM numeric_score_votes WHERE user_id=?", array($user_id)); + if(count($image_ids) == 0) return; + $database->execute( "DELETE FROM numeric_score_votes WHERE user_id=? AND image_id IN (".implode(",", $image_ids).")", array($user_id)); diff --git a/ext/pm/main.php b/ext/pm/main.php index d33c975d..ad37b06a 100644 --- a/ext/pm/main.php +++ b/ext/pm/main.php @@ -28,7 +28,7 @@ class PM { $this->sent_date = $a["sent_date"]; $this->subject = $a["subject"]; $this->message = $a["message"]; - $this->is_read = undb_bool($a["is_read"]); + $this->is_read = bool_escape($a["is_read"]); } else { $this->id = -1; diff --git a/ext/random_image/main.php b/ext/random_image/main.php index 5a77bb25..ced59d67 100644 --- a/ext/random_image/main.php +++ b/ext/random_image/main.php @@ -41,7 +41,7 @@ class RandomImage extends Extension { if($action === "download") { if(!is_null($image)) { $page->set_mode("data"); - $page->set_type("image/jpeg"); + $page->set_type($image->get_mime_type()); $page->set_data(file_get_contents($image->get_image_filename())); } } diff --git a/ext/setup/main.php b/ext/setup/main.php index 195c0904..83f7c235 100644 --- a/ext/setup/main.php +++ b/ext/setup/main.php @@ -291,6 +291,10 @@ class Setup extends Extension { } } log_warning("setup", "Configuration updated"); + foreach(glob("data/cache/*.css") as $css_cache) { + unlink($css_cache); + } + log_warning("setup", "Cache cleared"); } public function onUserBlockBuilding(UserBlockBuildingEvent $event) { diff --git a/install.php b/install.php index a08ac4d0..b177fd5d 100644 --- a/install.php +++ b/install.php @@ -300,6 +300,14 @@ function create_tables() { // {{{ try { $db = new Database(); + if ( $db->count_tables() > 0 ) { + echo " + <p>Warning: The Database schema is not empty!</p> + <p>Please ensure that the database you are installing Shimmie with is empty before continuing.</p> + <p>Once you have emptied the database of any tables, please hit 'refresh' to continue.</p>"; + exit; + } + $db->create_table("aliases", " oldtag VARCHAR(128) NOT NULL PRIMARY KEY, newtag VARCHAR(128) NOT NULL, diff --git a/themes/danbooru/view.theme.php b/themes/danbooru/view.theme.php index 718e95cd..c5823dbd 100644 --- a/themes/danbooru/view.theme.php +++ b/themes/danbooru/view.theme.php @@ -42,8 +42,10 @@ class CustomViewImageTheme extends ViewImageTheme { if($image->rating == null || $image->rating == "u"){ $image->rating = "u"; } + if(class_exists("Ratings")) { $h_rating = Ratings::rating_to_human($image->rating); $html .= "<br>Rating: $h_rating"; + } } return $html;