diff --git a/core/imageboard/image.php b/core/imageboard/image.php index fbfcc1a2..f3fce5e7 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -191,7 +191,13 @@ class Image { return null; } fwrite($fp, json_encode($req)); - $data = fgets($fp, 1024); + $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); } diff --git a/core/sys_config.php b/core/sys_config.php index 296885a8..7f07e6db 100644 --- a/core/sys_config.php +++ b/core/sys_config.php @@ -41,6 +41,7 @@ _d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,set _d("EXTRA_EXTS", ""); // string optional extra extensions _d("BASE_URL", null); // string force a specific base URL (default is auto-detect) _d("MIN_PHP_VERSION", '7.0');// string minimum supported PHP version +_d("SLOW_PAGES", null); // float log pages which take more time than this _d("ENABLED_MODS", "imageboard"); /* diff --git a/core/user.php b/core/user.php index 05ea7466..49868789 100644 --- a/core/user.php +++ b/core/user.php @@ -105,11 +105,19 @@ class User { $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; } diff --git a/core/util.php b/core/util.php index 965b56a3..09b87dab 100644 --- a/core/util.php +++ b/core/util.php @@ -350,6 +350,18 @@ function get_debug_info(): string { 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 score_assert_handler($file, $line, $code, $desc = null) { $file = basename($file); print("Assertion failed at $file:$line: $code ($desc)"); @@ -389,7 +401,7 @@ function _sanitise_environment() { date_default_timezone_set(TIMEZONE); } - ini_set('zend.assertions', 1); // generate assertions + # ini_set('zend.assertions', 1); // generate assertions ini_set('assert.exception', 1); // throw exceptions when failed if(DEBUG) { error_reporting(E_ALL); diff --git a/ext/admin/main.php b/ext/admin/main.php index c240ea7b..04da836c 100644 --- a/ext/admin/main.php +++ b/ext/admin/main.php @@ -130,16 +130,15 @@ class AdminPage extends Extension { $reason = @$_POST['reason']; assert(strlen($query) > 1); - log_warning("admin", "Mass deleting: $query"); - $count = 0; - foreach(Image::find_images(0, 1000000, Tag::explode($query)) as $image) { + $images = Image::find_images(0, 1000000, Tag::explode($query)); + $count = count($images); + log_warning("admin", "Mass-deleting $count images from $query", true); + foreach($images as $image) { if($reason && class_exists("ImageBan")) { send_event(new AddImageHashBanEvent($image->hash, $reason)); } send_event(new ImageDeletionEvent($image)); - $count++; } - log_debug("admin", "Deleted $count images", true); $page->set_mode("redirect"); $page->set_redirect(make_link("post/list")); diff --git a/ext/autocomplete/main.php b/ext/autocomplete/main.php index af6ad166..d3ed6900 100644 --- a/ext/autocomplete/main.php +++ b/ext/autocomplete/main.php @@ -14,10 +14,24 @@ class AutoComplete extends Extension { if($event->page_matches("api/internal/autocomplete")) { if(!isset($_GET["s"])) return; + $page->set_mode("data"); + $page->set_type("application/json"); + + $s = strtolower($_GET["s"]); + if( + $s == '' || + $s[0] == '_' || + $s[0] == '%' || + strlen($s) > 32 + ) { + $page->set_data("{}"); + return; + } + //$limit = 0; - $cache_key = "autocomplete-" . strtolower($_GET["s"]); + $cache_key = "autocomplete-$s"; $limitSQL = ""; - $SQLarr = array("search"=>$_GET["s"]."%"); + $SQLarr = array("search"=>"$s%"); if(isset($_GET["limit"]) && $_GET["limit"] !== 0){ $limitSQL = "LIMIT :limit"; $SQLarr['limit'] = $_GET["limit"]; @@ -37,8 +51,6 @@ class AutoComplete extends Extension { $database->cache->set($cache_key, $res, 600); } - $page->set_mode("data"); - $page->set_type("application/json"); $page->set_data(json_encode($res)); } diff --git a/ext/handle_video/main.php b/ext/handle_video/main.php index ec3ad58f..95e4a048 100644 --- a/ext/handle_video/main.php +++ b/ext/handle_video/main.php @@ -64,7 +64,7 @@ class VideoFileHandler extends DataHandlerExtension { $orig_size = $this->video_size($inname); $scaled_size = get_thumbnail_size($orig_size[0], $orig_size[1]); - $cmd = escapeshellcmd(Tag::implode([ + $cmd = escapeshellcmd(implode(" ", [ escapeshellarg($ffmpeg), "-y", "-i", escapeshellarg($inname), "-vf", "scale={$scaled_size[0]}:{$scaled_size[1]}", @@ -76,12 +76,13 @@ class VideoFileHandler extends DataHandlerExtension { exec($cmd, $output, $ret); - if ((int)$ret == (int)1) { + if ((int)$ret == (int)0) { $ok = true; + log_error('handle_video', "Generating thumbnail with command `$cmd`, returns $ret"); + } + else { + log_debug('handle_video', "Generating thumbnail with command `$cmd`, returns $ret"); } - - // error_log("Generating thumbnail with command `$cmd`, returns $ret"); - log_debug('handle_video', "Generating thumbnail with command `$cmd`, returns $ret"); return $ok; } @@ -89,7 +90,7 @@ class VideoFileHandler extends DataHandlerExtension { protected function video_size(string $filename) { global $config; $ffmpeg = $config->get_string("thumb_ffmpeg_path"); - $cmd = escapeshellcmd(Tag::implode([ + $cmd = escapeshellcmd(implode(" ", [ escapeshellarg($ffmpeg), "-y", "-i", escapeshellarg($filename), "-vstats" @@ -100,15 +101,17 @@ class VideoFileHandler extends DataHandlerExtension { $regex_sizes = "/Video: .* ([0-9]{1,4})x([0-9]{1,4})/"; if (preg_match($regex_sizes, $output, $regs)) { if (preg_match("/displaymatrix: rotation of (90|270).00 degrees/", $output)) { - return [$regs[2], $regs[1]]; + $size = [$regs[2], $regs[1]]; } else { - return [$regs[1], $regs[2]]; + $size = [$regs[1], $regs[2]]; } } else { - return [1, 1]; + $size = [1, 1]; } + log_debug('handle_video', "Getting video size with `$cmd`, returns $output -- $size[0], $size[1]"); + return $size; } /** diff --git a/ext/ipban/main.php b/ext/ipban/main.php index 59e53d70..bb95ff98 100644 --- a/ext/ipban/main.php +++ b/ext/ipban/main.php @@ -43,7 +43,11 @@ class IPBan extends Extension { if($config->get_int("ext_ipban_version") < 8) { $this->install(); } - $config->set_default_string("ipban_message", "If you couldn't possibly be guilty of what you're banned for, the person we banned probably had a dynamic IP address and so do you. See http://whatismyipaddress.com/dynamic-static for more information.\n"); + $config->set_default_string("ipban_message", +'

IP $IP has been banned until $DATE by $ADMIN because of $REASON +

If you couldn\'t possibly be guilty of what you\'re banned for, the person we banned probably had a dynamic IP address and so do you. +

See http://whatismyipaddress.com/dynamic-static for more information. +

$CONTACT'); $this->check_ip_ban(); } @@ -84,7 +88,7 @@ class IPBan extends Extension { public function onSetupBuilding(SetupBuildingEvent $event) { $sb = new SetupBlock("IP Ban"); - $sb->add_longtext_option("ipban_message", 'Message to show to banned users:'); + $sb->add_longtext_option("ipban_message", 'Message to show to banned users:
(with $IP, $DATE, $ADMIN, $REASON, and $CONTACT)'); $event->panel->add_block($sb); } @@ -226,14 +230,20 @@ class IPBan extends Extension { $admin = User::by_id($row[$prefix.'banner_id']); $date = date("Y-m-d", $row[$prefix.'end_timestamp']); $msg = $config->get_string("ipban_message"); - header("HTTP/1.0 403 Forbidden"); - print "IP $ip has been banned until $date by {$admin->name} because of $reason\n"; - print "

$msg"; - + $msg = str_replace('$IP', $ip, $msg); + $msg = str_replace('$DATE', $date, $msg); + $msg = str_replace('$ADMIN', $admin->name, $msg); + $msg = str_replace('$REASON', $reason, $msg); $contact_link = contact_link(); if(!empty($contact_link)) { - print "

Contact the staff (be sure to include this message)"; + $msg = str_replace('$CONTACT', "Contact the staff (be sure to include this message)", $msg); } + else { + $msg = str_replace('$CONTACT', "", $msg); + } + header("HTTP/1.0 403 Forbidden"); + print "$msg"; + exit; } } diff --git a/ext/rss_images/main.php b/ext/rss_images/main.php index 9fd6c072..13e49a79 100644 --- a/ext/rss_images/main.php +++ b/ext/rss_images/main.php @@ -91,13 +91,13 @@ class RSS_Images extends Extension { $link = make_http(make_link("post/view/{$image->id}")); $tags = html_escape($image->get_tag_list()); - $owner = $image->get_owner(); $thumb_url = $image->get_thumb_link(); $image_url = $image->get_image_link(); $posted = date(DATE_RSS, strtotime($image->posted)); $content = html_escape( + "

" . "

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

" . - "

Uploaded by " . html_escape($owner->name) . "

" + "
" ); $data = " diff --git a/ext/rule34/script.js b/ext/rule34/script.js index b8aef7cf..c80bddf1 100644 --- a/ext/rule34/script.js +++ b/ext/rule34/script.js @@ -1,16 +1,25 @@ $(function() { if(Cookies.get("ui-tnc-agreed") !== "true") { - $("BODY").html(""+ - "
"+ + $("BODY").addClass("censored"); + $("BODY").append("
"); + $("BODY").append(""+ + "
"+ "

For legal reasons, we need to point out that:"+ "

A) this site contains material not suitable for minors"+ "
B) cookies may be used"+ - "

Click here if you're an adult, and you're ok with that"+ + "

Click here if you're an adult, and you're ok with that"+ "

"+ ""); } }); +function tnc_agree() { + Cookies.set("ui-tnc-agreed", "true", {path: '/', expires: 365}); + $("BODY").removeClass("censored"); + $(".tnc_bg").hide(); + $(".tnc").hide(); +} + function image_hash_ban(id) { var reason = prompt("WHY?", "DNP"); if(reason) { diff --git a/ext/rule34/style.css b/ext/rule34/style.css new file mode 100644 index 00000000..b4687560 --- /dev/null +++ b/ext/rule34/style.css @@ -0,0 +1,35 @@ +BODY.censored #header, +BODY.censored NAV, +BODY.censored ARTICLE, +BODY.censored FOOTER { + filter: blur(10px); +} +.tnc_bg { + position: fixed; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + background: #ACE4A3; + opacity: 0.75; + z-index: 999999999999999999999; +} +.tnc { + position: fixed; + top: 20%; + left: 20%; + right: 20%; + text-align: center; + font-size: 2em; + background: #ACE4A3; + border: 1px solid #7EB977; + z-index: 9999999999999999999999; +} +@media (max-width: 1024px) { + .tnc { + top: 5%; + left: 5%; + right: 5%; + font-size: 3vw; + } +} diff --git a/ext/statsd/main.php b/ext/statsd/main.php index 01cbb757..174daf71 100644 --- a/ext/statsd/main.php +++ b/ext/statsd/main.php @@ -66,19 +66,19 @@ class StatsDInterface extends Extension { } public function onUserCreation(UserCreationEvent $event) { - StatsDInterface::$stats["shimmie.events.user_creations"] = "1|c"; + StatsDInterface::$stats["shimmie_events.user_creations"] = "1|c"; } public function onDataUpload(DataUploadEvent $event) { - StatsDInterface::$stats["shimmie.events.uploads"] = "1|c"; + StatsDInterface::$stats["shimmie_events.uploads"] = "1|c"; } public function onCommentPosting(CommentPostingEvent $event) { - StatsDInterface::$stats["shimmie.events.comments"] = "1|c"; + StatsDInterface::$stats["shimmie_events.comments"] = "1|c"; } public function onImageInfoSet(ImageInfoSetEvent $event) { - StatsDInterface::$stats["shimmie.events.info-sets"] = "1|c"; + StatsDInterface::$stats["shimmie_events.info-sets"] = "1|c"; } /** diff --git a/ext/tag_list/main.php b/ext/tag_list/main.php index 1be00b33..c736d6ed 100644 --- a/ext/tag_list/main.php +++ b/ext/tag_list/main.php @@ -497,6 +497,8 @@ class TagList extends Extension { private function add_refine_block(Page $page, array $search) { global $database, $config; + if(count($search) > 5) return; + $wild_tags = $search; $str_search = Tag::implode($search); $related_tags = $database->cache->get("related_tags:$str_search"); @@ -509,7 +511,7 @@ class TagList extends Extension { foreach($wild_tags as $tag) { $tag = str_replace("*", "%", $tag); $tag = str_replace("?", "_", $tag); - $tag_ids = $database->get_col("SELECT id FROM tags WHERE tag LIKE :tag", array("tag"=>$tag)); + $tag_ids = $database->get_col("SELECT id FROM tags WHERE tag LIKE :tag AND count < 25000", array("tag"=>$tag)); // $search_tags = array_merge($search_tags, // $database->get_col("SELECT tag FROM tags WHERE tag LIKE :tag", array("tag"=>$tag))); $tag_id_array = array_merge($tag_id_array, $tag_ids); @@ -518,6 +520,8 @@ class TagList extends Extension { } $tag_id_list = join(', ', $tag_id_array); + if(count($tag_id_array) > 5) return; + if($tags_ok) { $query = " SELECT t2.tag AS tag, COUNT(it2.image_id) AS calc_count diff --git a/ext/upload/main.php b/ext/upload/main.php index 5ac90ac3..64e6ae91 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -82,18 +82,6 @@ class Upload extends Extension { } } - public function onPostListBuilding(PostListBuildingEvent $event) { - global $user, $page; - if($user->can("create_image")) { - if($this->is_full) { - $this->theme->display_full($page); - } - else { - $this->theme->display_block($page); - } - } - } - public function onSetupBuilding(SetupBuildingEvent $event) { $tes = array(); $tes["Disabled"] = "none"; @@ -130,6 +118,15 @@ class Upload extends Extension { 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($event->page_matches("upload/replace")) { // check if the user is an administrator and can upload files. if(!$user->can("replace_image")) { diff --git a/ext/upload/theme.php b/ext/upload/theme.php index 149c2624..ae8dd540 100644 --- a/ext/upload/theme.php +++ b/ext/upload/theme.php @@ -19,9 +19,9 @@ class UploadTheme extends Themelet { $html = " ".make_form(make_link("upload"), "POST", $multipart=True, 'file_upload')." + + $upload_list - -
Common Tags
Common Source
Tags
Source
diff --git a/ext/user/main.php b/ext/user/main.php index cf75c5cc..b998469c 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -240,7 +240,9 @@ class UserPage extends Extension { $this->theme->display_ip_list( $page, $this->count_upload_ips($event->display_user), - $this->count_comment_ips($event->display_user)); + $this->count_comment_ips($event->display_user), + $this->count_log_ips($event->display_user) + ); } } @@ -344,7 +346,6 @@ class UserPage extends Extension { if(!is_null($duser)) { $user = $duser; $this->set_login_cookie($duser->name, $pass); - log_info("user", "{$user->class->name} logged in"); $page->set_mode("redirect"); // Try returning to previous page @@ -358,7 +359,6 @@ class UserPage extends Extension { } } else { - log_warning("user", "Failed to log in as ".html_escape($name)); $this->theme->display_error(401, "Error", "No user with those details was found"); } } @@ -587,6 +587,21 @@ class UserPage extends Extension { return $rows; } + private function count_log_ips(User $duser): array { + if(!class_exists('LogDatabase')) return array(); + global $database; + $rows = $database->get_pairs(" + SELECT + address, + COUNT(id) AS count, + MAX(date_sent) AS most_recent + FROM score_log + WHERE username=:username + GROUP BY address + ORDER BY most_recent DESC", array("username"=>$duser->name)); + return $rows; + } + private function delete_user(Page $page, bool $with_images=false, bool $with_comments=false) { global $user, $config, $database; diff --git a/ext/user/theme.php b/ext/user/theme.php index b261ec08..d2f55b11 100644 --- a/ext/user/theme.php +++ b/ext/user/theme.php @@ -168,7 +168,7 @@ class UserPageTheme extends Themelet { $page->add_block(new Block("Login", $html, "left", 90)); } - public function display_ip_list(Page $page, array $uploads, array $comments) { + public function display_ip_list(Page $page, array $uploads, array $comments, array $events) { $html = ""; $html .= ""; - $html .= "
Uploaded from: "; $n = 0; @@ -190,8 +190,18 @@ class UserPageTheme extends Themelet { } } + $html .= "Logged Events:"; + $n = 0; + foreach($events as $ip => $count) { + $html .= '
'.$ip.' ('.$count.')'; + if(++$n >= 20) { + $html .= "
..."; + break; + } + } + $html .= "
(Most recent at top)
"; + $html .= "(Most recent at top)"; $page->add_block(new Block("IPs", $html, "main", 70)); } diff --git a/index.php b/index.php index e748c06b..7c9ee6b9 100644 --- a/index.php +++ b/index.php @@ -107,4 +107,5 @@ catch(Exception $e) { _fatal_error($e); $_shm_ctx->log_ender(); } +log_slow();