2007-04-16 11:58:25 +00:00
|
|
|
<?php
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2009-01-04 13:53:14 +00:00
|
|
|
* All the imageboard-specific bits of code should be in this file, everything
|
|
|
|
* else in /core should be standard SCore bits.
|
|
|
|
*/
|
|
|
|
|
2009-07-21 03:18:40 +00:00
|
|
|
/**
|
|
|
|
* \page search Shimmie2: Searching
|
2014-02-22 20:42:09 +00:00
|
|
|
*
|
2009-07-21 03:18:40 +00:00
|
|
|
* The current search system is built of several search item -> image ID list
|
|
|
|
* translators, eg:
|
2014-02-22 20:42:09 +00:00
|
|
|
*
|
2009-07-21 03:18:40 +00:00
|
|
|
* \li the item "fred" will search the image_tags table to find image IDs with the fred tag
|
|
|
|
* \li the item "size=640x480" will search the images table to find image IDs of 640x480 images
|
2014-02-22 20:42:09 +00:00
|
|
|
*
|
2009-07-21 03:18:40 +00:00
|
|
|
* So the search "fred size=640x480" will calculate two lists and take the
|
|
|
|
* intersection. (There are some optimisations in there making it more
|
|
|
|
* complicated behind the scenes, but as long as you can turn a single word
|
|
|
|
* into a list of image IDs, making a search plugin should be simple)
|
|
|
|
*/
|
|
|
|
|
2009-01-04 13:53:14 +00:00
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
|
|
|
* Classes *
|
|
|
|
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-29 05:33:03 +00:00
|
|
|
* Class Image
|
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* An object representing an entry in the images table.
|
|
|
|
*
|
|
|
|
* As of 2.2, this no longer necessarily represents an
|
|
|
|
* image per se, but could be a video, sound file, or any
|
|
|
|
* other supported upload type.
|
2007-12-06 11:01:18 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
class Image {
|
2015-08-02 18:29:25 +00:00
|
|
|
private static $tag_n = 0; // temp hack
|
2015-08-02 19:39:41 +00:00
|
|
|
public static $order_sql = null; // this feels ugly
|
2015-08-02 18:29:25 +00:00
|
|
|
|
2014-04-27 19:33:57 +00:00
|
|
|
/** @var null|int */
|
2014-04-24 08:30:58 +00:00
|
|
|
public $id = null;
|
2014-04-27 19:33:57 +00:00
|
|
|
|
|
|
|
/** @var int */
|
|
|
|
public $height;
|
|
|
|
|
|
|
|
/** @var int */
|
|
|
|
public $width;
|
|
|
|
|
|
|
|
/** @var string */
|
|
|
|
public $hash;
|
|
|
|
|
|
|
|
public $filesize;
|
|
|
|
|
|
|
|
/** @var string */
|
|
|
|
public $filename;
|
|
|
|
|
|
|
|
/** @var string */
|
|
|
|
public $ext;
|
|
|
|
|
2014-04-28 06:23:45 +00:00
|
|
|
/** @var string[]|null */
|
|
|
|
public $tag_array;
|
|
|
|
|
2017-03-12 08:18:26 +00:00
|
|
|
/** @var int */
|
|
|
|
public $owner_id;
|
|
|
|
|
|
|
|
/** @var string */
|
|
|
|
public $owner_ip;
|
|
|
|
|
|
|
|
/** @var string */
|
2015-09-27 20:09:27 +00:00
|
|
|
public $posted;
|
2017-03-12 08:18:26 +00:00
|
|
|
|
|
|
|
/** @var string */
|
2014-04-24 08:30:58 +00:00
|
|
|
public $source;
|
2017-03-12 08:18:26 +00:00
|
|
|
|
|
|
|
/** @var boolean */
|
2014-04-24 08:30:58 +00:00
|
|
|
public $locked;
|
2007-04-16 11:58:25 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* One will very rarely construct an image directly, more common
|
2014-04-27 19:33:57 +00:00
|
|
|
* would be to use Image::by_id, Image::by_hash, etc.
|
2014-04-27 22:59:01 +00:00
|
|
|
*
|
|
|
|
* @param null|mixed $row
|
2009-01-04 16:15:00 +00:00
|
|
|
*/
|
2014-03-22 09:00:59 +00:00
|
|
|
public function __construct($row=null) {
|
2015-07-21 00:20:53 +00:00
|
|
|
assert('is_null($row) || is_array($row)');
|
|
|
|
|
2007-12-06 11:01:18 +00:00
|
|
|
if(!is_null($row)) {
|
|
|
|
foreach($row as $name => $value) {
|
2009-07-16 23:27:40 +00:00
|
|
|
// some databases use table.name rather than name
|
|
|
|
$name = str_replace("images.", "", $name);
|
2014-04-24 09:29:02 +00:00
|
|
|
$this->$name = $value; // hax, this is likely the cause of much scrutinizer-ci complaints.
|
2007-12-06 11:01:18 +00:00
|
|
|
}
|
2012-04-15 23:28:27 +00:00
|
|
|
$this->locked = bool_escape($this->locked);
|
2010-02-02 00:29:38 +00:00
|
|
|
|
|
|
|
assert(is_numeric($this->id));
|
|
|
|
assert(is_numeric($this->height));
|
|
|
|
assert(is_numeric($this->width));
|
2007-10-02 22:23:29 +00:00
|
|
|
}
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Find an image by ID.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-26 03:22:34 +00:00
|
|
|
* @param int $id
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return Image
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2012-02-02 13:58:48 +00:00
|
|
|
public static function by_id(/*int*/ $id) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_numeric($id)');
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2011-01-01 15:28:30 +00:00
|
|
|
$row = $database->get_row("SELECT * FROM images WHERE images.id=:id", array("id"=>$id));
|
2008-08-26 09:11:40 +00:00
|
|
|
return ($row ? new Image($row) : null);
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Find an image by hash.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-26 03:22:34 +00:00
|
|
|
* @param string $hash
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return Image
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2012-02-02 13:58:48 +00:00
|
|
|
public static function by_hash(/*string*/ $hash) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_string($hash)');
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2011-01-01 16:28:04 +00:00
|
|
|
$row = $database->get_row("SELECT images.* FROM images WHERE hash=:hash", array("hash"=>$hash));
|
2008-10-09 03:21:18 +00:00
|
|
|
return ($row ? new Image($row) : null);
|
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Pick a random image out of a set.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* @param string[] $tags
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return Image
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2009-05-11 14:04:33 +00:00
|
|
|
public static function by_random($tags=array()) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_array($tags)');
|
2009-05-11 14:04:33 +00:00
|
|
|
$max = Image::count_images($tags);
|
2011-09-12 01:41:46 +00:00
|
|
|
if ($max < 1) return null; // From Issue #22 - opened by HungryFeline on May 30, 2011.
|
2008-11-07 11:46:34 +00:00
|
|
|
$rand = mt_rand(0, $max-1);
|
2009-05-11 14:04:33 +00:00
|
|
|
$set = Image::find_images($rand, 1, $tags);
|
2008-10-09 03:21:18 +00:00
|
|
|
if(count($set) > 0) return $set[0];
|
|
|
|
else return null;
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Search for an array of images
|
2012-02-08 01:05:38 +00:00
|
|
|
*
|
2014-04-26 03:22:34 +00:00
|
|
|
* @param int $start
|
|
|
|
* @param int $limit
|
2014-04-27 19:33:57 +00:00
|
|
|
* @param string[] $tags
|
2014-04-24 23:08:23 +00:00
|
|
|
* @throws SCoreException
|
2014-04-29 21:45:13 +00:00
|
|
|
* @return Image[]
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2012-02-08 01:05:38 +00:00
|
|
|
public static function find_images(/*int*/ $start, /*int*/ $limit, $tags=array()) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_numeric($start)');
|
|
|
|
assert('is_numeric($limit)');
|
|
|
|
assert('is_array($tags)');
|
2015-08-02 19:39:41 +00:00
|
|
|
global $database, $user, $config;
|
2009-05-11 14:04:33 +00:00
|
|
|
|
|
|
|
$images = array();
|
|
|
|
|
2008-10-09 03:21:18 +00:00
|
|
|
if($start < 0) $start = 0;
|
|
|
|
if($limit < 1) $limit = 1;
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2012-02-05 04:21:03 +00:00
|
|
|
if(SPEED_HAX) {
|
2012-02-07 15:15:18 +00:00
|
|
|
if(!$user->can("big_search") and count($tags) > 3) {
|
2014-03-30 12:26:48 +00:00
|
|
|
throw new SCoreException("Anonymous users may only search for up to 3 tags at a time");
|
2012-02-05 04:21:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-12 21:12:05 +00:00
|
|
|
$result = null;
|
|
|
|
if(SEARCH_ACCEL) {
|
|
|
|
$result = Image::get_accelerated_result($tags, $start, $limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!$result) {
|
|
|
|
$querylet = Image::build_search_querylet($tags);
|
2015-08-02 19:39:41 +00:00
|
|
|
$querylet->append(new Querylet(" ORDER BY ".(Image::$order_sql ?: "images.".$config->get_string("index_order"))));
|
2015-07-12 21:12:05 +00:00
|
|
|
$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);
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2011-01-01 15:28:30 +00:00
|
|
|
while($row = $result->fetch()) {
|
|
|
|
$images[] = new Image($row);
|
2008-10-09 03:21:18 +00:00
|
|
|
}
|
2015-08-02 19:39:41 +00:00
|
|
|
Image::$order_sql = null;
|
2008-10-09 03:21:18 +00:00
|
|
|
return $images;
|
|
|
|
}
|
|
|
|
|
2017-03-09 07:02:26 +00:00
|
|
|
/**
|
|
|
|
* @param string[] $tags
|
|
|
|
* @return boolean
|
|
|
|
*/
|
2015-07-12 21:12:05 +00:00
|
|
|
public function validate_accel($tags) {
|
|
|
|
$yays = 0;
|
|
|
|
$nays = 0;
|
|
|
|
foreach($tags as $tag) {
|
|
|
|
if(!preg_match("/^-?[a-zA-Z0-9_]+$/", $tag)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if($tag[0] == "-") $nays++;
|
|
|
|
else $yays++;
|
|
|
|
}
|
|
|
|
return ($yays > 1 || $nays > 0);
|
|
|
|
}
|
|
|
|
|
2015-09-27 01:17:44 +00:00
|
|
|
/**
|
|
|
|
* @param string[] $tags
|
|
|
|
* @param int $offset
|
|
|
|
* @param int $limit
|
|
|
|
* @return null|PDOStatement
|
|
|
|
* @throws SCoreException
|
|
|
|
*/
|
2015-07-12 21:12:05 +00:00
|
|
|
public function get_accelerated_result($tags, $offset, $limit) {
|
|
|
|
global $database;
|
|
|
|
|
|
|
|
if(!Image::validate_accel($tags)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$yays = array();
|
|
|
|
$nays = array();
|
|
|
|
foreach($tags as $tag) {
|
|
|
|
if($tag[0] == "-") {
|
|
|
|
$nays[] = substr($tag, 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$yays[] = $tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$req = array(
|
|
|
|
"yays" => $yays,
|
|
|
|
"nays" => $nays,
|
|
|
|
"offset" => $offset,
|
|
|
|
"limit" => $limit,
|
|
|
|
);
|
|
|
|
|
|
|
|
$fp = fsockopen("127.0.0.1", 21212);
|
|
|
|
if (!$fp) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
fwrite($fp, json_encode($req));
|
|
|
|
$data = fgets($fp, 1024);
|
|
|
|
fclose($fp);
|
|
|
|
|
|
|
|
$response = json_decode($data);
|
|
|
|
$list = implode(",", $response);
|
|
|
|
if($list) {
|
|
|
|
$result = $database->execute("SELECT * FROM images WHERE id IN ($list) ORDER BY images.id DESC");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$result = $database->execute("SELECT * FROM images WHERE 1=0 ORDER BY images.id DESC");
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2009-01-04 16:15:00 +00:00
|
|
|
/*
|
|
|
|
* Image-related utility functions
|
|
|
|
*/
|
2014-02-22 20:42:09 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Count the number of image results for a given search
|
2014-04-26 09:01:49 +00:00
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* @param string[] $tags
|
2015-09-27 01:17:44 +00:00
|
|
|
* @return int
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2009-05-11 14:04:33 +00:00
|
|
|
public static function count_images($tags=array()) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_array($tags)');
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2013-10-04 21:17:42 +00:00
|
|
|
$tag_count = count($tags);
|
2014-02-22 20:42:09 +00:00
|
|
|
|
2013-10-04 21:17:42 +00:00
|
|
|
if($tag_count === 0) {
|
2010-02-02 00:29:38 +00:00
|
|
|
$total = $database->cache->get("image-count");
|
|
|
|
if(!$total) {
|
2011-01-01 15:28:30 +00:00
|
|
|
$total = $database->get_one("SELECT COUNT(*) FROM images");
|
2010-02-02 00:29:38 +00:00
|
|
|
$database->cache->set("image-count", $total, 600);
|
|
|
|
}
|
|
|
|
return $total;
|
2008-10-09 03:28:58 +00:00
|
|
|
}
|
2013-10-04 21:17:42 +00:00
|
|
|
else if($tag_count === 1 && !preg_match("/[:=><\*\?]/", $tags[0])) {
|
2011-01-01 15:28:30 +00:00
|
|
|
return $database->get_one(
|
2012-06-23 23:57:55 +00:00
|
|
|
$database->scoreql_to_sql("SELECT count FROM tags WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)"),
|
2016-07-30 21:11:49 +00:00
|
|
|
array("tag"=>$tags[0]));
|
2010-02-02 16:33:56 +00:00
|
|
|
}
|
2008-10-09 03:28:58 +00:00
|
|
|
else {
|
2009-05-11 14:04:33 +00:00
|
|
|
$querylet = Image::build_search_querylet($tags);
|
2008-10-09 03:28:58 +00:00
|
|
|
$result = $database->execute($querylet->sql, $querylet->variables);
|
2011-01-01 15:58:09 +00:00
|
|
|
return $result->rowCount();
|
2008-10-09 03:28:58 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Count the number of pages for a given search
|
2014-04-26 09:01:49 +00:00
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* @param string[] $tags
|
2014-04-26 09:01:49 +00:00
|
|
|
* @return float
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2009-05-11 14:04:33 +00:00
|
|
|
public static function count_pages($tags=array()) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_array($tags)');
|
2015-05-24 15:08:26 +00:00
|
|
|
global $config;
|
2012-04-01 16:47:39 +00:00
|
|
|
return ceil(Image::count_images($tags) / $config->get_int('index_images'));
|
2008-10-09 03:28:58 +00:00
|
|
|
}
|
|
|
|
|
2009-01-04 16:15:00 +00:00
|
|
|
/*
|
|
|
|
* Accessors & mutators
|
|
|
|
*/
|
2009-07-19 07:38:13 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Find the next image in the sequence.
|
|
|
|
*
|
|
|
|
* Rather than simply $this_id + 1, one must take into account
|
|
|
|
* deleted images and search queries
|
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* @param string[] $tags
|
2014-04-24 23:08:23 +00:00
|
|
|
* @param bool $next
|
|
|
|
* @return Image
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2008-10-09 03:21:18 +00:00
|
|
|
public function get_next($tags=array(), $next=true) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_array($tags)');
|
|
|
|
assert('is_bool($next)');
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2008-10-09 03:21:18 +00:00
|
|
|
if($next) {
|
|
|
|
$gtlt = "<";
|
|
|
|
$dir = "DESC";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$gtlt = ">";
|
|
|
|
$dir = "ASC";
|
|
|
|
}
|
|
|
|
|
2013-10-04 21:17:42 +00:00
|
|
|
if(count($tags) === 0) {
|
2016-06-07 01:05:19 +00:00
|
|
|
$row = $database->get_row('
|
|
|
|
SELECT images.*
|
|
|
|
FROM images
|
|
|
|
WHERE images.id '.$gtlt.' '.$this->id.'
|
|
|
|
ORDER BY images.id '.$dir.'
|
|
|
|
LIMIT 1
|
|
|
|
');
|
2008-10-09 03:21:18 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-01-11 20:08:27 +00:00
|
|
|
$tags[] = 'id'. $gtlt . $this->id;
|
2009-05-11 14:04:33 +00:00
|
|
|
$querylet = Image::build_search_querylet($tags);
|
2012-01-11 20:08:27 +00:00
|
|
|
$querylet->append_sql(' ORDER BY images.id '.$dir.' LIMIT 1');
|
2011-01-01 16:28:04 +00:00
|
|
|
$row = $database->get_row($querylet->sql, $querylet->variables);
|
2008-10-09 03:21:18 +00:00
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2008-10-09 03:21:18 +00:00
|
|
|
return ($row ? new Image($row) : null);
|
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* The reverse of get_next
|
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* @param string[] $tags
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return Image
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2008-10-09 03:21:18 +00:00
|
|
|
public function get_prev($tags=array()) {
|
|
|
|
return $this->get_next($tags, false);
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Find the User who owns this Image
|
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return User
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_owner() {
|
2009-05-11 14:04:33 +00:00
|
|
|
return User::by_id($this->owner_id);
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2012-02-09 17:03:39 +00:00
|
|
|
/**
|
2014-04-26 09:01:49 +00:00
|
|
|
* Set the image's owner.
|
|
|
|
*
|
|
|
|
* @param User $owner
|
2012-02-09 17:03:39 +00:00
|
|
|
*/
|
|
|
|
public function set_owner(User $owner) {
|
|
|
|
global $database;
|
|
|
|
if($owner->id != $this->owner_id) {
|
2016-06-07 01:05:19 +00:00
|
|
|
$database->execute("
|
|
|
|
UPDATE images
|
|
|
|
SET owner_id=:owner_id
|
|
|
|
WHERE id=:id
|
|
|
|
", array("owner_id"=>$owner->id, "id"=>$this->id));
|
2013-08-29 23:19:38 +00:00
|
|
|
log_info("core_image", "Owner for Image #{$this->id} set to {$owner->name}", false, array("image_id" => $this->id));
|
2012-02-09 17:03:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Get this image's tags as an array.
|
|
|
|
*
|
|
|
|
* @return string[]
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_tag_array() {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2007-04-16 11:58:25 +00:00
|
|
|
if(!isset($this->tag_array)) {
|
2016-06-07 01:05:19 +00:00
|
|
|
$this->tag_array = $database->get_col("
|
|
|
|
SELECT tag
|
|
|
|
FROM image_tags
|
|
|
|
JOIN tags ON image_tags.tag_id = tags.id
|
|
|
|
WHERE image_id=:id
|
|
|
|
ORDER BY tag
|
|
|
|
", array("id"=>$this->id));
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
return $this->tag_array;
|
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-26 09:01:49 +00:00
|
|
|
* Get this image's tags as a string.
|
|
|
|
*
|
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_tag_list() {
|
2009-08-24 02:33:51 +00:00
|
|
|
return Tag::implode($this->get_tag_array());
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Get the URL for the full size image
|
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_image_link() {
|
2016-05-14 21:56:08 +00:00
|
|
|
return $this->get_link('image_ilink', '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext');
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2015-06-01 09:57:56 +00:00
|
|
|
* Get the URL for the thumbnail
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2015-06-01 09:57:56 +00:00
|
|
|
public function get_thumb_link() {
|
|
|
|
return $this->get_link('image_tlink', '_thumbs/$hash/thumb.jpg', 'thumb/$id.jpg');
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2015-06-01 09:57:56 +00:00
|
|
|
* Check configured template for a link, then try nice URL, then plain URL
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2015-09-27 01:17:44 +00:00
|
|
|
* @param string $template
|
|
|
|
* @param string $nice
|
|
|
|
* @param string $plain
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2015-06-01 09:57:56 +00:00
|
|
|
private function get_link($template, $nice, $plain) {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $config;
|
2014-02-22 20:42:09 +00:00
|
|
|
|
2015-06-01 09:57:56 +00:00
|
|
|
$image_link = $config->get_string($template);
|
2014-02-22 20:42:09 +00:00
|
|
|
|
2015-06-01 09:57:56 +00:00
|
|
|
if(!empty($image_link)) {
|
2015-07-21 00:00:13 +00:00
|
|
|
if(!(strpos($image_link, "://") > 0) && !startsWith($image_link, "/")) {
|
2015-06-01 09:57:56 +00:00
|
|
|
$image_link = make_link($image_link);
|
2012-01-31 15:11:06 +00:00
|
|
|
}
|
2015-06-01 09:57:56 +00:00
|
|
|
return $this->parse_link_template($image_link);
|
2008-12-27 10:17:53 +00:00
|
|
|
}
|
2009-05-11 14:04:33 +00:00
|
|
|
else if($config->get_bool('nice_urls', false)) {
|
2015-06-01 09:57:56 +00:00
|
|
|
return $this->parse_link_template(make_link($nice));
|
2008-12-27 10:17:53 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-06-01 09:57:56 +00:00
|
|
|
return $this->parse_link_template(make_link($plain));
|
2008-12-27 10:17:53 +00:00
|
|
|
}
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Get the tooltip for this image, formatted according to the
|
2014-04-27 19:33:57 +00:00
|
|
|
* configured template.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_tooltip() {
|
|
|
|
global $config;
|
2012-03-12 05:08:40 +00:00
|
|
|
$tt = $this->parse_link_template($config->get_string('image_tip'), "no_escape");
|
|
|
|
|
2014-02-22 20:42:09 +00:00
|
|
|
// Removes the size tag if the file is an mp3
|
2012-03-12 05:08:40 +00:00
|
|
|
if($this->ext === 'mp3'){
|
|
|
|
$iitip = $tt;
|
|
|
|
$mp3tip = array("0x0");
|
|
|
|
$h_tip = str_replace($mp3tip, " ", $iitip);
|
|
|
|
|
|
|
|
// Makes it work with a variation of the default tooltips (I.E $tags // $filesize // $size)
|
|
|
|
$justincase = array(" //", "// ", " //", "// ", " ");
|
|
|
|
if(strstr($h_tip, " ")) {
|
|
|
|
$h_tip = html_escape(str_replace($justincase, "", $h_tip));
|
|
|
|
}else{
|
|
|
|
$h_tip = html_escape($h_tip);
|
|
|
|
}
|
|
|
|
return $h_tip;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return $tt;
|
|
|
|
}
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Figure out where the full size image is on disk.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_image_filename() {
|
2010-02-02 00:29:38 +00:00
|
|
|
return warehouse_path("images", $this->hash);
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Figure out where the thumbnail is on disk.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_thumb_filename() {
|
2010-02-02 00:29:38 +00:00
|
|
|
return warehouse_path("thumbs", $this->hash);
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Get the original filename.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_filename() {
|
|
|
|
return $this->filename;
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Get the image's mime type.
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_mime_type() {
|
2012-09-22 22:15:25 +00:00
|
|
|
return getMimeType($this->get_image_filename(), $this->get_ext());
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Get the image's filename extension
|
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-04-16 11:58:25 +00:00
|
|
|
public function get_ext() {
|
|
|
|
return $this->ext;
|
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Get the image's source URL
|
|
|
|
*
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2008-02-06 17:33:08 +00:00
|
|
|
public function get_source() {
|
|
|
|
return $this->source;
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Set the image's source URL
|
2014-04-26 03:22:34 +00:00
|
|
|
*
|
|
|
|
* @param string $new_source
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2013-05-07 08:13:03 +00:00
|
|
|
public function set_source(/*string*/ $new_source) {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2013-05-07 08:13:03 +00:00
|
|
|
$old_source = $this->source;
|
|
|
|
if(empty($new_source)) $new_source = null;
|
|
|
|
if($new_source != $old_source) {
|
|
|
|
$database->execute("UPDATE images SET source=:source WHERE id=:id", array("source"=>$new_source, "id"=>$this->id));
|
2013-08-29 23:19:38 +00:00
|
|
|
log_info("core_image", "Source for Image #{$this->id} set to: $new_source (was $old_source)", false, array("image_id" => $this->id));
|
2012-01-21 00:17:07 +00:00
|
|
|
}
|
2009-01-04 16:15:00 +00:00
|
|
|
}
|
|
|
|
|
2012-02-08 01:05:38 +00:00
|
|
|
/**
|
|
|
|
* Check if the image is locked.
|
2014-04-24 23:08:23 +00:00
|
|
|
* @return bool
|
2012-02-08 01:05:38 +00:00
|
|
|
*/
|
2010-02-17 14:16:20 +00:00
|
|
|
public function is_locked() {
|
2012-03-10 18:53:42 +00:00
|
|
|
return $this->locked;
|
2010-02-17 14:16:20 +00:00
|
|
|
}
|
2012-03-10 18:53:42 +00:00
|
|
|
|
2015-09-27 01:17:44 +00:00
|
|
|
/**
|
|
|
|
* @param bool $tf
|
|
|
|
* @throws SCoreException
|
|
|
|
*/
|
2012-01-27 16:27:02 +00:00
|
|
|
public function set_locked($tf) {
|
2010-02-17 14:16:20 +00:00
|
|
|
global $database;
|
|
|
|
$ln = $tf ? "Y" : "N";
|
2012-06-23 23:57:55 +00:00
|
|
|
$sln = $database->scoreql_to_sql('SCORE_BOOL_'.$ln);
|
2010-02-17 14:16:20 +00:00
|
|
|
$sln = str_replace("'", "", $sln);
|
|
|
|
$sln = str_replace('"', "", $sln);
|
2012-04-15 23:28:27 +00:00
|
|
|
if(bool_escape($sln) !== $this->locked) {
|
2012-01-21 00:17:07 +00:00
|
|
|
$database->execute("UPDATE images SET locked=:yn WHERE id=:id", array("yn"=>$sln, "id"=>$this->id));
|
2013-08-29 23:19:38 +00:00
|
|
|
log_info("core_image", "Setting Image #{$this->id} lock to: $ln", false, array("image_id" => $this->id));
|
2012-01-21 00:17:07 +00:00
|
|
|
}
|
2010-02-17 14:16:20 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Delete all tags from this image.
|
|
|
|
*
|
|
|
|
* Normally in preparation to set them to a new set.
|
|
|
|
*/
|
2009-01-04 16:15:00 +00:00
|
|
|
public function delete_tags_from_image() {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2015-12-04 11:38:44 +00:00
|
|
|
if($database->get_driver_name() == "mysql") {
|
|
|
|
//mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this
|
|
|
|
$database->execute("
|
|
|
|
UPDATE tags t
|
|
|
|
INNER JOIN image_tags it ON t.id = it.tag_id
|
|
|
|
SET count = count - 1
|
|
|
|
WHERE it.image_id = :id",
|
|
|
|
array("id"=>$this->id)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$database->execute("
|
|
|
|
UPDATE tags
|
|
|
|
SET count = count - 1
|
2016-06-07 01:05:19 +00:00
|
|
|
WHERE id IN (
|
|
|
|
SELECT tag_id
|
|
|
|
FROM image_tags
|
|
|
|
WHERE image_id = :id
|
|
|
|
)
|
|
|
|
", array("id"=>$this->id));
|
2015-12-04 11:38:44 +00:00
|
|
|
}
|
2016-06-07 01:05:19 +00:00
|
|
|
$database->execute("
|
|
|
|
DELETE
|
|
|
|
FROM image_tags
|
|
|
|
WHERE image_id=:id
|
|
|
|
", array("id"=>$this->id));
|
2009-01-04 16:15:00 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-27 19:33:57 +00:00
|
|
|
* Set the tags for this image.
|
|
|
|
*
|
|
|
|
* @param string[] $tags
|
2015-09-12 10:43:28 +00:00
|
|
|
* @throws Exception
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2012-01-27 16:27:02 +00:00
|
|
|
public function set_tags($tags) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_array($tags) && count($tags) > 0', var_export($tags, true));
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2012-01-27 16:27:02 +00:00
|
|
|
|
2015-07-19 18:04:35 +00:00
|
|
|
if(count($tags) <= 0) {
|
|
|
|
throw new SCoreException('Tried to set zero tags');
|
|
|
|
}
|
2012-01-27 16:27:02 +00:00
|
|
|
|
2015-07-19 18:04:35 +00:00
|
|
|
if(implode(" ", $tags) != $this->get_tag_list()) {
|
2012-01-21 00:17:07 +00:00
|
|
|
// delete old
|
|
|
|
$this->delete_tags_from_image();
|
|
|
|
// insert each new tags
|
|
|
|
foreach($tags as $tag) {
|
2014-06-19 23:39:29 +00:00
|
|
|
if(mb_strlen($tag, 'UTF-8') > 255){
|
|
|
|
flash_message("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-01-21 00:17:07 +00:00
|
|
|
$id = $database->get_one(
|
2016-06-07 01:05:19 +00:00
|
|
|
$database->scoreql_to_sql("
|
|
|
|
SELECT id
|
|
|
|
FROM tags
|
|
|
|
WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)
|
|
|
|
"),
|
|
|
|
array("tag"=>$tag)
|
|
|
|
);
|
2012-01-21 00:17:07 +00:00
|
|
|
if(empty($id)) {
|
|
|
|
// a new tag
|
|
|
|
$database->execute(
|
|
|
|
"INSERT INTO tags(tag) VALUES (:tag)",
|
|
|
|
array("tag"=>$tag));
|
|
|
|
$database->execute(
|
|
|
|
"INSERT INTO image_tags(image_id, tag_id)
|
|
|
|
VALUES(:id, (SELECT id FROM tags WHERE tag = :tag))",
|
|
|
|
array("id"=>$this->id, "tag"=>$tag));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// user of an existing tag
|
2016-06-07 01:05:19 +00:00
|
|
|
$database->execute("
|
|
|
|
INSERT INTO image_tags(image_id, tag_id)
|
|
|
|
VALUES(:iid, :tid)
|
|
|
|
", array("iid"=>$this->id, "tid"=>$id));
|
2012-01-21 00:17:07 +00:00
|
|
|
}
|
2009-05-11 14:04:33 +00:00
|
|
|
$database->execute(
|
2016-06-07 01:05:19 +00:00
|
|
|
$database->scoreql_to_sql("
|
|
|
|
UPDATE tags
|
|
|
|
SET count = count + 1
|
|
|
|
WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)
|
|
|
|
"),
|
|
|
|
array("tag"=>$tag)
|
|
|
|
);
|
2009-01-22 17:08:33 +00:00
|
|
|
}
|
2009-01-19 18:27:53 +00:00
|
|
|
|
2014-06-19 23:39:29 +00:00
|
|
|
log_info("core_image", "Tags for Image #{$this->id} set to: ".implode(" ", $tags), null, array("image_id" => $this->id));
|
2012-01-21 00:17:07 +00:00
|
|
|
$database->cache->delete("image-{$this->id}-tags");
|
|
|
|
}
|
2009-01-04 16:15:00 +00:00
|
|
|
}
|
|
|
|
|
2015-10-08 17:58:52 +00:00
|
|
|
/**
|
|
|
|
* Send list of metatags to be parsed.
|
|
|
|
*
|
2016-07-03 11:07:54 +00:00
|
|
|
* @param string[] $metatags
|
2015-10-08 18:25:38 +00:00
|
|
|
* @param int $image_id
|
2015-10-08 17:58:52 +00:00
|
|
|
*/
|
2015-10-08 18:25:38 +00:00
|
|
|
public function parse_metatags($metatags, $image_id) {
|
2015-10-08 17:58:52 +00:00
|
|
|
foreach($metatags as $tag) {
|
|
|
|
$ttpe = new TagTermParseEvent($tag, $image_id, TRUE);
|
|
|
|
send_event($ttpe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Delete this image from the database and disk
|
2009-01-04 16:15:00 +00:00
|
|
|
*/
|
|
|
|
public function delete() {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2009-05-11 14:48:18 +00:00
|
|
|
$this->delete_tags_from_image();
|
2011-01-01 15:58:09 +00:00
|
|
|
$database->execute("DELETE FROM images WHERE id=:id", array("id"=>$this->id));
|
2013-08-29 23:19:38 +00:00
|
|
|
log_info("core_image", 'Deleted Image #'.$this->id.' ('.$this->hash.')', false, array("image_id" => $this->id));
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2009-01-04 16:15:00 +00:00
|
|
|
unlink($this->get_image_filename());
|
|
|
|
unlink($this->get_thumb_filename());
|
|
|
|
}
|
2008-02-06 17:33:08 +00:00
|
|
|
|
2011-08-25 00:53:53 +00:00
|
|
|
/**
|
|
|
|
* This function removes an image (and thumbnail) from the DISK ONLY.
|
|
|
|
* It DOES NOT remove anything from the database.
|
|
|
|
*/
|
|
|
|
public function remove_image_only() {
|
2013-08-29 23:19:38 +00:00
|
|
|
log_info("core_image", 'Removed Image File ('.$this->hash.')', false, array("image_id" => $this->id));
|
2011-09-04 15:17:14 +00:00
|
|
|
@unlink($this->get_image_filename());
|
|
|
|
@unlink($this->get_thumb_filename());
|
2011-08-25 00:53:53 +00:00
|
|
|
}
|
2014-02-22 20:42:09 +00:00
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2009-07-21 06:36:12 +00:00
|
|
|
* Someone please explain this
|
2009-07-19 07:38:13 +00:00
|
|
|
*
|
2014-04-27 19:33:57 +00:00
|
|
|
* @param string $tmpl
|
2014-04-24 23:08:23 +00:00
|
|
|
* @param string $_escape
|
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2007-07-16 16:48:35 +00:00
|
|
|
public function parse_link_template($tmpl, $_escape="url_escape") {
|
2009-05-11 14:04:33 +00:00
|
|
|
global $config;
|
|
|
|
|
2007-04-16 11:58:25 +00:00
|
|
|
// don't bother hitting the database if it won't be used...
|
2009-08-11 14:12:48 +00:00
|
|
|
$tags = "";
|
2007-04-16 11:58:25 +00:00
|
|
|
if(strpos($tmpl, '$tags') !== false) { // * stabs dynamically typed languages with a rusty spoon *
|
2009-08-11 14:12:48 +00:00
|
|
|
$tags = $this->get_tag_list();
|
|
|
|
$tags = str_replace("/", "", $tags);
|
|
|
|
$tags = preg_replace("/^\.+/", "", $tags);
|
2007-04-16 11:58:25 +00:00
|
|
|
}
|
|
|
|
|
2009-05-11 14:04:33 +00:00
|
|
|
$base_href = $config->get_string('base_href');
|
2007-05-07 00:18:52 +00:00
|
|
|
$fname = $this->get_filename();
|
2007-04-16 11:58:25 +00:00
|
|
|
$base_fname = strpos($fname, '.') ? substr($fname, 0, strrpos($fname, '.')) : $fname;
|
|
|
|
|
2007-05-07 00:18:52 +00:00
|
|
|
$tmpl = str_replace('$id', $this->id, $tmpl);
|
2009-11-12 09:27:09 +00:00
|
|
|
$tmpl = str_replace('$hash_ab', substr($this->hash, 0, 2), $tmpl);
|
|
|
|
$tmpl = str_replace('$hash_cd', substr($this->hash, 2, 2), $tmpl);
|
2009-11-12 09:30:41 +00:00
|
|
|
$tmpl = str_replace('$hash', $this->hash, $tmpl);
|
2009-08-11 14:12:48 +00:00
|
|
|
$tmpl = str_replace('$tags', $_escape($tags), $tmpl);
|
2007-05-07 00:18:52 +00:00
|
|
|
$tmpl = str_replace('$base', $base_href, $tmpl);
|
|
|
|
$tmpl = str_replace('$ext', $this->ext, $tmpl);
|
|
|
|
$tmpl = str_replace('$size', "{$this->width}x{$this->height}", $tmpl);
|
|
|
|
$tmpl = str_replace('$filesize', to_shorthand_int($this->filesize), $tmpl);
|
2007-07-16 16:48:35 +00:00
|
|
|
$tmpl = str_replace('$filename', $_escape($base_fname), $tmpl);
|
2009-05-11 14:04:33 +00:00
|
|
|
$tmpl = str_replace('$title', $_escape($config->get_string("title")), $tmpl);
|
2013-10-04 01:19:19 +00:00
|
|
|
$tmpl = str_replace('$date', $_escape(autodate($this->posted, false)), $tmpl);
|
2007-04-16 11:58:25 +00:00
|
|
|
|
2011-12-24 14:49:55 +00:00
|
|
|
// nothing seems to use this, sending the event out to 50 exts is a lot of overhead
|
|
|
|
if(!SPEED_HAX) {
|
|
|
|
$plte = new ParseLinkTemplateEvent($tmpl, $this);
|
|
|
|
send_event($plte);
|
|
|
|
$tmpl = $plte->link;
|
|
|
|
}
|
2007-11-04 08:16:41 +00:00
|
|
|
|
2015-08-02 19:39:41 +00:00
|
|
|
static $flexihash = null;
|
|
|
|
static $fh_last_opts = null;
|
2012-01-16 02:53:38 +00:00
|
|
|
$matches = array();
|
2012-01-16 19:58:03 +00:00
|
|
|
if(preg_match("/(.*){(.*)}(.*)/", $tmpl, $matches)) {
|
2012-01-16 02:53:38 +00:00
|
|
|
$pre = $matches[1];
|
|
|
|
$opts = $matches[2];
|
|
|
|
$post = $matches[3];
|
|
|
|
|
2015-08-02 19:39:41 +00:00
|
|
|
if($opts != $fh_last_opts) {
|
|
|
|
$fh_last_opts = $opts;
|
2016-05-11 22:27:42 +00:00
|
|
|
$flexihash = new Flexihash\Flexihash();
|
2012-01-16 02:53:38 +00:00
|
|
|
foreach(explode(",", $opts) as $opt) {
|
2012-01-17 15:47:58 +00:00
|
|
|
$parts = explode("=", $opt);
|
2013-10-04 21:17:42 +00:00
|
|
|
$parts_count = count($parts);
|
2012-01-17 15:47:58 +00:00
|
|
|
$opt_val = "";
|
|
|
|
$opt_weight = 0;
|
2013-10-04 21:17:42 +00:00
|
|
|
if($parts_count === 2) {
|
2012-01-17 15:47:58 +00:00
|
|
|
$opt_val = $parts[0];
|
|
|
|
$opt_weight = $parts[1];
|
|
|
|
}
|
2013-10-04 21:17:42 +00:00
|
|
|
elseif($parts_count === 1) {
|
2012-01-17 15:47:58 +00:00
|
|
|
$opt_val = $parts[0];
|
|
|
|
$opt_weight = 1;
|
|
|
|
}
|
2015-08-02 19:39:41 +00:00
|
|
|
$flexihash->addTarget($opt_val, $opt_weight);
|
2012-01-16 02:53:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-02 19:39:41 +00:00
|
|
|
$choice = $flexihash->lookup($pre.$post);
|
2012-01-16 02:53:38 +00:00
|
|
|
$tmpl = $pre.$choice.$post;
|
|
|
|
}
|
|
|
|
|
2007-04-16 11:58:25 +00:00
|
|
|
return $tmpl;
|
|
|
|
}
|
2008-10-09 03:28:58 +00:00
|
|
|
|
2014-04-27 19:33:57 +00:00
|
|
|
/**
|
|
|
|
* @param string[] $terms
|
|
|
|
* @return \Querylet
|
|
|
|
*/
|
2009-05-11 14:04:33 +00:00
|
|
|
private static function build_search_querylet($terms) {
|
2015-07-19 18:04:35 +00:00
|
|
|
assert('is_array($terms)');
|
2009-05-11 14:04:33 +00:00
|
|
|
global $database;
|
2009-05-11 10:52:48 +00:00
|
|
|
|
2016-06-07 00:34:38 +00:00
|
|
|
$tag_querylets = array();
|
2015-09-27 20:09:27 +00:00
|
|
|
$img_querylets = array();
|
2016-06-07 00:34:38 +00:00
|
|
|
$positive_tag_count = 0;
|
|
|
|
$negative_tag_count = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Turn a bunch of strings into a bunch of TagQuerylet
|
|
|
|
* and ImgQuerylet objects
|
|
|
|
*/
|
2015-09-27 20:09:27 +00:00
|
|
|
$stpe = new SearchTermParseEvent(null, $terms);
|
|
|
|
send_event($stpe);
|
|
|
|
if ($stpe->is_querylet_set()) {
|
|
|
|
foreach ($stpe->get_querylets() as $querylet) {
|
|
|
|
$img_querylets[] = new ImgQuerylet($querylet, true);
|
|
|
|
}
|
|
|
|
}
|
2009-05-11 14:04:33 +00:00
|
|
|
|
2016-06-07 00:34:38 +00:00
|
|
|
foreach ($terms as $term) {
|
2008-10-09 03:28:58 +00:00
|
|
|
$positive = true;
|
2016-06-07 00:34:38 +00:00
|
|
|
if (is_string($term) && !empty($term) && ($term[0] == '-')) {
|
2008-10-09 03:28:58 +00:00
|
|
|
$positive = false;
|
|
|
|
$term = substr($term, 1);
|
|
|
|
}
|
2016-06-07 00:34:38 +00:00
|
|
|
if (strlen($term) === 0) {
|
2012-01-26 17:16:06 +00:00
|
|
|
continue;
|
|
|
|
}
|
2009-01-04 19:18:37 +00:00
|
|
|
|
2008-10-17 19:58:37 +00:00
|
|
|
$stpe = new SearchTermParseEvent($term, $terms);
|
2008-10-09 03:28:58 +00:00
|
|
|
send_event($stpe);
|
2016-06-07 00:34:38 +00:00
|
|
|
if ($stpe->is_querylet_set()) {
|
|
|
|
foreach ($stpe->get_querylets() as $querylet) {
|
2008-10-17 20:18:38 +00:00
|
|
|
$img_querylets[] = new ImgQuerylet($querylet, $positive);
|
|
|
|
}
|
2016-07-30 21:11:49 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// if the whole match is wild, skip this;
|
|
|
|
// if not, translate into SQL
|
|
|
|
if(str_replace("*", "", $term) != "") {
|
|
|
|
$term = str_replace('_', '\_', $term);
|
|
|
|
$term = str_replace('%', '\%', $term);
|
|
|
|
$term = str_replace('*', '%', $term);
|
|
|
|
$tag_querylets[] = new TagQuerylet($term, $positive);
|
|
|
|
if ($positive) $positive_tag_count++;
|
|
|
|
else $negative_tag_count++;
|
|
|
|
}
|
2008-10-09 03:28:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-07 00:34:38 +00:00
|
|
|
/*
|
|
|
|
* Turn a bunch of Querylet objects into a base query
|
|
|
|
*
|
|
|
|
* Must follow the format
|
|
|
|
*
|
|
|
|
* SELECT images.*
|
|
|
|
* FROM (...) AS images
|
|
|
|
* WHERE (...)
|
|
|
|
*
|
|
|
|
* ie, return a set of images.* columns, and end with a WHERE
|
|
|
|
*/
|
|
|
|
|
|
|
|
// no tags, do a simple search
|
2016-06-19 10:57:01 +00:00
|
|
|
if($positive_tag_count === 0 && $negative_tag_count === 0) {
|
2016-06-06 23:19:41 +00:00
|
|
|
$query = new Querylet("
|
|
|
|
SELECT images.*
|
|
|
|
FROM images
|
|
|
|
WHERE 1=1
|
|
|
|
");
|
2008-10-09 03:28:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// one positive tag (a common case), do an optimised search
|
2016-06-07 00:34:38 +00:00
|
|
|
else if($positive_tag_count === 1 && $negative_tag_count === 0) {
|
2016-06-07 01:05:19 +00:00
|
|
|
# "LIKE" to account for wildcards
|
2012-06-23 23:57:55 +00:00
|
|
|
$query = new Querylet($database->scoreql_to_sql("
|
2016-06-07 00:34:38 +00:00
|
|
|
SELECT *
|
|
|
|
FROM (
|
|
|
|
SELECT images.*
|
|
|
|
FROM images
|
|
|
|
JOIN image_tags ON images.id=image_tags.image_id
|
|
|
|
JOIN tags ON image_tags.tag_id=tags.id
|
2016-06-07 00:39:23 +00:00
|
|
|
WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(:tag)
|
2016-06-07 00:34:38 +00:00
|
|
|
GROUP BY images.id
|
|
|
|
) AS images
|
|
|
|
WHERE 1=1
|
2015-09-27 20:09:27 +00:00
|
|
|
"), array("tag"=>$tag_querylets[0]->tag));
|
2008-10-09 03:28:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// more than one positive tag, or more than zero negative tags
|
|
|
|
else {
|
2016-06-07 00:34:38 +00:00
|
|
|
if($database->get_driver_name() === "mysql")
|
2016-06-07 01:05:19 +00:00
|
|
|
$query = Image::build_ugly_search_querylet($tag_querylets);
|
2016-06-07 00:34:38 +00:00
|
|
|
else
|
2016-06-07 01:05:19 +00:00
|
|
|
$query = Image::build_accurate_search_querylet($tag_querylets);
|
2008-10-09 03:28:58 +00:00
|
|
|
}
|
|
|
|
|
2016-06-07 00:34:38 +00:00
|
|
|
/*
|
|
|
|
* Merge all the image metadata searches into one generic querylet
|
|
|
|
* and append to the base querylet with "AND blah"
|
|
|
|
*/
|
2016-07-03 11:07:54 +00:00
|
|
|
if(!empty($img_querylets)) {
|
2016-06-07 00:34:38 +00:00
|
|
|
$n = 0;
|
|
|
|
$img_sql = "";
|
|
|
|
$img_vars = array();
|
|
|
|
foreach ($img_querylets as $iq) {
|
|
|
|
if ($n++ > 0) $img_sql .= " AND";
|
|
|
|
if (!$iq->positive) $img_sql .= " NOT";
|
|
|
|
$img_sql .= " (" . $iq->qlet->sql . ")";
|
|
|
|
$img_vars = array_merge($img_vars, $iq->qlet->variables);
|
|
|
|
}
|
2016-06-06 23:19:41 +00:00
|
|
|
$query->append_sql(" AND ");
|
2016-06-07 00:34:38 +00:00
|
|
|
$query->append(new Querylet($img_sql, $img_vars));
|
2016-06-06 23:19:41 +00:00
|
|
|
}
|
|
|
|
|
2008-10-09 03:28:58 +00:00
|
|
|
return $query;
|
|
|
|
}
|
2009-05-11 10:52:48 +00:00
|
|
|
|
2010-02-09 02:07:19 +00:00
|
|
|
/**
|
2016-06-07 00:34:38 +00:00
|
|
|
* WARNING: this description is no longer accurate, though it does get across
|
|
|
|
* the general idea - the actual method has a few extra optimisations
|
|
|
|
*
|
|
|
|
* "foo bar -baz user=foo" becomes
|
|
|
|
*
|
|
|
|
* SELECT * FROM images WHERE
|
|
|
|
* images.id IN (SELECT image_id FROM image_tags WHERE tag='foo')
|
|
|
|
* AND images.id IN (SELECT image_id FROM image_tags WHERE tag='bar')
|
|
|
|
* AND NOT images.id IN (SELECT image_id FROM image_tags WHERE tag='baz')
|
|
|
|
* AND images.id IN (SELECT id FROM images WHERE owner_name='foo')
|
|
|
|
*
|
|
|
|
* This is:
|
|
|
|
* A) Incredibly simple:
|
|
|
|
* Each search term maps to a list of image IDs
|
|
|
|
* B) Runs really fast on a good database:
|
|
|
|
* These lists are calculated once, and the set intersection taken
|
|
|
|
* C) Runs really slow on bad databases:
|
|
|
|
* All the subqueries are executed every time for every row in the
|
|
|
|
* images table. Yes, MySQL does suck this much.
|
2015-09-12 10:43:28 +00:00
|
|
|
*
|
2016-06-07 01:05:19 +00:00
|
|
|
* @param TagQuerylet[] $tag_querylets
|
2015-09-27 20:09:27 +00:00
|
|
|
* @return Querylet
|
2010-02-09 02:07:19 +00:00
|
|
|
*/
|
2016-06-07 01:05:19 +00:00
|
|
|
private static function build_accurate_search_querylet($tag_querylets) {
|
2014-03-30 12:26:48 +00:00
|
|
|
global $database;
|
2009-05-11 14:04:33 +00:00
|
|
|
|
2016-06-07 00:34:38 +00:00
|
|
|
$positive_tag_id_array = array();
|
|
|
|
$negative_tag_id_array = array();
|
|
|
|
|
|
|
|
foreach ($tag_querylets as $tq) {
|
|
|
|
$tag_ids = $database->get_col(
|
|
|
|
$database->scoreql_to_sql("
|
|
|
|
SELECT id
|
|
|
|
FROM tags
|
2016-06-07 01:05:19 +00:00
|
|
|
WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(:tag)
|
2016-06-07 00:34:38 +00:00
|
|
|
"),
|
|
|
|
array("tag" => $tq->tag)
|
|
|
|
);
|
|
|
|
if ($tq->positive) {
|
|
|
|
$positive_tag_id_array = array_merge($positive_tag_id_array, $tag_ids);
|
|
|
|
if (count($tag_ids) == 0) {
|
|
|
|
# one of the positive tags had zero results, therefor there
|
|
|
|
# can be no results; "where 1=0" should shortcut things
|
|
|
|
return new Querylet("
|
|
|
|
SELECT images.*
|
|
|
|
FROM images
|
|
|
|
WHERE 1=0
|
|
|
|
");
|
2009-05-11 10:52:48 +00:00
|
|
|
}
|
2016-06-07 00:34:38 +00:00
|
|
|
} else {
|
|
|
|
$negative_tag_id_array = array_merge($negative_tag_id_array, $tag_ids);
|
2009-05-11 10:52:48 +00:00
|
|
|
}
|
2016-06-07 00:34:38 +00:00
|
|
|
}
|
2016-05-22 17:35:37 +00:00
|
|
|
|
2016-06-07 01:05:19 +00:00
|
|
|
assert('$positive_tag_id_array || $negative_tag_id_array');
|
|
|
|
$wheres = array();
|
2016-07-03 11:07:54 +00:00
|
|
|
if (!empty($positive_tag_id_array)) {
|
2016-06-07 00:34:38 +00:00
|
|
|
$positive_tag_id_list = join(', ', $positive_tag_id_array);
|
2016-06-07 01:05:19 +00:00
|
|
|
$wheres[] = "tag_id IN ($positive_tag_id_list)";
|
2016-06-07 00:34:38 +00:00
|
|
|
}
|
2016-07-03 11:07:54 +00:00
|
|
|
if (!empty($negative_tag_id_array)) {
|
2016-06-07 00:34:38 +00:00
|
|
|
$negative_tag_id_list = join(', ', $negative_tag_id_array);
|
2016-06-07 01:05:19 +00:00
|
|
|
$wheres[] = "tag_id NOT IN ($negative_tag_id_list)";
|
2016-06-07 00:34:38 +00:00
|
|
|
}
|
2016-06-07 01:05:19 +00:00
|
|
|
$wheres_str = join(" AND ", $wheres);
|
2016-06-07 00:34:38 +00:00
|
|
|
return new Querylet("
|
|
|
|
SELECT images.*
|
|
|
|
FROM images
|
2016-06-07 01:05:19 +00:00
|
|
|
WHERE images.id IN (
|
|
|
|
SELECT image_id
|
|
|
|
FROM image_tags
|
|
|
|
WHERE $wheres_str
|
|
|
|
GROUP BY image_id
|
|
|
|
HAVING COUNT(image_id) >= :search_score
|
|
|
|
)
|
|
|
|
", array("search_score"=>count($positive_tag_id_array)));
|
2016-06-07 00:34:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* this function exists because mysql is a turd, see the docs for
|
|
|
|
* build_accurate_search_querylet() for a full explanation
|
|
|
|
*
|
2016-06-07 01:05:19 +00:00
|
|
|
* @param TagQuerylet[] $tag_querylets
|
2016-06-07 00:34:38 +00:00
|
|
|
* @return Querylet
|
|
|
|
*/
|
2016-06-07 01:05:19 +00:00
|
|
|
private static function build_ugly_search_querylet($tag_querylets) {
|
2016-06-07 00:34:38 +00:00
|
|
|
global $database;
|
2009-05-11 10:52:48 +00:00
|
|
|
|
2016-06-07 01:05:19 +00:00
|
|
|
$positive_tag_count = 0;
|
|
|
|
foreach($tag_querylets as $tq) {
|
|
|
|
if($tq->positive) $positive_tag_count++;
|
|
|
|
}
|
|
|
|
|
2016-06-07 00:34:38 +00:00
|
|
|
// only negative tags - shortcut to fail
|
|
|
|
if($positive_tag_count == 0) {
|
|
|
|
// TODO: This isn't currently implemented.
|
|
|
|
// SEE: https://github.com/shish/shimmie2/issues/66
|
|
|
|
return new Querylet("
|
2016-06-06 23:19:41 +00:00
|
|
|
SELECT images.*
|
|
|
|
FROM images
|
2016-06-07 00:34:38 +00:00
|
|
|
WHERE 1=0
|
2016-06-06 23:19:41 +00:00
|
|
|
");
|
2009-05-11 10:52:48 +00:00
|
|
|
}
|
|
|
|
|
2016-06-07 00:50:56 +00:00
|
|
|
// merge all the tag querylets into one generic one
|
|
|
|
$sql = "0";
|
|
|
|
$terms = array();
|
|
|
|
foreach($tag_querylets as $tq) {
|
|
|
|
$sign = $tq->positive ? "+" : "-";
|
2016-06-07 01:05:19 +00:00
|
|
|
$sql .= ' '.$sign.' IF(SUM(tag LIKE :tag'.Image::$tag_n.'), 1, 0)';
|
2016-06-07 00:50:56 +00:00
|
|
|
$terms['tag'.Image::$tag_n] = $tq->tag;
|
|
|
|
Image::$tag_n++;
|
|
|
|
}
|
|
|
|
$tag_search = new Querylet($sql, $terms);
|
|
|
|
|
2016-06-07 00:34:38 +00:00
|
|
|
$tag_id_array = array();
|
|
|
|
|
2016-06-07 01:05:19 +00:00
|
|
|
foreach($tag_querylets as $tq) {
|
2016-06-07 00:34:38 +00:00
|
|
|
$tag_ids = $database->get_col(
|
|
|
|
$database->scoreql_to_sql("
|
|
|
|
SELECT id
|
|
|
|
FROM tags
|
2016-06-07 01:05:19 +00:00
|
|
|
WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(:tag)
|
2016-06-07 00:34:38 +00:00
|
|
|
"),
|
2016-06-07 01:05:19 +00:00
|
|
|
array("tag" => $tq->tag)
|
2016-06-07 00:34:38 +00:00
|
|
|
);
|
|
|
|
$tag_id_array = array_merge($tag_id_array, $tag_ids);
|
2009-05-11 10:52:48 +00:00
|
|
|
|
2016-06-07 01:05:19 +00:00
|
|
|
if($tq->positive && count($tag_ids) == 0) {
|
2016-06-07 00:34:38 +00:00
|
|
|
# one of the positive tags had zero results, therefor there
|
|
|
|
# can be no results; "where 1=0" should shortcut things
|
|
|
|
return new Querylet("
|
2009-05-11 10:52:48 +00:00
|
|
|
SELECT images.*
|
|
|
|
FROM images
|
|
|
|
WHERE 1=0
|
|
|
|
");
|
|
|
|
}
|
2016-06-06 23:19:41 +00:00
|
|
|
}
|
|
|
|
|
2015-08-02 18:29:25 +00:00
|
|
|
Image::$tag_n = 0;
|
2016-06-07 00:34:38 +00:00
|
|
|
return new Querylet('
|
|
|
|
SELECT *
|
|
|
|
FROM (
|
2016-06-07 01:05:19 +00:00
|
|
|
SELECT images.*, ('.$tag_search->sql.') AS score
|
2016-06-07 00:34:38 +00:00
|
|
|
FROM images
|
|
|
|
LEFT JOIN image_tags ON image_tags.image_id = images.id
|
|
|
|
JOIN tags ON image_tags.tag_id = tags.id
|
|
|
|
WHERE tags.id IN (' . join(', ', $tag_id_array) . ')
|
|
|
|
GROUP BY images.id
|
|
|
|
HAVING score = :score
|
|
|
|
) AS images
|
|
|
|
WHERE 1=1
|
|
|
|
', array_merge(
|
|
|
|
$tag_search->variables,
|
|
|
|
array("score"=>$positive_tag_count)
|
|
|
|
));
|
2009-05-11 10:52:48 +00:00
|
|
|
}
|
2009-01-04 13:53:14 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-29 05:33:03 +00:00
|
|
|
* Class Tag
|
|
|
|
*
|
2009-07-19 07:38:13 +00:00
|
|
|
* A class for organising the tag related functions.
|
|
|
|
*
|
|
|
|
* All the methods are static, one should never actually use a tag object.
|
2014-04-29 05:33:03 +00:00
|
|
|
*
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2009-01-04 18:39:11 +00:00
|
|
|
class Tag {
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2016-07-30 21:11:49 +00:00
|
|
|
* @param string[] $tags
|
2015-09-27 01:17:44 +00:00
|
|
|
* @return string
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2016-07-30 21:11:49 +00:00
|
|
|
public static function implode($tags) {
|
|
|
|
assert('is_array($tags)');
|
|
|
|
|
|
|
|
sort($tags);
|
|
|
|
$tags = implode(' ', $tags);
|
|
|
|
|
|
|
|
return $tags;
|
2009-01-04 18:39:11 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2016-07-30 21:11:49 +00:00
|
|
|
* Turn a human-supplied string into a valid tag array.
|
2014-04-27 19:33:57 +00:00
|
|
|
*
|
2016-07-30 21:11:49 +00:00
|
|
|
* @param string $tags
|
|
|
|
* @param bool $tagme add "tagme" if the string is empty
|
2015-09-27 01:17:44 +00:00
|
|
|
* @return string[]
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2013-08-04 17:11:02 +00:00
|
|
|
public static function explode($tags, $tagme=true) {
|
2016-07-30 21:11:49 +00:00
|
|
|
global $database;
|
|
|
|
assert('is_string($tags)');
|
2014-02-22 20:42:09 +00:00
|
|
|
|
2016-07-30 21:11:49 +00:00
|
|
|
$tags = explode(' ', trim($tags));
|
2009-01-24 11:32:48 +00:00
|
|
|
|
2016-07-30 21:11:49 +00:00
|
|
|
/* sanitise by removing invisible / dodgy characters */
|
2009-01-24 11:32:48 +00:00
|
|
|
$tag_array = array();
|
|
|
|
foreach($tags as $tag) {
|
2016-07-30 21:11:49 +00:00
|
|
|
$tag = preg_replace("/\s/", "", $tag); # whitespace
|
|
|
|
$tag = preg_replace('/\x20(\x0e|\x0f)/', '', $tag); # unicode RTL
|
|
|
|
$tag = preg_replace("/\.+/", ".", $tag); # strings of dots?
|
|
|
|
$tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes?
|
2012-03-11 14:54:14 +00:00
|
|
|
$tag = trim($tag, ", \t\n\r\0\x0B");
|
2016-07-30 21:11:49 +00:00
|
|
|
|
2016-08-29 08:21:23 +00:00
|
|
|
if(mb_strlen($tag, 'UTF-8') > 255){
|
|
|
|
flash_message("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-30 21:11:49 +00:00
|
|
|
if(!empty($tag)) {
|
2009-01-24 11:32:48 +00:00
|
|
|
$tag_array[] = $tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-30 21:11:49 +00:00
|
|
|
/* if user supplied a blank string, add "tagme" */
|
2013-10-04 21:17:42 +00:00
|
|
|
if(count($tag_array) === 0 && $tagme) {
|
2009-01-24 11:32:48 +00:00
|
|
|
$tag_array = array("tagme");
|
|
|
|
}
|
|
|
|
|
2016-07-30 21:11:49 +00:00
|
|
|
/* resolve aliases */
|
2009-01-24 11:32:48 +00:00
|
|
|
$new = array();
|
2014-01-16 03:28:23 +00:00
|
|
|
$i = 0;
|
2016-07-30 21:11:49 +00:00
|
|
|
$tag_count = count($tag_array);
|
2014-01-16 03:28:23 +00:00
|
|
|
while($i<$tag_count) {
|
2016-07-30 21:11:49 +00:00
|
|
|
$tag = $tag_array[$i];
|
|
|
|
$negative = '';
|
|
|
|
if(!empty($tag) && ($tag[0] == '-')) {
|
|
|
|
$negative = '-';
|
|
|
|
$tag = substr($tag, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
$newtags = $database->get_one(
|
|
|
|
$database->scoreql_to_sql("
|
|
|
|
SELECT newtag
|
|
|
|
FROM aliases
|
|
|
|
WHERE SCORE_STRNORM(oldtag)=SCORE_STRNORM(:tag)
|
|
|
|
"),
|
|
|
|
array("tag"=>$tag)
|
|
|
|
);
|
|
|
|
if(empty($newtags)) {
|
|
|
|
//tag has no alias, use old tag
|
|
|
|
$aliases = array($tag);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$aliases = Tag::explode($newtags);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach($aliases as $alias) {
|
|
|
|
if(!in_array($alias, $new)) {
|
|
|
|
if($tag == $alias) {
|
|
|
|
$new[] = $negative.$alias;
|
|
|
|
}
|
|
|
|
elseif(!in_array($alias, $tag_array)) {
|
|
|
|
$tag_array[] = $negative.$alias;
|
2014-01-16 03:28:23 +00:00
|
|
|
$tag_count++;
|
|
|
|
}
|
|
|
|
}
|
2009-01-24 11:32:48 +00:00
|
|
|
}
|
2014-01-16 03:28:23 +00:00
|
|
|
$i++;
|
2009-01-24 11:32:48 +00:00
|
|
|
}
|
2013-08-04 17:11:02 +00:00
|
|
|
|
2016-07-30 21:11:49 +00:00
|
|
|
/* remove any duplicate tags */
|
|
|
|
$tag_array = array_iunique($new);
|
|
|
|
|
|
|
|
/* tidy up */
|
|
|
|
sort($tag_array);
|
|
|
|
|
|
|
|
return $tag_array;
|
2009-01-24 11:32:48 +00:00
|
|
|
}
|
2009-01-04 18:39:11 +00:00
|
|
|
}
|
|
|
|
|
2008-10-09 03:28:58 +00:00
|
|
|
|
2009-01-04 13:53:14 +00:00
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
|
|
|
|
* Misc functions *
|
|
|
|
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
|
|
|
* Move a file from PHP's temporary area into shimmie's image storage
|
2014-04-27 19:33:57 +00:00
|
|
|
* hierarchy, or throw an exception trying.
|
|
|
|
*
|
|
|
|
* @param DataUploadEvent $event
|
|
|
|
* @throws UploadException
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2012-02-02 13:58:48 +00:00
|
|
|
function move_upload_to_archive(DataUploadEvent $event) {
|
2010-02-02 00:29:38 +00:00
|
|
|
$target = warehouse_path("images", $event->hash);
|
|
|
|
if(!@copy($event->tmpname, $target)) {
|
2016-07-30 21:11:49 +00:00
|
|
|
$errors = error_get_last();
|
|
|
|
throw new UploadException(
|
|
|
|
"Failed to copy file from uploads ({$event->tmpname}) to archive ($target): ".
|
|
|
|
"{$errors['type']} / {$errors['message']}"
|
|
|
|
);
|
2009-01-04 13:53:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-24 15:08:26 +00:00
|
|
|
/**
|
|
|
|
* Add a directory full of images
|
|
|
|
*
|
|
|
|
* @param $base string
|
2015-08-23 15:09:52 +00:00
|
|
|
* @return array
|
2015-05-24 15:08:26 +00:00
|
|
|
*/
|
2015-09-27 20:09:27 +00:00
|
|
|
function add_dir($base) {
|
2015-08-23 15:09:52 +00:00
|
|
|
$results = array();
|
2015-05-24 15:08:26 +00:00
|
|
|
|
|
|
|
foreach(list_files($base) as $full_path) {
|
|
|
|
$short_path = str_replace($base, "", $full_path);
|
|
|
|
$filename = basename($full_path);
|
|
|
|
|
|
|
|
$tags = path_to_tags($short_path);
|
2015-08-23 15:09:52 +00:00
|
|
|
$result = "$short_path (".str_replace(" ", ", ", $tags).")... ";
|
2015-05-24 15:08:26 +00:00
|
|
|
try {
|
|
|
|
add_image($full_path, $filename, $tags);
|
2015-08-23 15:09:52 +00:00
|
|
|
$result .= "ok";
|
2015-05-24 15:08:26 +00:00
|
|
|
}
|
|
|
|
catch(UploadException $ex) {
|
2015-08-23 15:09:52 +00:00
|
|
|
$result .= "failed: ".$ex->getMessage();
|
2015-05-24 15:08:26 +00:00
|
|
|
}
|
2015-08-23 15:09:52 +00:00
|
|
|
$results[] = $result;
|
2015-05-24 15:08:26 +00:00
|
|
|
}
|
|
|
|
|
2015-08-23 15:09:52 +00:00
|
|
|
return $results;
|
2015-05-24 15:08:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-09-27 01:17:44 +00:00
|
|
|
* @param string $tmpname
|
|
|
|
* @param string $filename
|
|
|
|
* @param string $tags
|
2015-05-24 15:08:26 +00:00
|
|
|
* @throws UploadException
|
|
|
|
*/
|
2015-09-27 20:09:27 +00:00
|
|
|
function add_image($tmpname, $filename, $tags) {
|
2015-05-24 15:08:26 +00:00
|
|
|
assert(file_exists($tmpname));
|
|
|
|
|
|
|
|
$pathinfo = pathinfo($filename);
|
|
|
|
if(!array_key_exists('extension', $pathinfo)) {
|
|
|
|
throw new UploadException("File has no extension");
|
|
|
|
}
|
|
|
|
$metadata = array();
|
|
|
|
$metadata['filename'] = $pathinfo['basename'];
|
|
|
|
$metadata['extension'] = $pathinfo['extension'];
|
|
|
|
$metadata['tags'] = $tags;
|
|
|
|
$metadata['source'] = null;
|
|
|
|
$event = new DataUploadEvent($tmpname, $metadata);
|
|
|
|
send_event($event);
|
|
|
|
if($event->image_id == -1) {
|
|
|
|
throw new UploadException("File type not recognised");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-19 07:38:13 +00:00
|
|
|
/**
|
2014-04-24 23:08:23 +00:00
|
|
|
* Given a full size pair of dimensions, return a pair scaled down to fit
|
2009-07-19 07:38:13 +00:00
|
|
|
* into the configured thumbnail square, with ratio intact
|
2014-04-26 09:01:49 +00:00
|
|
|
*
|
|
|
|
* @param int $orig_width
|
|
|
|
* @param int $orig_height
|
2015-09-27 01:17:44 +00:00
|
|
|
* @return int[]
|
2009-07-19 07:38:13 +00:00
|
|
|
*/
|
2012-02-02 13:58:48 +00:00
|
|
|
function get_thumbnail_size(/*int*/ $orig_width, /*int*/ $orig_height) {
|
2009-01-04 13:53:14 +00:00
|
|
|
global $config;
|
|
|
|
|
2013-10-04 21:17:42 +00:00
|
|
|
if($orig_width === 0) $orig_width = 192;
|
|
|
|
if($orig_height === 0) $orig_height = 192;
|
2009-01-04 13:53:14 +00:00
|
|
|
|
2011-02-13 11:18:23 +00:00
|
|
|
if($orig_width > $orig_height * 5) $orig_width = $orig_height * 5;
|
|
|
|
if($orig_height > $orig_width * 5) $orig_height = $orig_width * 5;
|
|
|
|
|
2009-01-04 13:53:14 +00:00
|
|
|
$max_width = $config->get_int('thumb_width');
|
|
|
|
$max_height = $config->get_int('thumb_height');
|
|
|
|
|
|
|
|
$xscale = ($max_height / $orig_height);
|
|
|
|
$yscale = ($max_width / $orig_width);
|
|
|
|
$scale = ($xscale < $yscale) ? $xscale : $yscale;
|
|
|
|
|
|
|
|
if($scale > 1 && $config->get_bool('thumb_upscale')) {
|
|
|
|
return array((int)$orig_width, (int)$orig_height);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return array((int)($orig_width*$scale), (int)($orig_height*$scale));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|