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 640 x480 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 *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-03-14 12:44:58 +00:00
2012-02-02 04:35:26 +00:00
require_once " lib/flexihash.php " ;
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 ;
2014-04-24 09:25:12 +00:00
public $owner_id , $owner_ip ;
2015-09-27 20:09:27 +00:00
public $posted ;
2014-04-24 08:30:58 +00:00
public $source ;
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 ;
}
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 ;
$tags = Tag :: resolve_aliases ( $tags );
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 ])) {
2012-02-12 07:30:16 +00:00
$term = Tag :: resolve_alias ( $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) " ),
2012-02-12 07:30:16 +00:00
array ( " tag " => $term ));
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 ) {
2012-01-11 20:08:27 +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 ) {
$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 )) {
2011-01-01 15:28:30 +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 () {
2015-06-01 09:57:56 +00:00
return $this -> get_link ( 'image_ilink' , '_images/$hash/$id%20-%20$tags.$ext' , 'image/$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
* 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
WHERE id IN ( SELECT tag_id FROM image_tags WHERE image_id = : id ) " , array( " id " => $this->id )
);
}
2011-01-01 15:58:09 +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 (
2012-06-23 23:57:55 +00:00
$database -> scoreql_to_sql (
2012-01-21 00:17:07 +00:00
" SELECT id FROM tags WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag) "
),
2011-01-01 15:58:09 +00:00
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
$database -> execute (
" INSERT INTO image_tags(image_id, tag_id) VALUES(:iid, :tid) " ,
array ( " iid " => $this -> id , " tid " => $id ));
}
2009-05-11 14:04:33 +00:00
$database -> execute (
2012-06-23 23:57:55 +00:00
$database -> scoreql_to_sql (
2012-01-21 00:17:07 +00:00
" 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 .
*
* @ param [] $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 ;
$flexihash = new 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
2015-09-27 20:09:27 +00:00
$terms = Tag :: resolve_aliases ( $terms );
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-06-07 00:34:38 +00:00
} else {
2013-03-03 18:26:47 +00:00
$expansions = Tag :: resolve_wildcard ( $term );
2016-06-07 00:34:38 +00:00
if ( $expansions ) {
if ( $positive ) $positive_tag_count ++ ;
else $negative_tag_count ++ ;
}
foreach ( $expansions as $expanded_term ) {
2014-04-24 05:36:30 +00:00
$tag_querylets [] = new TagQuerylet ( $expanded_term , $positive );
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
if ( $positive_tag_count + $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 ) {
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 " )
$query = Image :: build_ugly_search_querylet (
$tag_querylets ,
$positive_tag_count
);
else
$query = Image :: build_accurate_search_querylet (
$tag_querylets ,
$positive_tag_count
2015-09-27 20:09:27 +00:00
);
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 "
*/
if ( $img_querylets ) {
$n = 0 ;
$img_sql = " " ;
$img_vars = array ();
foreach ( $img_querylets as $iq ) {
if ( $n ++ > 0 ) $img_sql .= " AND " ;
if ( ! $iq -> positive ) $img_sql .= " NOT " ;
$img_sql .= " ( " . $iq -> qlet -> sql . " ) " ;
$img_vars = array_merge ( $img_vars , $iq -> qlet -> variables );
}
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 00:34:38 +00:00
* @ param array $tag_querylets
* @ param int $positive_tag_count
2015-09-27 20:09:27 +00:00
* @ return Querylet
2010-02-09 02:07:19 +00:00
*/
2016-06-07 00:34:38 +00:00
private static function build_accurate_search_querylet (
$tag_querylets ,
$positive_tag_count
) {
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
WHERE SCORE_STRNORM ( tag ) = SCORE_STRNORM ( : tag )
" ),
array ( " tag " => $tq -> tag )
);
if ( $tq -> positive ) {
$positive_tag_id_array = array_merge ( $positive_tag_id_array , $tag_ids );
if ( count ( $tag_ids ) == 0 ) {
# one of the positive tags had zero results, therefor there
# can be no results; "where 1=0" should shortcut things
return new Querylet ( "
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 00:34:38 +00:00
$have_pos = count ( $positive_tag_id_array ) > 0 ;
$have_neg = count ( $negative_tag_id_array ) > 0 ;
$sql = " " ;
if ( $have_pos ) {
$positive_tag_id_list = join ( ', ' , $positive_tag_id_array );
$sql .= "
SELECT image_id
FROM image_tags
WHERE tag_id IN ( $positive_tag_id_list )
GROUP BY image_id
HAVING COUNT ( image_id ) >= $positive_tag_count
" ;
2009-05-11 10:52:48 +00:00
}
2016-06-07 00:34:38 +00:00
if ( $have_pos && $have_neg ) {
$sql .= " EXCEPT " ;
}
if ( $have_neg ) {
$negative_tag_id_list = join ( ', ' , $negative_tag_id_array );
$sql .= "
SELECT image_id
FROM image_tags
WHERE tag_id IN ( $negative_tag_id_list )
" ;
}
return new Querylet ( "
SELECT images .*
FROM images
WHERE images . id IN ( $sql )
" );
}
/**
* this function exists because mysql is a turd , see the docs for
* build_accurate_search_querylet () for a full explanation
*
* @ param array $tag_querylets
* @ param int $positive_tag_count
* @ return Querylet
*/
private static function build_ugly_search_querylet (
$tag_querylets ,
$positive_tag_count
) {
global $database ;
2009-05-11 10:52:48 +00:00
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 ? " + " : " - " ;
$sql .= ' ' . $sign . ' IF(tag LIKE :tag' . Image :: $tag_n . ', 1, 0)' ;
$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 ();
$x = 0 ;
foreach ( $tag_search -> variables as $tag ) {
$tag_ids = $database -> get_col (
$database -> scoreql_to_sql ( "
SELECT id
FROM tags
WHERE SCORE_STRNORM ( tag ) = SCORE_STRNORM ( : tag )
" ),
array ( " tag " => $tag )
);
$tag_id_array = array_merge ( $tag_id_array , $tag_ids );
2009-05-11 10:52:48 +00:00
2016-06-07 00:34:38 +00:00
if ( $tag_querylets [ $x ] -> positive && count ( $tag_ids ) == 0 ) {
# one of the positive tags had zero results, therefor there
# can be no results; "where 1=0" should shortcut things
return new Querylet ( "
2009-05-11 10:52:48 +00:00
SELECT images .*
FROM images
WHERE 1 = 0
" );
}
2016-06-07 00:34:38 +00:00
$x ++ ;
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 (
SELECT images .* , SUM ( '.$tag_search->sql.' ) AS score
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
/**
* Remove any excess fluff from a user - input tag
2014-04-26 03:22:34 +00:00
*
* @ param string $tag
2015-09-27 01:17:44 +00:00
* @ return string
2009-07-19 07:38:13 +00:00
*/
2009-01-04 18:39:11 +00:00
public static function sanitise ( $tag ) {
2015-07-19 18:04:35 +00:00
assert ( 'is_string($tag)' );
2015-04-26 12:02:17 +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?
2009-01-04 18:39:11 +00:00
return $tag ;
}
2009-07-19 07:38:13 +00:00
/**
2014-04-27 19:33:57 +00:00
* Turn any string or array into a valid tag array .
*
* @ param string | string [] $tags
* @ param bool $tagme
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 ) {
2015-07-19 18:04:35 +00:00
assert ( 'is_string($tags) || is_array($tags)' );
2014-02-22 20:42:09 +00:00
2009-01-24 11:32:48 +00:00
if ( is_string ( $tags )) {
2013-08-04 17:11:02 +00:00
$tags = explode ( ' ' , trim ( $tags ));
2009-01-24 11:32:48 +00:00
}
2012-01-11 20:57:00 +00:00
//else if(is_array($tags)) {
2009-01-24 11:32:48 +00:00
// do nothing
2012-01-11 20:57:00 +00:00
//}
2009-01-24 11:32:48 +00:00
$tag_array = array ();
foreach ( $tags as $tag ) {
2012-03-11 14:54:14 +00:00
$tag = trim ( $tag , " , \t \n \r \0 \x0B " );
2012-01-13 04:07:14 +00:00
if ( is_string ( $tag ) && ! empty ( $tag )) {
2009-01-24 11:32:48 +00:00
$tag_array [] = $tag ;
}
}
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 " );
}
2015-10-08 17:25:03 +00:00
$tag_array = array_iunique ( $tag_array ); //remove duplicate tags
2011-01-01 18:40:21 +00:00
sort ( $tag_array );
2009-01-24 11:32:48 +00:00
return $tag_array ;
}
2014-04-26 09:01:49 +00:00
/**
2014-04-27 19:33:57 +00:00
* @ param string | string [] $tags
2014-04-26 09:01:49 +00:00
* @ return string
*/
2009-08-24 02:33:51 +00:00
public static function implode ( $tags ) {
2015-07-19 18:04:35 +00:00
assert ( 'is_string($tags) || is_array($tags)' );
2009-08-24 02:33:51 +00:00
2012-01-11 20:57:00 +00:00
if ( is_array ( $tags )) {
2011-01-01 18:40:21 +00:00
sort ( $tags );
2009-08-24 02:33:51 +00:00
$tags = implode ( ' ' , $tags );
}
2012-01-11 20:57:00 +00:00
//else if(is_string($tags)) {
// do nothing
//}
2009-08-24 02:33:51 +00:00
return $tags ;
}
2014-04-26 09:01:49 +00:00
/**
* @ param string $tag
* @ return string
*/
2009-01-04 18:39:11 +00:00
public static function resolve_alias ( $tag ) {
2015-07-19 18:04:35 +00:00
assert ( 'is_string($tag)' );
2015-08-12 05:11:21 +00:00
global $database ;
2009-01-04 18:39:11 +00:00
2013-08-04 17:19:23 +00:00
$negative = false ;
if ( ! empty ( $tag ) && ( $tag [ 0 ] == '-' )) {
$negative = true ;
$tag = substr ( $tag , 1 );
}
2015-08-12 05:11:21 +00:00
2011-01-22 15:51:55 +00:00
$newtag = $database -> get_one (
2012-06-23 23:57:55 +00:00
$database -> scoreql_to_sql ( " SELECT newtag FROM aliases WHERE SCORE_STRNORM(oldtag)=SCORE_STRNORM(:tag) " ),
2015-08-12 05:11:21 +00:00
array ( " tag " => $tag )
);
2013-08-04 17:19:23 +00:00
if ( empty ( $newtag )) {
2015-08-12 05:11:21 +00:00
//tag has no alias, use old tag
2013-08-04 17:19:23 +00:00
$newtag = $tag ;
2009-01-04 18:39:11 +00:00
}
2015-08-12 05:11:21 +00:00
return ! $negative ? $newtag : preg_replace ( " /( \ S+)/ " , " - $ 1 " , $newtag );
2009-01-04 18:39:11 +00:00
}
2014-04-27 19:33:57 +00:00
/**
* @ param string $tag
* @ return array
*/
2009-01-04 18:39:11 +00:00
public static function resolve_wildcard ( $tag ) {
2013-03-03 18:26:47 +00:00
// if there is no wildcard, return the tag
if ( strpos ( $tag , " * " ) === false ) {
2009-01-04 18:39:11 +00:00
return array ( $tag );
}
2013-03-03 18:26:47 +00:00
// if the whole match is wild, return null to save the database
2013-03-03 18:34:27 +00:00
else if ( str_replace ( " * " , " " , $tag ) == " " ) {
2013-03-03 18:26:47 +00:00
return array ();
}
// else find some matches
2009-01-04 18:39:11 +00:00
else {
global $database ;
2013-03-03 18:26:47 +00:00
$db_wild_tag = str_replace ( " % " , " \ % " , $tag );
2014-03-17 22:05:37 +00:00
$db_wild_tag = str_replace ( " * " , " % " , $db_wild_tag );
2015-09-27 20:09:27 +00:00
$newtags = $database -> get_col (
$database -> scoreql_to_sql ( " SELECT tag FROM tags WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(?) " ),
array ( $db_wild_tag )
);
2009-01-04 18:39:11 +00:00
if ( count ( $newtags ) > 0 ) {
$resolved = $newtags ;
} else {
$resolved = array ( $tag );
}
return $resolved ;
}
}
2009-01-24 11:32:48 +00:00
2012-02-04 20:35:21 +00:00
/**
* This function takes a list ( array ) of tags and changes any tags that have aliases
*
2014-04-27 19:33:57 +00:00
* @ param string [] $tags Array of tags
* @ return array
2012-02-04 20:35:21 +00:00
*/
2013-08-04 17:13:50 +00:00
public static function resolve_aliases ( $tags ) {
2015-07-19 18:04:35 +00:00
assert ( 'is_array($tags)' );
2013-08-04 17:11:02 +00:00
2009-01-24 11:32:48 +00:00
$new = array ();
2014-01-16 03:28:23 +00:00
$i = 0 ;
$tag_count = count ( $tags );
while ( $i < $tag_count ) {
2015-10-08 17:28:00 +00:00
$aliases = Tag :: explode ( Tag :: resolve_alias ( $tags [ $i ]), FALSE );
2014-01-16 03:28:23 +00:00
foreach ( $aliases as $alias ){
if ( ! in_array ( $alias , $new )){
if ( $tags [ $i ] == $alias ){
$new [] = $alias ;
} elseif ( ! in_array ( $alias , $tags )){
$tags [] = $alias ;
$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
2009-01-24 11:32:48 +00:00
$new = array_iunique ( $new ); // remove any duplicate tags
return $new ;
}
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
* @ return bool
* @ 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 )) {
2011-11-08 11:02:04 +00:00
$errors = error_get_last (); // note: requires php 5.2
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
}
return true ;
}
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 ));
}
}