From 6a4031dfd59bbd04ca01dd4fc2c57138afa6ca41 Mon Sep 17 00:00:00 2001 From: Diftraku Date: Tue, 3 Dec 2013 00:45:07 +0200 Subject: [PATCH 01/32] Bumping Ouroros API to v0.2: now with XML support and post creation! --- ext/ouroboros_api/main.php | 546 +++++++++++++++++++++++++++++++------ 1 file changed, 470 insertions(+), 76 deletions(-) diff --git a/ext/ouroboros_api/main.php b/ext/ouroboros_api/main.php index a2413e42..4ff9553c 100644 --- a/ext/ouroboros_api/main.php +++ b/ext/ouroboros_api/main.php @@ -3,6 +3,7 @@ * Name: Ouroboros API * Author: Diftraku * Description: Ouroboros-like API for Shimmie + * Version: 0.2 * Documentation: * Currently working features * - *
  • user=Username, eg + *
  • user=Username & poster=Username, eg *
      *
    • user=Shish -- find all of Shish's posts + *
    • poster=Shish -- same as above *
    - *
  • hash=md5sum, eg + *
  • user_id=userID & poster_id=userID, eg + *
      + *
    • user_id=2 -- find all posts by user id 2 + *
    • poster_id=2 -- same as above + *
    + *
  • hash=md5sum & md5=md5sum, eg *
      *
    • hash=bf5b59173f16b6937a4021713dbfaa72 -- find the "Taiga want up!" image + *
    • md5=bf5b59173f16b6937a4021713dbfaa72 -- same as above *
    - *
  • filetype=type, eg + *
  • filetype=type & ext=type, eg *
      *
    • filetype=png -- find all PNG images + *
    • ext=png -- same as above *
    - *
  • filename=blah, eg + *
  • filename=blah & name=blah, eg *
      *
    • filename=kitten -- find all images with "kitten" in the original filename + *
    • name=kitten -- same as above *
    *
  • posted (=, <, >, <=, >=) date, eg *
      *
    • posted>=2009-12-25 posted<=2010-01-01 -- find images posted between christmas and new year *
    + *
  • tags (=, <, >, <=, >=) count, eg + *
      + *
    • tags=1 -- search for images with only 1 tag + *
    • tags>=10 -- search for images with 10 or more tags + *
    • tags<25 -- search for images with less than 25 tags + *
    + *
  • source=url, eg + *
      + *
    • source=http://example.com -- find all images with "http://example.com" in the source + *
    * *

    Search items can be combined to search for images which match both, * or you can stick "-" in front of an item to search for things that don't * match it. + *

    Metatags can be followed by ":" rather than "=" if you prefer. + *
    I.E: "posted:2014-01-01", "id:>=500" etc. *

    Some search methods provided by extensions: *

      - *
    • Danbooru API - *
        - *
      • md5:[hash] -- same as "hash=", but the API calls it by a different name - *
      *
    • Numeric Score *
        *
      • score (=, <, >, <=, >=) number -- seach by score @@ -81,11 +98,14 @@ *
      • Favorites *
          *
        • favorites (=, <, >, <=, >=) number -- search for images favourited a certain number of times - *
        • favourited_by=Username -- search for a user's choices + *
        • favourited_by=Username -- search for a user's choices by username + *
        • favorited_by_userno=UserID -- search for a user's choice by userID *
        *
      • Notes *
          *
        • notes (=, <, >, <=, >=) number -- search by the number of notes an image has + *
        • notes_by=Username -- search for a notes created by username + *
        • notes_by_userno=UserID -- search for a notes created by userID *
        *
      */ @@ -240,45 +260,45 @@ class Index extends Extension { public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); // check for tags first as tag based searches are more common. - if(preg_match("/tags(<|>|<=|>=|=)(\d+)/", $event->term, $matches)) { - $cmp = $matches[1]; + if(preg_match("/^tags([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; $tags = $matches[2]; $event->add_querylet(new Querylet('images.id IN (SELECT DISTINCT image_id FROM image_tags GROUP BY image_id HAVING count(image_id) '.$cmp.' '.$tags.')')); } - else if(preg_match("/^ratio(<|>|<=|>=|=)(\d+):(\d+)$/", $event->term, $matches)) { - $cmp = $matches[1]; + else if(preg_match("/^ratio([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+):(\d+)$/", $event->term, $matches)) { + $cmp = preg_replace('/^:/', '=', $matches[1]); $args = array("width{$this->stpen}"=>int_escape($matches[2]), "height{$this->stpen}"=>int_escape($matches[3])); $event->add_querylet(new Querylet("width / height $cmp :width{$this->stpen} / :height{$this->stpen}", $args)); } - else if(preg_match("/^(filesize|id)(<|>|<=|>=|=)(\d+[kmg]?b?)$/i", $event->term, $matches)) { + else if(preg_match("/^(filesize|id)([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+[kmg]?b?)$/i", $event->term, $matches)) { $col = $matches[1]; - $cmp = $matches[2]; + $cmp = ltrim($matches[2], ":") ?: "="; $val = parse_shorthand_int($matches[3]); $event->add_querylet(new Querylet("images.$col $cmp :val{$this->stpen}", array("val{$this->stpen}"=>$val))); } - else if(preg_match("/^(hash|md5)=([0-9a-fA-F]*)$/i", $event->term, $matches)) { + else if(preg_match("/^(hash|md5)[=|:]([0-9a-fA-F]*)$/i", $event->term, $matches)) { $hash = strtolower($matches[2]); $event->add_querylet(new Querylet('images.hash = :hash', array("hash" => $hash))); } - else if(preg_match("/^(filetype|ext)=([a-zA-Z0-9]*)$/i", $event->term, $matches)) { + else if(preg_match("/^(filetype|ext)[=|:]([a-zA-Z0-9]*)$/i", $event->term, $matches)) { $ext = strtolower($matches[2]); $event->add_querylet(new Querylet('images.ext = :ext', array("ext" => $ext))); } - else if(preg_match("/^(filename|name)=([a-zA-Z0-9]*)$/i", $event->term, $matches)) { + else if(preg_match("/^(filename|name)[=|:]([a-zA-Z0-9]*)$/i", $event->term, $matches)) { $filename = strtolower($matches[2]); $event->add_querylet(new Querylet("images.filename LIKE :filename{$this->stpen}", array("filename{$this->stpen}"=>"%$filename%"))); } - else if(preg_match("/^(source)=([a-zA-Z0-9]*)$/i", $event->term, $matches)) { - $filename = strtolower($matches[2]); - $event->add_querylet(new Querylet('images.source LIKE :src', array("src"=>"%$filename%"))); + else if(preg_match("/^(source)[=|:]([a-zA-Z0-9]*)$/i", $event->term, $matches)) { + $source = strtolower($matches[2]); + $event->add_querylet(new Querylet('images.source LIKE :src', array("src"=>"%$source%"))); } - else if(preg_match("/^posted(<|>|<=|>=|=)([0-9-]*)$/", $event->term, $matches)) { - $cmp = $matches[1]; + else if(preg_match("/^posted([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])([0-9-]*)$/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; $val = $matches[2]; $event->add_querylet(new Querylet("images.posted $cmp :posted{$this->stpen}", array("posted{$this->stpen}"=>$val))); } - else if(preg_match("/^size(<|>|<=|>=|=)(\d+)x(\d+)$/", $event->term, $matches)) { - $cmp = $matches[1]; + else if(preg_match("/^size([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)x(\d+)$/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; $args = array("width{$this->stpen}"=>int_escape($matches[2]), "height{$this->stpen}"=>int_escape($matches[3])); $event->add_querylet(new Querylet("width $cmp :width{$this->stpen} AND height $cmp :height{$this->stpen}", $args)); } diff --git a/ext/notes/main.php b/ext/notes/main.php index 5bc09ef6..f29a22e9 100644 --- a/ext/notes/main.php +++ b/ext/notes/main.php @@ -210,16 +210,16 @@ class Notes extends Extension { */ public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); - if(preg_match("/note=(.*)/i", $event->term, $matches)) { + if(preg_match("/^note[=|:](.*)$/i", $event->term, $matches)) { $notes = int_escape($matches[1]); $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE note = $notes)")); } - else if(preg_match("/notes(<|>|<=|>=|=)(\d+)/", $event->term, $matches)) { - $cmp = $matches[1]; + else if(preg_match("/^notes([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)%/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; $notes = $matches[2]; $event->add_querylet(new Querylet("images.id IN (SELECT id FROM images WHERE notes $cmp $notes)")); } - else if(preg_match("/notes_by=(.*)/i", $event->term, $matches)) { + else if(preg_match("/^notes_by[=|:](.*)$/i", $event->term, $matches)) { global $database; $user = User::by_name($matches[1]); if(!is_null($user)) { @@ -231,7 +231,7 @@ class Notes extends Extension { $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE user_id = $user_id)")); } - else if(preg_match("/notes_by_userno=([0-9]+)/i", $event->term, $matches)) { + else if(preg_match("/^notes_by_userno[=|:](\d+)$/i", $event->term, $matches)) { $user_id = int_escape($matches[1]); $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM notes WHERE user_id = $user_id)")); } diff --git a/ext/rating/main.php b/ext/rating/main.php index be54cdb4..1b41b89f 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -116,7 +116,7 @@ class Ratings extends Extension { $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)) { + if(preg_match("/^rating[=|:](?:([sqeu]+)|(safe|questionable|explicit|unknown))$/D", strtolower($event->term), $matches)) { $ratings = $matches[1] ? $matches[1] : array($matches[2][0]); $ratings = array_intersect(str_split($ratings), str_split(Ratings::get_user_privs($user))); $set = "'" . join("', '", $ratings) . "'"; @@ -199,7 +199,7 @@ class Ratings extends Extension { private function no_rating_query($context) { foreach($context as $term) { - if(preg_match("/^rating=/", $term)) { + if(preg_match("/^rating[=|:]/", $term)) { return false; } } diff --git a/ext/user/main.php b/ext/user/main.php index 5a4058ca..67755004 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -309,7 +309,7 @@ class UserPage extends Extension { global $user; $matches = array(); - if(preg_match("/^(poster|user)=(.*)$/i", $event->term, $matches)) { + if(preg_match("/^(poster|user)[=|:](.*)$/i", $event->term, $matches)) { $duser = User::by_name($matches[2]); if(!is_null($duser)) { $user_id = $duser->id; @@ -319,11 +319,11 @@ class UserPage extends Extension { } $event->add_querylet(new Querylet("images.owner_id = $user_id")); } - else if(preg_match("/^(poster|user)_id=([0-9]+)$/i", $event->term, $matches)) { + else if(preg_match("/^(poster|user)_id[=|:]([0-9]+)$/i", $event->term, $matches)) { $user_id = int_escape($matches[2]); $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)) { + else if($user->can("view_ip") && preg_match("/^(poster|user)_ip[=|:]([0-9\.]+)$/i", $event->term, $matches)) { $user_ip = $matches[2]; // FIXME: ip_escape? $event->add_querylet(new Querylet("images.owner_ip = '$user_ip'")); } From 14899e79ad1ec00acb556607ca0928b517045911 Mon Sep 17 00:00:00 2001 From: Daku Date: Thu, 2 Jan 2014 14:10:08 +0000 Subject: [PATCH 19/32] added height & width metatags --- ext/index/main.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ext/index/main.php b/ext/index/main.php index 4acc663c..20820fe2 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -21,6 +21,16 @@ *
    • size>=500x500 -- no small images *
    • size<1000x1000 -- no large images *
    + *
  • width (=, <, >, <=, >=) width, eg + *
      + *
    • width=1024 -- find images with 1024 width + *
    • width>2000 -- find images bigger than 2000 width + *
    + *
  • height (=, <, >, <=, >=) height, eg + *
      + *
    • height=768 -- find images with 768 height + *
    • height>1000 -- find images bigger than 1000 height + *
    *
  • ratio (=, <, >, <=, >=) width : height, eg *
      *
    • ratio=4:3, ratio=16:9 -- standard wallpaper @@ -302,6 +312,14 @@ class Index extends Extension { $args = array("width{$this->stpen}"=>int_escape($matches[2]), "height{$this->stpen}"=>int_escape($matches[3])); $event->add_querylet(new Querylet("width $cmp :width{$this->stpen} AND height $cmp :height{$this->stpen}", $args)); } + else if(preg_match("/^width([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; + $event->add_querylet(new Querylet("width $cmp :width{$this->stpen}", array("width{$this->stpen}"=>int_escape($matches[2])))); + } + else if(preg_match("/^height([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; + $event->add_querylet(new Querylet("height $cmp :height{$this->stpen}",array("height{$this->stpen}"=>int_escape($matches[2])))); + } $this->stpen++; } From 9f06a5c5656049c923d5c6361c0217d010729b86 Mon Sep 17 00:00:00 2001 From: Daku Date: Fri, 3 Jan 2014 00:41:28 +0000 Subject: [PATCH 20/32] fix search not working properly for aliases to multiple tags fix issue 359 --- core/imageboard.pack.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php index c9a2ce4a..eb34035e 100644 --- a/core/imageboard.pack.php +++ b/core/imageboard.pack.php @@ -663,6 +663,8 @@ class Image { } } + $terms = Tag::resolve_aliases($terms); + // parse the words that are searched for into // various types of querylet foreach($terms as $term) { @@ -675,8 +677,6 @@ class Image { continue; } - $term = Tag::resolve_alias($term); - $stpe = new SearchTermParseEvent($term, $terms); send_event($stpe); if($stpe->is_querylet_set()) { @@ -824,6 +824,8 @@ class Image { } } + $terms = Tag::resolve_aliases($terms); + reset($terms); // rewind to first element in array. // turn each term into a specific type of querylet @@ -833,8 +835,6 @@ class Image { $negative = true; $term = substr($term, 1); } - - $term = Tag::resolve_alias($term); $stpe = new SearchTermParseEvent($term, $terms); send_event($stpe); @@ -1082,11 +1082,22 @@ class Tag { assert(is_array($tags)); $new = array(); - foreach($tags as $tag) { - $new_set = explode(' ', Tag::resolve_alias($tag)); - foreach($new_set as $new_one) { - $new[] = $new_one; + + $i = 0; + $tag_count = count($tags); + while($i<$tag_count) { + $aliases = explode(' ', Tag::resolve_alias($tags[$i])); + foreach($aliases as $alias){ + if(!in_array($alias, $new)){ + if($tags[$i] == $alias){ + $new[] = $alias; + }elseif(!in_array($alias, $tags)){ + $tags[] = $alias; + $tag_count++; + } + } } + $i++; } $new = array_iunique($new); // remove any duplicate tags From 9cae856df7a408ec874a7b270eb0e03e6678a774 Mon Sep 17 00:00:00 2001 From: Daku Date: Fri, 3 Jan 2014 00:58:53 +0000 Subject: [PATCH 21/32] use the Content-Disposition header for filename & Content-Type for extension if either doesn't exist, it will fallback to using pathinfo --- core/util.inc.php | 64 +++++++++++++++++++++++++++++++++++++++++---- ext/upload/main.php | 14 +++++----- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/core/util.inc.php b/core/util.inc.php index b1331a4a..b63c0d43 100644 --- a/core/util.inc.php +++ b/core/util.inc.php @@ -801,17 +801,24 @@ function transload($url, $mfile) { $ch = curl_init($url); $fp = fopen($mfile, "w"); - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_setopt($ch, CURLOPT_HEADER, 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); - 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); + curl_close($ch); + fwrite($fp, $body); fclose($fp); - return true; + return $headers; } if($config->get_string("transload_engine") === "wget") { @@ -839,12 +846,59 @@ function transload($url, $mfile) { fwrite($fp, $data); fclose($fp); - return true; + $headers = http_parse_headers(implode("\n", $http_response_header)); + + return $headers; } return false; } +if (!function_exists('http_parse_headers')) { #http://www.php.net/manual/en/function.http-parse-headers.php#112917 + function http_parse_headers ($raw_headers){ + $headers = array(); // $headers = []; + + 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; + } +} + +function getExtension ($mime_type){ + if(empty($mime_type)){ + return false; + } + + $extensions = array( + 'image/jpeg' => 'jpg', + 'image/gif' => 'gif', + 'image/png' => 'png', + 'application/x-shockwave-flash' => 'swf', + 'image/x-icon' => 'ico', + 'image/svg+xml' => 'svg', + 'audio/mpeg' => 'mp3', + 'video/x-flv' => 'flv', + 'audio/mp4' => 'mp4', + 'video/mp4' => 'mp4', + 'audio/webm' => 'webm', + 'video/webm' => 'webm' + ); + + return $extensions[$mime_type]; +} $_included = array(); /** diff --git a/ext/upload/main.php b/ext/upload/main.php index 2e7a073e..b92fc479 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -329,9 +329,12 @@ class Upload extends Extension { } $tmp_filename = tempnam(ini_get('upload_tmp_dir'), "shimmie_transload"); - $filename = basename($url); - if(!transload($url, $tmp_filename)) { + $headers = transload($url, $tmp_filename); + $h_filename = (isset($headers['Content-Disposition']) ? preg_replace('/^.*filename="([^ ]+)"/i', '$1', $headers['Content-Disposition']) : 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; @@ -341,12 +344,11 @@ class Upload extends Extension { $this->theme->display_upload_error($page, "Error with ".html_escape($filename), "No data found -- perhaps the site has hotlink protection?"); $ok = false; - } - else { + }else{ global $user; $pathinfo = pathinfo($url); - $metadata['filename'] = $pathinfo['basename']; - $metadata['extension'] = $pathinfo['extension']; + $metadata['filename'] = $filename; + $metadata['extension'] = getExtension($headers['Content-Type']) ?: $pathinfo['extension']; $metadata['tags'] = $tags; $metadata['source'] = $source; From 2c2f27ca640985d49e3eb5134b53516687e91d80 Mon Sep 17 00:00:00 2001 From: Daku Date: Fri, 3 Jan 2014 01:24:55 +0000 Subject: [PATCH 22/32] add order metatag not too happy with how this works...but it does work --- core/imageboard.pack.php | 48 ++++++++++++++++++++++------------------ ext/index/main.php | 13 +++++++++++ 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php index eb34035e..ac4d0ea5 100644 --- a/core/imageboard.pack.php +++ b/core/imageboard.pack.php @@ -26,6 +26,7 @@ $tag_n = 0; // temp hack $_flexihash = null; $_fh_last_opts = null; +$order_sql = null; // this feels ugly require_once "lib/flexihash.php"; @@ -114,7 +115,7 @@ class Image { assert(is_numeric($start)); assert(is_numeric($limit)); assert(is_array($tags)); - global $database, $user; + global $database, $user, $order_sql; $images = array(); @@ -128,13 +129,15 @@ class Image { } $querylet = Image::build_search_querylet($tags); - $querylet->append(new Querylet("ORDER BY images.id DESC LIMIT :limit OFFSET :offset", array("limit"=>$limit, "offset"=>$start))); + $querylet->append(new Querylet($order_sql ?: " ORDER BY images.id DESC")); + $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); while($row = $result->fetch()) { $images[] = new Image($row); } + $order_sql = null; return $images; } @@ -663,8 +666,6 @@ class Image { } } - $terms = Tag::resolve_aliases($terms); - // parse the words that are searched for into // various types of querylet foreach($terms as $term) { @@ -677,6 +678,15 @@ class Image { continue; } + $aliases = explode(" ", Tag::resolve_alias($term)); + $found = array_search($term, $aliases); + if($found !== false){ + unset($aliases[$found]); + }else{ + $term = array_shift($aliases); + } + foreach($aliases as $alias) array_push($terms, $alias); + $stpe = new SearchTermParseEvent($term, $terms); send_event($stpe); if($stpe->is_querylet_set()) { @@ -824,8 +834,6 @@ class Image { } } - $terms = Tag::resolve_aliases($terms); - reset($terms); // rewind to first element in array. // turn each term into a specific type of querylet @@ -835,6 +843,15 @@ class Image { $negative = true; $term = substr($term, 1); } + + $aliases = explode(" ", Tag::resolve_alias($term)); + $found = array_search($term, $aliases); + if($found !== false){ + unset($aliases[$found]); + }else{ + $term = array_shift($aliases); + } + foreach($aliases as $alias) array_push($terms, $alias); $stpe = new SearchTermParseEvent($term, $terms); send_event($stpe); @@ -1082,22 +1099,11 @@ class Tag { assert(is_array($tags)); $new = array(); - - $i = 0; - $tag_count = count($tags); - while($i<$tag_count) { - $aliases = explode(' ', Tag::resolve_alias($tags[$i])); - foreach($aliases as $alias){ - if(!in_array($alias, $new)){ - if($tags[$i] == $alias){ - $new[] = $alias; - }elseif(!in_array($alias, $tags)){ - $tags[] = $alias; - $tag_count++; - } - } + foreach($tags as $tag) { + $new_set = explode(' ', Tag::resolve_alias($tag)); + foreach($new_set as $new_one) { + $new[] = $new_one; } - $i++; } $new = array_iunique($new); // remove any duplicate tags diff --git a/ext/index/main.php b/ext/index/main.php index 20820fe2..b2df34f0 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -87,6 +87,11 @@ *
        *
      • source=http://example.com -- find all images with "http://example.com" in the source *
      + *
    • order (id, width, height, filesize, filename)_(ASC, DESC), eg + *
        + *
      • order=width -- find all images sorted from highest > lowest width + *
      • order=filesize_asc -- find all images sorted from lowest > highest filesize + *
      *
    *

    Search items can be combined to search for images which match both, * or you can stick "-" in front of an item to search for things that don't @@ -320,6 +325,14 @@ class Index extends Extension { $cmp = ltrim($matches[1], ":") ?: "="; $event->add_querylet(new Querylet("height $cmp :height{$this->stpen}",array("height{$this->stpen}"=>int_escape($matches[2])))); } + else if(preg_match("/^order[=|:](id|width|height|filesize|filename)[_]?(desc|asc)?$/i", $event->term, $matches)){ + global $order_sql; + $order = strtolower($matches[1]); + $sort = isset($matches[2]) ? strtoupper($matches[2]) : (preg_match("/^(id|filename)$/", $matches[1]) ? "ASC" : "DESC"); + // $event->add_querylet(new Querylet("ORDER BY images.:order :sort", array("order" => $order, "sort" => $sort))); + $event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag + $order_sql = " ORDER BY images.$order $sort"; + } $this->stpen++; } From 152f5fbf26791c142eedc9bedb5d7ac0505b378d Mon Sep 17 00:00:00 2001 From: Daku Date: Fri, 3 Jan 2014 08:24:47 +0000 Subject: [PATCH 23/32] add config option for default order --- core/imageboard.pack.php | 4 ++-- ext/index/main.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php index ac4d0ea5..0bf145e9 100644 --- a/core/imageboard.pack.php +++ b/core/imageboard.pack.php @@ -115,7 +115,7 @@ class Image { assert(is_numeric($start)); assert(is_numeric($limit)); assert(is_array($tags)); - global $database, $user, $order_sql; + global $database, $user, $config, $order_sql; $images = array(); @@ -129,7 +129,7 @@ class Image { } $querylet = Image::build_search_querylet($tags); - $querylet->append(new Querylet($order_sql ?: " ORDER BY images.id DESC")); + $querylet->append(new Querylet(" ORDER BY images.".($order_sql ?: $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); diff --git a/ext/index/main.php b/ext/index/main.php index b2df34f0..1831ec68 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -176,6 +176,7 @@ class Index extends Extension { global $config; $config->set_default_int("index_images", 24); $config->set_default_bool("index_tips", true); + $config->set_default_string("index_order", "id DESC"); } public function onPageRequest(PageRequestEvent $event) { @@ -327,11 +328,10 @@ class Index extends Extension { } else if(preg_match("/^order[=|:](id|width|height|filesize|filename)[_]?(desc|asc)?$/i", $event->term, $matches)){ global $order_sql; - $order = strtolower($matches[1]); + $ord = strtolower($matches[1]); $sort = isset($matches[2]) ? strtoupper($matches[2]) : (preg_match("/^(id|filename)$/", $matches[1]) ? "ASC" : "DESC"); - // $event->add_querylet(new Querylet("ORDER BY images.:order :sort", array("order" => $order, "sort" => $sort))); + $order_sql = "$ord $sort"; $event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag - $order_sql = " ORDER BY images.$order $sort"; } $this->stpen++; From 7d49e21792297a79566241aa0f5e76a1b5734711 Mon Sep 17 00:00:00 2001 From: Daku Date: Sun, 5 Jan 2014 11:52:09 +0000 Subject: [PATCH 24/32] readability + moved stuff --- core/util.inc.php | 47 +++++++++++++++++++++++----------------------- ext/index/main.php | 5 +++-- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/core/util.inc.php b/core/util.inc.php index b63c0d43..09dbe7fe 100644 --- a/core/util.inc.php +++ b/core/util.inc.php @@ -556,6 +556,30 @@ function getMimeType($file, $ext="") { return 'application/octet-stream'; } + +function getExtension ($mime_type){ + if(empty($mime_type)){ + return false; + } + + $extensions = array( + 'image/jpeg' => 'jpg', + 'image/gif' => 'gif', + 'image/png' => 'png', + 'application/x-shockwave-flash' => 'swf', + 'image/x-icon' => 'ico', + 'image/svg+xml' => 'svg', + 'audio/mpeg' => 'mp3', + 'video/x-flv' => 'flv', + 'audio/mp4' => 'mp4', + 'video/mp4' => 'mp4', + 'audio/webm' => 'webm', + 'video/webm' => 'webm' + ); + + return $extensions[$mime_type]; +} + /** * @private */ @@ -877,29 +901,6 @@ if (!function_exists('http_parse_headers')) { #http://www.php.net/manual/en/func } } -function getExtension ($mime_type){ - if(empty($mime_type)){ - return false; - } - - $extensions = array( - 'image/jpeg' => 'jpg', - 'image/gif' => 'gif', - 'image/png' => 'png', - 'application/x-shockwave-flash' => 'swf', - 'image/x-icon' => 'ico', - 'image/svg+xml' => 'svg', - 'audio/mpeg' => 'mp3', - 'video/x-flv' => 'flv', - 'audio/mp4' => 'mp4', - 'video/mp4' => 'mp4', - 'audio/webm' => 'webm', - 'video/webm' => 'webm' - ); - - return $extensions[$mime_type]; -} - $_included = array(); /** * Get the active contents of a .php file diff --git a/ext/index/main.php b/ext/index/main.php index 1831ec68..45f71f02 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -87,7 +87,7 @@ *

      *
    • source=http://example.com -- find all images with "http://example.com" in the source *
    - *
  • order (id, width, height, filesize, filename)_(ASC, DESC), eg + *
  • order=(id, width, height, filesize, filename)_(ASC, DESC), eg *
      *
    • order=width -- find all images sorted from highest > lowest width *
    • order=filesize_asc -- find all images sorted from lowest > highest filesize @@ -329,7 +329,8 @@ class Index extends Extension { else if(preg_match("/^order[=|:](id|width|height|filesize|filename)[_]?(desc|asc)?$/i", $event->term, $matches)){ global $order_sql; $ord = strtolower($matches[1]); - $sort = isset($matches[2]) ? strtoupper($matches[2]) : (preg_match("/^(id|filename)$/", $matches[1]) ? "ASC" : "DESC"); + $default_order_for_column = preg_match("/^(id|filename)$/", $matches[1]) ? "ASC" : "DESC"; + $sort = isset($matches[2]) ? strtoupper($matches[2]) : $default_order_for_column; $order_sql = "$ord $sort"; $event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag } From 325da1111913ccbbe5824c2d1e5cd7b6a5937b8f Mon Sep 17 00:00:00 2001 From: Daku Date: Mon, 13 Jan 2014 09:13:56 +0000 Subject: [PATCH 25/32] artist/comment/numeric_score metatags now work using : also updated docs --- ext/artists/main.php | 2 +- ext/comment/main.php | 8 ++++---- ext/index/main.php | 12 ++++++++++++ ext/numeric_score/main.php | 12 ++++++------ 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/ext/artists/main.php b/ext/artists/main.php index d426d512..984b12af 100644 --- a/ext/artists/main.php +++ b/ext/artists/main.php @@ -45,7 +45,7 @@ class Artists extends Extension { public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); - if(preg_match("/^author=(.*)$/", $event->term, $matches)) { + if(preg_match("/^author[=|:](.*)$/", $event->term, $matches)) { $char = $matches[1]; $event->add_querylet(new Querylet("Author = :author_char", array("author_char"=>$char))); } diff --git a/ext/comment/main.php b/ext/comment/main.php index 48d4f013..1c472626 100644 --- a/ext/comment/main.php +++ b/ext/comment/main.php @@ -262,12 +262,12 @@ class CommentList extends Extension { public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); - if(preg_match("/comments(<|>|<=|>=|=)(\d+)/", $event->term, $matches)) { - $cmp = $matches[1]; + if(preg_match("/^comments([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; $comments = $matches[2]; $event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM comments GROUP BY image_id HAVING count(image_id) $cmp $comments)")); } - else if(preg_match("/commented_by=(.*)/i", $event->term, $matches)) { + else if(preg_match("/^commented_by[=|:](.*)$/i", $event->term, $matches)) { global $database; $user = User::by_name($matches[1]); if(!is_null($user)) { @@ -279,7 +279,7 @@ class CommentList extends Extension { $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM comments WHERE owner_id = $user_id)")); } - else if(preg_match("/commented_by_userid=([0-9]+)/i", $event->term, $matches)) { + else if(preg_match("/^commented_by_userno[=|:]([0-9]+)$/i", $event->term, $matches)) { $user_id = int_escape($matches[1]); $event->add_querylet(new Querylet("images.id IN (SELECT image_id FROM comments WHERE owner_id = $user_id)")); } diff --git a/ext/index/main.php b/ext/index/main.php index 45f71f02..bd4f3e30 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -105,6 +105,8 @@ *
    • score (=, <, >, <=, >=) number -- seach by score *
    • upvoted_by=Username -- search for a user's likes *
    • downvoted_by=Username -- search for a user's dislikes + *
    • upvoted_by_id=UserID -- search for a user's likes by user ID + *
    • downvoted_by_id=UserID -- search for a user's dislikes by user ID *
    *
  • Image Rating *
      @@ -122,6 +124,16 @@ *
    • notes_by=Username -- search for a notes created by username *
    • notes_by_userno=UserID -- search for a notes created by userID *
    + *
  • Artists + *
      + *
    • author=ArtistName -- search for images by artist + *
    + *
  • Image Comments + *
      + *
    • comments (=, <, >, <=, >=) number -- search for images by number of comments + *
    • commented_by=Username -- search for a user's comments by username + *
    • commented_by_userno=UserID -- search for a user's comments by userID + *
    * */ diff --git a/ext/numeric_score/main.php b/ext/numeric_score/main.php index 9cf21ab3..2da74577 100644 --- a/ext/numeric_score/main.php +++ b/ext/numeric_score/main.php @@ -217,12 +217,12 @@ class NumericScore extends Extension { public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); - if(preg_match("/^score(<|<=|=|>=|>)(-?\d+)$/", $event->term, $matches)) { - $cmp = $matches[1]; + if(preg_match("/^score([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(-?\d+)$/", $event->term, $matches)) { + $cmp = ltrim($matches[1], ":") ?: "="; $score = $matches[2]; $event->add_querylet(new Querylet("numeric_score $cmp $score")); } - if(preg_match("/^upvoted_by=(.*)$/", $event->term, $matches)) { + if(preg_match("/^upvoted_by[=|:](.*)$/", $event->term, $matches)) { $duser = User::by_name($matches[1]); if(is_null($duser)) { throw new SearchTermParseException( @@ -232,7 +232,7 @@ class NumericScore extends Extension { "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))); } - if(preg_match("/^downvoted_by=(.*)$/", $event->term, $matches)) { + if(preg_match("/^downvoted_by[=|:](.*)$/", $event->term, $matches)) { $duser = User::by_name($matches[1]); if(is_null($duser)) { throw new SearchTermParseException( @@ -242,13 +242,13 @@ class NumericScore extends Extension { "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))); } - if(preg_match("/^upvoted_by_id=(\d+)$/", $event->term, $matches)) { + if(preg_match("/^upvoted_by_id[=|:](\d+)$/", $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))); } - if(preg_match("/^downvoted_by_id=(\d+)$/", $event->term, $matches)) { + if(preg_match("/^downvoted_by_id[=|:](\d+)$/", $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)", From ae4da2b410234f425224369f98d06283551ef90a Mon Sep 17 00:00:00 2001 From: Daku Date: Mon, 13 Jan 2014 10:03:38 +0000 Subject: [PATCH 26/32] add option for getMimeType to return list of extensions --- core/util.inc.php | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/core/util.inc.php b/core/util.inc.php index 09dbe7fe..a4c5b244 100644 --- a/core/util.inc.php +++ b/core/util.inc.php @@ -509,14 +509,15 @@ function captcha_check() { * @param string &$file File path * @return string */ -function getMimeType($file, $ext="") { +function getMimeType($file, $ext="", $list=false) { // Static extension lookup $ext = strtolower($ext); 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', + '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', @@ -529,6 +530,8 @@ function getMimeType($file, $ext="") { 'mp4' => 'video/mp4', 'ogv' => 'video/ogg', 'webm' => 'video/webm' ); + if ($list == true){ return $exts; } + if (isset($exts[$ext])) { return $exts[$ext]; } $type = false; @@ -562,22 +565,9 @@ function getExtension ($mime_type){ return false; } - $extensions = array( - 'image/jpeg' => 'jpg', - 'image/gif' => 'gif', - 'image/png' => 'png', - 'application/x-shockwave-flash' => 'swf', - 'image/x-icon' => 'ico', - 'image/svg+xml' => 'svg', - 'audio/mpeg' => 'mp3', - 'video/x-flv' => 'flv', - 'audio/mp4' => 'mp4', - 'video/mp4' => 'mp4', - 'audio/webm' => 'webm', - 'video/webm' => 'webm' - ); - - return $extensions[$mime_type]; + $extensions = getMimeType(null, null, true); + $ext = array_search($mime_type, $extensions); + return ($ext ?: false); } /** From ce256f5bf4a7a883243d063a89c628ddc92c8e76 Mon Sep 17 00:00:00 2001 From: Daku Date: Tue, 14 Jan 2014 06:12:34 +0000 Subject: [PATCH 27/32] added pool & pool_by_name search metatags --- ext/index/main.php | 13 +++++++++---- ext/pools/main.php | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/ext/index/main.php b/ext/index/main.php index bd4f3e30..0aadaf2b 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -121,8 +121,8 @@ *
  • Notes *
      *
    • notes (=, <, >, <=, >=) number -- search by the number of notes an image has - *
    • notes_by=Username -- search for a notes created by username - *
    • notes_by_userno=UserID -- search for a notes created by userID + *
    • notes_by=Username -- search for images contains notes created by username + *
    • notes_by_userno=UserID -- search for images contains notes created by userID *
    *
  • Artists *
      @@ -131,8 +131,13 @@ *
    • Image Comments *
        *
      • comments (=, <, >, <=, >=) number -- search for images by number of comments - *
      • commented_by=Username -- search for a user's comments by username - *
      • commented_by_userno=UserID -- search for a user's comments by userID + *
      • commented_by=Username -- search for images contains user's comments by username + *
      • commented_by_userno=UserID -- search for images contains user's comments by userID + *
      + *
    • Pools + *
        + *
      • pool=PoolID -- search for images in a pool by PoolID + *
      • pool_by_name=PoolName -- search for images in a pool by PoolName. underscores are replaced with spaces *
      *
    */ diff --git a/ext/pools/main.php b/ext/pools/main.php index 008838d3..8431a653 100644 --- a/ext/pools/main.php +++ b/ext/pools/main.php @@ -293,6 +293,22 @@ class Pools extends Extension { } } + public function onSearchTermParse(SearchTermParseEvent $event) { + $matches = array(); + if(preg_match("/^pool[=|:]([0-9]+)$/", $event->term, $matches)) { + $poolID = $matches[1]; + $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[=|:](.*)$/", $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)")); + } + } + public function add_post_from_tag(/*str*/ $poolTag, /*int*/ $imageID){ $poolTag = str_replace("_", " ", $poolTag); //First check if pool tag is a title From 55ff224ac0bd6354ef21a37cf9175a836f92a389 Mon Sep 17 00:00:00 2001 From: Daku Date: Tue, 14 Jan 2014 06:27:12 +0000 Subject: [PATCH 28/32] added any/none options to the source/pool metatags --- ext/index/main.php | 14 +++++++++++--- ext/pools/main.php | 10 ++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/ext/index/main.php b/ext/index/main.php index 0aadaf2b..4d41ed20 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -83,9 +83,11 @@ *
  • tags>=10 -- search for images with 10 or more tags *
  • tags<25 -- search for images with less than 25 tags * - *
  • source=url, eg + *
  • source=(URL, any, none) eg *
      *
    • source=http://example.com -- find all images with "http://example.com" in the source + *
    • source=any -- find all images with a source + *
    • source=none -- find all images without a source *
    *
  • order=(id, width, height, filesize, filename)_(ASC, DESC), eg *
      @@ -136,7 +138,7 @@ *
    *
  • Pools *
      - *
    • pool=PoolID -- search for images in a pool by PoolID + *
    • pool=(PoolID, any, none) -- search for images in a pool by PoolID. *
    • pool_by_name=PoolName -- search for images in a pool by PoolName. underscores are replaced with spaces *
    * @@ -323,7 +325,13 @@ class Index extends Extension { } else if(preg_match("/^(source)[=|:]([a-zA-Z0-9]*)$/i", $event->term, $matches)) { $source = strtolower($matches[2]); - $event->add_querylet(new Querylet('images.source LIKE :src', array("src"=>"%$source%"))); + + if(preg_match("/^(any|none)$/", $source)){ + $not = ($source == "any" ? "NOT" : ""); + $event->add_querylet(new Querylet("images.source IS $not NULL")); + }else{ + $event->add_querylet(new Querylet('images.source LIKE :src', array("src"=>"%$source%"))); + } } else if(preg_match("/^posted([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])([0-9-]*)$/", $event->term, $matches)) { $cmp = ltrim($matches[1], ":") ?: "="; diff --git a/ext/pools/main.php b/ext/pools/main.php index 8431a653..6bcd8760 100644 --- a/ext/pools/main.php +++ b/ext/pools/main.php @@ -295,9 +295,15 @@ class Pools extends Extension { public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); - if(preg_match("/^pool[=|:]([0-9]+)$/", $event->term, $matches)) { + if(preg_match("/^pool[=|:]([0-9]+|any|none)$/", $event->term, $matches)) { $poolID = $matches[1]; - $event->add_querylet(new Querylet("images.id IN (SELECT DISTINCT image_id FROM pool_images WHERE pool_id = $poolID)")); + + 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[=|:](.*)$/", $event->term, $matches)) { $poolTitle = str_replace("_", " ", $matches[1]); From b5f70de49638241686ba64e7e9f6b02e4c6cfe28 Mon Sep 17 00:00:00 2001 From: Daku Date: Tue, 14 Jan 2014 07:52:45 +0000 Subject: [PATCH 29/32] change source metatag regex to allow searching for URLs --- ext/index/main.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/index/main.php b/ext/index/main.php index 4d41ed20..9cf5abfc 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -123,8 +123,8 @@ *
  • Notes *
      *
    • notes (=, <, >, <=, >=) number -- search by the number of notes an image has - *
    • notes_by=Username -- search for images contains notes created by username - *
    • notes_by_userno=UserID -- search for images contains notes created by userID + *
    • notes_by=Username -- search for images containing notes created by username + *
    • notes_by_userno=UserID -- search for images containing notes created by userID *
    *
  • Artists *
      @@ -133,8 +133,8 @@ *
    • Image Comments *
        *
      • comments (=, <, >, <=, >=) number -- search for images by number of comments - *
      • commented_by=Username -- search for images contains user's comments by username - *
      • commented_by_userno=UserID -- search for images contains user's comments by userID + *
      • commented_by=Username -- search for images containing user's comments by username + *
      • commented_by_userno=UserID -- search for images containing user's comments by userID *
      *
    • Pools *
        @@ -323,7 +323,7 @@ class Index extends Extension { $filename = strtolower($matches[2]); $event->add_querylet(new Querylet("images.filename LIKE :filename{$this->stpen}", array("filename{$this->stpen}"=>"%$filename%"))); } - else if(preg_match("/^(source)[=|:]([a-zA-Z0-9]*)$/i", $event->term, $matches)) { + else if(preg_match("/^(source)[=|:](.*)$/i", $event->term, $matches)) { $source = strtolower($matches[2]); if(preg_match("/^(any|none)$/", $source)){ From b856b132354f7c359d43ec1d214d3643187f2fbf Mon Sep 17 00:00:00 2001 From: Diftraku Date: Wed, 15 Jan 2014 23:06:27 +0200 Subject: [PATCH 30/32] Fix EXIF data throwing a notice when showing an image --- ext/handle_pixel/theme.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/handle_pixel/theme.php b/ext/handle_pixel/theme.php index 4099e97f..74f9af4c 100644 --- a/ext/handle_pixel/theme.php +++ b/ext/handle_pixel/theme.php @@ -13,6 +13,10 @@ class PixelFileHandlerTheme extends Themelet { foreach ($exif as $key => $section) { foreach ($section as $name => $val) { if($key == "IFD0") { + // Cheap fix for array'd values in EXIF-data + if (is_array($val)) { + $val = implode(',', $val); + } $head .= html_escape("$name: $val")."
        \n"; } } From 85303d232eecccb4685d75b3ba63c1ef04a506d6 Mon Sep 17 00:00:00 2001 From: Diftraku Date: Wed, 15 Jan 2014 23:28:40 +0200 Subject: [PATCH 31/32] Fixing stuff with API output being output twice Also some code formatting and a redirect from post/show for clients such as CartonBox so you can actually view the image after opening it in the browser on the client. --- ext/ouroboros_api/main.php | 297 +++++++++++++++++++++---------------- 1 file changed, 168 insertions(+), 129 deletions(-) diff --git a/ext/ouroboros_api/main.php b/ext/ouroboros_api/main.php index b16abbc7..cbfb38ae 100644 --- a/ext/ouroboros_api/main.php +++ b/ext/ouroboros_api/main.php @@ -1,4 +1,5 @@ @@ -213,7 +214,7 @@ class _SafeOuroborosImage if (defined('ENABLED_EXTS')) { if (strstr(ENABLED_EXTS, 'rating') !== false) { // 'u' is not a "valid" rating - if($img->rating == 's' || $img->rating == 'q' || $img->rating == 'e') { + if ($img->rating == 's' || $img->rating == 'q' || $img->rating == 'e') { $this->rating = $img->rating; } } @@ -239,7 +240,9 @@ class _SafeOuroborosImage $this->sample_url = make_http($img->get_image_link()); } } -class OuroborosPost extends _SafeOuroborosImage { + +class OuroborosPost extends _SafeOuroborosImage +{ /** * Multipart File * @var array @@ -265,7 +268,8 @@ class OuroborosPost extends _SafeOuroborosImage { * @TODO implement more validation from OuroborosAPI * @param array $post */ - public function __construct(array $post) { + public function __construct(array $post) + { if (array_key_exists('tags', $post)) { $this->tags = $post['tags']; } @@ -305,6 +309,7 @@ class OuroborosPost extends _SafeOuroborosImage { } } } + class _SafeOuroborosTag { public $ambiguous = false; @@ -320,6 +325,7 @@ class _SafeOuroborosTag $this->name = $tag['tag']; } } + class OuroborosAPI extends Extension { private $event; @@ -369,8 +375,7 @@ class OuroborosAPI extends Extension $this->type = $matches[1]; if ($this->type == 'json') { $page->set_type('application/json; charset=utf-8'); - } - elseif ($this->type == 'xml') { + } elseif ($this->type == 'xml') { $page->set_type('text/xml; charset=utf-8'); } $page->set_mode('data'); @@ -380,59 +385,105 @@ class OuroborosAPI extends Extension if ($this->match('create')) { // Create // @TODO Should move the validation logic into OuroborosPost instead? - if($user->can("create_image")) { + if ($user->can("create_image")) { $post = array( - 'tags' => !empty($_REQUEST['post']['tags']) ? filter_var($_REQUEST['post']['tags'], FILTER_SANITIZE_STRING) : 'tagme', - 'file' => !empty($_REQUEST['post']['file']) ? filter_var($_REQUEST['post']['file'], FILTER_UNSAFE_RAW) : null, - 'rating' => !empty($_REQUEST['post']['rating']) ? filter_var($_REQUEST['post']['rating'], FILTER_SANITIZE_NUMBER_INT) : 'q', - 'source' => !empty($_REQUEST['post']['source']) ? filter_var(urldecode($_REQUEST['post']['source']), FILTER_SANITIZE_URL) : null, - 'sourceurl' => !empty($_REQUEST['post']['sourceurl']) ? filter_var(urldecode($_REQUEST['post']['sourceurl']), FILTER_SANITIZE_URL) : '', - 'description' => !empty($_REQUEST['post']['description']) ? filter_var($_REQUEST['post']['description'], FILTER_SANITIZE_STRING) : '', - 'is_rating_locked' => !empty($_REQUEST['post']['is_rating_locked']) ? filter_var($_REQUEST['post']['is_rating_locked'], FILTER_SANITIZE_NUMBER_INT) : false, - 'is_note_locked' => !empty($_REQUEST['post']['is_note_locked']) ? filter_var($_REQUEST['post']['is_note_locked'], FILTER_SANITIZE_NUMBER_INT) : false, - 'parent_id' => !empty($_REQUEST['post']['parent_id']) ? filter_var($_REQUEST['post']['parent_id'], FILTER_SANITIZE_NUMBER_INT) : null, + 'tags' => !empty($_REQUEST['post']['tags']) ? filter_var( + urldecode($_REQUEST['post']['tags']), + FILTER_SANITIZE_STRING + ) : 'tagme', + 'file' => !empty($_REQUEST['post']['file']) ? filter_var( + $_REQUEST['post']['file'], + FILTER_UNSAFE_RAW + ) : null, + 'rating' => !empty($_REQUEST['post']['rating']) ? filter_var( + $_REQUEST['post']['rating'], + FILTER_SANITIZE_NUMBER_INT + ) : 'q', + 'source' => !empty($_REQUEST['post']['source']) ? filter_var( + urldecode($_REQUEST['post']['source']), + FILTER_SANITIZE_URL + ) : null, + 'sourceurl' => !empty($_REQUEST['post']['sourceurl']) ? filter_var( + urldecode($_REQUEST['post']['sourceurl']), + FILTER_SANITIZE_URL + ) : '', + 'description' => !empty($_REQUEST['post']['description']) ? filter_var( + $_REQUEST['post']['description'], + FILTER_SANITIZE_STRING + ) : '', + 'is_rating_locked' => !empty($_REQUEST['post']['is_rating_locked']) ? filter_var( + $_REQUEST['post']['is_rating_locked'], + FILTER_SANITIZE_NUMBER_INT + ) : false, + 'is_note_locked' => !empty($_REQUEST['post']['is_note_locked']) ? filter_var( + $_REQUEST['post']['is_note_locked'], + FILTER_SANITIZE_NUMBER_INT + ) : false, + 'parent_id' => !empty($_REQUEST['post']['parent_id']) ? filter_var( + $_REQUEST['post']['parent_id'], + FILTER_SANITIZE_NUMBER_INT + ) : null, ); $md5 = !empty($_REQUEST['md5']) ? filter_var($_REQUEST['md5'], FILTER_SANITIZE_STRING) : null; $this->postCreate(new OuroborosPost($post), $md5); - } - else { + } else { $this->sendResponse(403, 'You cannot create new posts'); } - } - elseif ($this->match('update')) { + } elseif ($this->match('update')) { // Update //@todo add post update - } - elseif ($this->match('show')) { + } elseif ($this->match('show')) { // Show $id = !empty($_REQUEST['id']) ? filter_var($_REQUEST['id'], FILTER_SANITIZE_NUMBER_INT) : null; $this->postShow($id); - } - elseif ($this->match('index') || $this->match('list')) { + } elseif ($this->match('index') || $this->match('list')) { // List - $limit = !empty($_REQUEST['limit']) ? intval(filter_var($_REQUEST['limit'], FILTER_SANITIZE_NUMBER_INT)) : 45; - $p = !empty($_REQUEST['page']) ? intval(filter_var($_REQUEST['page'], FILTER_SANITIZE_NUMBER_INT)) : 1; + $limit = !empty($_REQUEST['limit']) ? intval( + filter_var($_REQUEST['limit'], FILTER_SANITIZE_NUMBER_INT) + ) : 45; + $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(); if (!empty($tags)) { $tags = Tag::explode($tags); } $this->postIndex($limit, $p, $tags); } - } - elseif ($event->page_matches('tag')) { + } elseif ($event->page_matches('tag')) { if ($this->match('index') || $this->match('list')) { - $limit = !empty($_REQUEST['limit']) ? intval(filter_var($_REQUEST['limit'], FILTER_SANITIZE_NUMBER_INT)) : 50; - $p = !empty($_REQUEST['page']) ? intval(filter_var($_REQUEST['page'], FILTER_SANITIZE_NUMBER_INT)) : 1; - $order = (!empty($_REQUEST['order']) && ($_REQUEST['order'] == 'date' || $_REQUEST['order'] == 'count' || $_REQUEST['order'] == 'name')) ? filter_var($_REQUEST['order'], FILTER_SANITIZE_STRING) : 'date'; - $id = !empty($_REQUEST['id']) ? intval(filter_var($_REQUEST['id'], FILTER_SANITIZE_NUMBER_INT)) : null; - $after_id = !empty($_REQUEST['after_id']) ? intval(filter_var($_REQUEST['after_id'], FILTER_SANITIZE_NUMBER_INT)) : null; + $limit = !empty($_REQUEST['limit']) ? intval( + filter_var($_REQUEST['limit'], FILTER_SANITIZE_NUMBER_INT) + ) : 50; + $p = !empty($_REQUEST['page']) ? intval( + filter_var($_REQUEST['page'], FILTER_SANITIZE_NUMBER_INT) + ) : 1; + $order = (!empty($_REQUEST['order']) && ($_REQUEST['order'] == 'date' || $_REQUEST['order'] == 'count' || $_REQUEST['order'] == 'name')) ? filter_var( + $_REQUEST['order'], + FILTER_SANITIZE_STRING + ) : 'date'; + $id = !empty($_REQUEST['id']) ? intval( + filter_var($_REQUEST['id'], FILTER_SANITIZE_NUMBER_INT) + ) : null; + $after_id = !empty($_REQUEST['after_id']) ? intval( + filter_var($_REQUEST['after_id'], FILTER_SANITIZE_NUMBER_INT) + ) : null; $name = !empty($_REQUEST['name']) ? filter_var($_REQUEST['name'], FILTER_SANITIZE_STRING) : ''; - $name_pattern = !empty($_REQUEST['name_pattern']) ? filter_var($_REQUEST['name_pattern'], FILTER_SANITIZE_STRING) : ''; + $name_pattern = !empty($_REQUEST['name_pattern']) ? filter_var( + $_REQUEST['name_pattern'], + FILTER_SANITIZE_STRING + ) : ''; $this->tagIndex($limit, $p, $order, $id, $after_id, $name, $name_pattern); } } + } elseif ($event->page_matches('post/show')) { + $page->set_mode('redirect'); + $page->set_redirect(make_link(str_replace('post/show', 'post/view', implode('/', $event->args)))); + $page->display(); + die(); } + } /** @@ -444,12 +495,14 @@ class OuroborosAPI extends Extension * @param OuroborosPost $post * @param string $md5 */ - protected function postCreate(OuroborosPost $post, $md5 = '') { + protected function postCreate(OuroborosPost $post, $md5 = '') + { global $page, $config, $user; if (!empty($md5)) { $img = Image::by_hash($md5); if (!is_null($img)) { $this->sendResponse(420, self::ERROR_POST_CREATE_DUPE); + return; } } $meta = array(); @@ -461,42 +514,20 @@ 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) !== false) { + if (empty($post->file) && !empty($post->file_url) && filter_var( + $post->file_url, + FILTER_VALIDATE_URL + ) !== false + ) { // Transload from source - $meta['file'] = tempnam('/tmp', 'shimmie_transload_'.$config->get_string('transload_engine')); + $meta['file'] = tempnam('/tmp', 'shimmie_transload_' . $config->get_string('transload_engine')); $meta['filename'] = basename($post->file_url); - if ($config->get_string('transload_engine') == 'fopen') { - $fp = fopen($post->file_url, 'r'); - if (!$fp) { - $this->sendResponse(500, 'fopen failed'); - } - - $data = ""; - $length = 0; - while (!feof($fp) && $length <= $config->get_int('upload_size')) { - $data .= fread($fp, 8192); - $length = strlen($data); - } - fclose($fp); - - $fp = fopen($meta['file'], 'w'); - fwrite($fp, $data); - fclose($fp); - } - elseif ($config->get_string('transload_engine') == 'curl') { - $ch = curl_init($post->file_url); - $fp = fopen($meta['file'], 'w'); - - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_setopt($ch, CURLOPT_HEADER, 0); - - curl_exec($ch); - curl_close($ch); - fclose($fp); + if (!transload($post->file_url, $meta['file'])) { + $this->sendResponse(500, 'Transloading failed'); + return; } $meta['hash'] = md5_file($meta['file']); - } - else { + } else { // Use file $meta['file'] = $post->file['tmp_name']; $meta['filename'] = $post->file['name']; @@ -504,11 +535,13 @@ class OuroborosAPI extends Extension } if (!empty($md5) && $md5 !== $meta['hash']) { $this->sendResponse(420, self::ERROR_POST_CREATE_MD5); + return; } if (!empty($meta['hash'])) { $img = Image::by_hash($meta['hash']); if (!is_null($img)) { $this->sendResponse(420, self::ERROR_POST_CREATE_DUPE); + return; } } $meta['extension'] = pathinfo($meta['filename'], PATHINFO_EXTENSION); @@ -517,15 +550,17 @@ class OuroborosAPI extends Extension send_event($upload); $image = Image::by_hash($meta['hash']); if (!is_null($image)) { - $this->sendResponse(200, make_link('post/view/'.$image->id), true); - } - else { + $this->sendResponse(200, make_link('post/view/' . $image->id), true); + return; + } else { // Fail, unsupported file? $this->sendResponse(500, 'Unknown error'); + return; } } catch (UploadException $e) { // Cleanup in case shit hit the fan $this->sendResponse(500, $e->getMessage()); + return; } } @@ -533,12 +568,12 @@ class OuroborosAPI extends Extension * Wrapper for getting a single post * @param int $id */ - protected function postShow($id = null) { + protected function postShow($id = null) + { if (!is_null($id)) { $post = new _SafeOuroborosImage(Image::by_id($id)); $this->sendData('post', $post); - } - else { + } else { $this->sendResponse(424, 'ID is mandatory'); } } @@ -549,8 +584,9 @@ class OuroborosAPI extends Extension * @param $page * @param $tags */ - protected function postIndex($limit, $page, $tags) { - $start = ( $page - 1 ) * $limit; + protected function postIndex($limit, $page, $tags) + { + $start = ($page - 1) * $limit; $results = Image::find_images(max($start, 0), min($limit, 100), $tags); $posts = array(); foreach ($results as $img) { @@ -576,35 +612,47 @@ class OuroborosAPI extends Extension * @param $name * @param $name_pattern */ - protected function tagIndex($limit, $page, $order, $id, $after_id, $name, $name_pattern) { + protected function tagIndex($limit, $page, $order, $id, $after_id, $name, $name_pattern) + { global $database, $config; - $start = ( $page - 1 ) * $limit; + $start = ($page - 1) * $limit; $tag_data = array(); switch ($order) { case 'name': - $tag_data = $database->get_col($database->scoreql_to_sql(" - SELECT DISTINCT - id, SCORE_STRNORM(substr(tag, 1, 1)), count - FROM tags - WHERE count >= :tags_min - 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)); + $tag_data = $database->get_col( + $database->scoreql_to_sql( + " + SELECT DISTINCT + id, SCORE_STRNORM(substr(tag, 1, 1)), count + FROM tags + WHERE count >= :tags_min + 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) + ); break; case 'count': - $tag_data = $database->get_all(" - SELECT id, tag, count - FROM tags - 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)); + $tag_data = $database->get_all( + " + SELECT id, tag, count + FROM tags + 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) + ); break; case 'date': - $tag_data = $database->get_all(" - SELECT id, tag, count - FROM tags - 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)); + $tag_data = $database->get_all( + " + SELECT id, tag, count + FROM tags + 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) + ); break; } $tags = array(); @@ -628,19 +676,18 @@ class OuroborosAPI extends Extension * @param string $reason Reason for the code * @param bool $location Is $reason a location? (used mainly for post/create) */ - private function sendResponse($code = 200, $reason = '', $location = false) { + private function sendResponse($code = 200, $reason = '', $location = false) + { global $page; if ($code == 200) { $success = true; - } - else { + } else { $success = false; } if (empty($reason)) { if (defined("self::MSG_HTTP_{$code}")) { $reason = constant("self::MSG_HTTP_{$code}"); - } - else { + } else { $reason = self::MSG_HTTP_418; } } @@ -648,8 +695,7 @@ class OuroborosAPI extends Extension $proto = $_SERVER['SERVER_PROTOCOL']; if (defined("self::HEADER_HTTP_{$code}")) { $header = constant("self::HEADER_HTTP_{$code}"); - } - else { + } else { // I'm a teapot! $code = 418; $header = self::HEADER_HTTP_418; @@ -663,8 +709,7 @@ class OuroborosAPI extends Extension unset($response['reason']); } $response = json_encode($response); - } - elseif ($this->type == 'xml') { + } elseif ($this->type == 'xml') { // Seriously, XML sucks... $xml = new XMLWriter(); $xml->openMemory(); @@ -673,8 +718,7 @@ class OuroborosAPI extends Extension $xml->writeAttribute('success', var_export($success, true)); if ($location !== false) { $xml->writeAttribute('location', $reason); - } - else { + } else { $xml->writeAttribute('reason', $reason); } $xml->endElement(); @@ -683,7 +727,6 @@ class OuroborosAPI extends Extension unset($xml); } $page->set_data($response); - $page->display(); } /** @@ -692,18 +735,18 @@ class OuroborosAPI extends Extension * @param mixed $data * @param int $offset */ - private function sendData($type = '', $data = array(), $offset = 0) { + private function sendData($type = '', $data = array(), $offset = 0) + { global $page; $response = ''; if ($this->type == 'json') { $response = json_encode($data); - } - elseif ($this->type == 'xml') { + } elseif ($this->type == 'xml') { $xml = new XMLWriter(); $xml->openMemory(); $xml->startDocument('1.0', 'utf-8'); if (array_key_exists(0, $data)) { - $xml->startElement($type.'s'); + $xml->startElement($type . 's'); if ($type == 'post') { $xml->writeAttribute('count', count($data)); $xml->writeAttribute('offset', $offset); @@ -715,8 +758,7 @@ class OuroborosAPI extends Extension $this->createItemXML($xml, $type, $item); } $xml->endElement(); - } - else { + } else { $this->createItemXML($xml, $type, $data); } $xml->endDocument(); @@ -724,17 +766,15 @@ class OuroborosAPI extends Extension unset($xml); } $page->set_data($response); - $page->display(); - exit; } - private function createItemXML(XMLWriter &$xml, $type, $item) { + private function createItemXML(XMLWriter &$xml, $type, $item) + { $xml->startElement($type); foreach ($item as $key => $val) { if ($key == 'created_at' && $type == 'post') { $xml->writeAttribute($key, $val['s']); - } - else { + } else { if (is_bool($val)) { $val = $val ? 'true' : 'false'; } @@ -752,7 +792,8 @@ class OuroborosAPI extends Extension * @param void * @return void */ - private function tryAuth() { + private function tryAuth() + { global $config, $user; if (isset($_REQUEST['user']) && isset($_REQUEST['session'])) { @@ -762,22 +803,19 @@ class OuroborosAPI extends Extension $duser = User::by_session($name, $session); if (!is_null($duser)) { $user = $duser; - } - else { + } else { $user = User::by_id($config->get_int("anon_id", 0)); } - } - elseif (isset($_COOKIE[$config->get_string('cookie_prefix', 'shm').'_'.'session']) && - isset($_COOKIE[$config->get_string('cookie_prefix', 'shm').'_'.'user']) + } elseif (isset($_COOKIE[$config->get_string('cookie_prefix', 'shm') . '_' . 'session']) && + isset($_COOKIE[$config->get_string('cookie_prefix', 'shm') . '_' . 'user']) ) { //Auth by session data from cookies - $session = $_COOKIE[$config->get_string('cookie_prefix', 'shm').'_'.'session']; - $user = $_COOKIE[$config->get_string('cookie_prefix', 'shm').'_'.'user']; + $session = $_COOKIE[$config->get_string('cookie_prefix', 'shm') . '_' . 'session']; + $user = $_COOKIE[$config->get_string('cookie_prefix', 'shm') . '_' . 'user']; $duser = User::by_session($user, $session); if (!is_null($duser)) { $user = $duser; - } - else { + } else { $user = User::by_id($config->get_int("anon_id", 0)); } } @@ -788,7 +826,8 @@ class OuroborosAPI extends Extension * @param $page * @return bool */ - private function match($page) { + private function match($page) + { return (preg_match("%{$page}\.(xml|json)$%", implode('/', $this->event->args), $matches) === 1); } } From c07dc2e0abe0f387096ccdc9c0e427c37713e226 Mon Sep 17 00:00:00 2001 From: Daku Date: Thu, 16 Jan 2014 03:28:23 +0000 Subject: [PATCH 32/32] use resolve_aliases rather than resolve_alias --- core/imageboard.pack.php | 41 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php index 0bf145e9..6d5cd1cd 100644 --- a/core/imageboard.pack.php +++ b/core/imageboard.pack.php @@ -666,6 +666,8 @@ class Image { } } + $terms = Tag::resolve_aliases($terms); + // parse the words that are searched for into // various types of querylet foreach($terms as $term) { @@ -678,15 +680,6 @@ class Image { continue; } - $aliases = explode(" ", Tag::resolve_alias($term)); - $found = array_search($term, $aliases); - if($found !== false){ - unset($aliases[$found]); - }else{ - $term = array_shift($aliases); - } - foreach($aliases as $alias) array_push($terms, $alias); - $stpe = new SearchTermParseEvent($term, $terms); send_event($stpe); if($stpe->is_querylet_set()) { @@ -834,6 +827,8 @@ class Image { } } + $terms = Tag::resolve_aliases($terms); + reset($terms); // rewind to first element in array. // turn each term into a specific type of querylet @@ -843,15 +838,6 @@ class Image { $negative = true; $term = substr($term, 1); } - - $aliases = explode(" ", Tag::resolve_alias($term)); - $found = array_search($term, $aliases); - if($found !== false){ - unset($aliases[$found]); - }else{ - $term = array_shift($aliases); - } - foreach($aliases as $alias) array_push($terms, $alias); $stpe = new SearchTermParseEvent($term, $terms); send_event($stpe); @@ -1099,11 +1085,22 @@ class Tag { assert(is_array($tags)); $new = array(); - foreach($tags as $tag) { - $new_set = explode(' ', Tag::resolve_alias($tag)); - foreach($new_set as $new_one) { - $new[] = $new_one; + + $i = 0; + $tag_count = count($tags); + while($i<$tag_count) { + $aliases = explode(' ', Tag::resolve_alias($tags[$i])); + foreach($aliases as $alias){ + if(!in_array($alias, $new)){ + if($tags[$i] == $alias){ + $new[] = $alias; + }elseif(!in_array($alias, $tags)){ + $tags[] = $alias; + $tag_count++; + } + } } + $i++; } $new = array_iunique($new); // remove any duplicate tags