422 lines
14 KiB
PHP
422 lines
14 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Holds data specific to a specific thumbnail
|
|
*
|
|
* @author drossiter
|
|
*/
|
|
class DG_Thumb {
|
|
|
|
/**
|
|
* TODO: Replace w/ https://codex.wordpress.org/Class_Reference/WP_Object_Cache
|
|
* @var DG_Thumb[] The cached copy of thumbs.
|
|
*/
|
|
private static $thumbs = null;
|
|
|
|
/**
|
|
* @var string The meta key identifying DG thumbs.
|
|
*/
|
|
private static $meta_key = '_dg_thumbnail';
|
|
|
|
/**
|
|
* @var int The DB row ID.
|
|
*/
|
|
private $meta_id;
|
|
|
|
/**
|
|
* @var int The post (attachment) ID.
|
|
*/
|
|
private $post_id;
|
|
|
|
/**
|
|
* @return int The post ID.
|
|
*/
|
|
public function getPostId() {
|
|
return $this->post_id;
|
|
}
|
|
|
|
/**
|
|
* @param $post_id int The post ID.
|
|
*/
|
|
public function setPostId($post_id) {
|
|
$this->post_id = $post_id;
|
|
}
|
|
|
|
/**
|
|
* @var string The thumb dimensions (format: WIDTHxHEIGHT).
|
|
*/
|
|
private $dimensions = '';
|
|
|
|
/**
|
|
* @return string The dimensions (WIDTHxHEIGHT).
|
|
*/
|
|
public function getDimensions() {
|
|
return $this->dimensions;
|
|
}
|
|
|
|
/**
|
|
* @param $dimensions string The dimensions (WIDTHxHEIGHT).
|
|
*/
|
|
public function setDimensions($dimensions) {
|
|
$this->dimensions = $dimensions;
|
|
}
|
|
|
|
/**
|
|
* @var string The path relative to the WP uploads directory.
|
|
*/
|
|
private $relative_path = '';
|
|
|
|
/**
|
|
* @return string The path relative to the WP uploads directory.
|
|
*/
|
|
public function getRelativePath() {
|
|
return $this->relative_path;
|
|
}
|
|
|
|
/**
|
|
* @param $relative_path string The path relative to the WP uploads directory.
|
|
*/
|
|
public function setRelativePath($relative_path) {
|
|
$this->relative_path = $relative_path;
|
|
}
|
|
|
|
/**
|
|
* @var int The time when thumbnail was generated.
|
|
*/
|
|
private $timestamp;
|
|
|
|
/**
|
|
* @return int The time when thumbnail was generated.
|
|
*/
|
|
public function getTimestamp() {
|
|
return $this->timestamp;
|
|
}
|
|
|
|
/**
|
|
* @param $timestamp int The time when thumbnail was generated.
|
|
*/
|
|
public function setTimestamp($timestamp) {
|
|
$this->timestamp = $timestamp;
|
|
}
|
|
|
|
/**
|
|
* @var string The function used in generating this thumb.
|
|
*/
|
|
private $generator = '';
|
|
|
|
/**
|
|
* @return string The function used in generating this thumb.
|
|
*/
|
|
public function getGenerator() {
|
|
return $this->generator;
|
|
}
|
|
|
|
/**
|
|
* @param $generator string The function used in generating this thumb.
|
|
*/
|
|
public function setGenerator($generator) {
|
|
$this->generator = $generator;
|
|
}
|
|
|
|
/**
|
|
* DG_Thumb constructor.
|
|
* @param $db_row object The result of querying WP postmeta.
|
|
*/
|
|
public function __construct($db_row = null) {
|
|
if ( is_null ($db_row) ) return;
|
|
|
|
$this->meta_id = $db_row->meta_id;
|
|
$this->post_id = $db_row->post_id;
|
|
$this->setMetaValue( $db_row->meta_value );
|
|
}
|
|
|
|
/**
|
|
* Meta value is in the following format: [width]x[height]:[timestamp]:[path]:[generator].
|
|
* Note that generator may contain colons, so parsing of this field must be done carefully.
|
|
*
|
|
* @param $meta_value string Populates the dimensions and path from meta_value.
|
|
*/
|
|
private function setMetaValue($meta_value) {
|
|
$split = explode( ':', $meta_value, 4 );
|
|
$this->dimensions = $split[0];
|
|
$this->timestamp = absint( $split[1] );
|
|
$this->relative_path = $split[2];
|
|
$this->generator = $split[3];
|
|
}
|
|
|
|
/**
|
|
* Meta value is in the following format: [width]x[height]:[timestamp]:[path]:[generator].
|
|
*
|
|
* @return string The meta_value generated from the dimensions & path fields.
|
|
*/
|
|
private function getMetaValue() {
|
|
return $this->dimensions . ':' . $this->timestamp . ':' . $this->relative_path . ':' . $this->generator;
|
|
}
|
|
|
|
/**
|
|
* @return int Parses dimensions string pulling out the width.
|
|
*/
|
|
public function getWidth() {
|
|
$split = explode( 'x', $this->dimensions, 2 );
|
|
return absint( $split[0] );
|
|
}
|
|
|
|
/**
|
|
* @return int Parses dimensions string pulling out the height.
|
|
*/
|
|
public function getHeight() {
|
|
$split = explode( 'x', $this->dimensions, 2 );
|
|
return absint( $split[1] );
|
|
}
|
|
|
|
/**
|
|
* @return string Get fully-qualified URL pointing to this thumb.
|
|
*/
|
|
public function getUrl() {
|
|
$upload_dir = wp_upload_dir();
|
|
return $upload_dir['baseurl'] . '/' . $this->relative_path;
|
|
}
|
|
|
|
/**
|
|
* @return string Get fully-qualified system path pointing to this thumb.
|
|
*/
|
|
public function getPath() {
|
|
$upload_dir = wp_upload_dir();
|
|
return $upload_dir['basedir'] . DIRECTORY_SEPARATOR . $this->relative_path;
|
|
}
|
|
|
|
/**
|
|
* @return bool Whether this instance represents a successful thumb generation.
|
|
*/
|
|
public function isSuccess() {
|
|
return ! empty( $this->relative_path ) && ! DG_Util::startsWith( $this->getPath(), DG_PATH );
|
|
}
|
|
|
|
/**
|
|
* Saves thumb to DB. Either an UPDATE or an INSERT is performed depending on whether meta_id isset and
|
|
* updates the instance meta_id if INSERT is performed.
|
|
*/
|
|
public function save() {
|
|
global $wpdb;
|
|
|
|
// thumbs are immutable -- once created they can only be read or deleted
|
|
if ( isset( $this->meta_id ) ) return;
|
|
|
|
// don't re-save identical thumb
|
|
if ( isset( self::$thumbs[$this->post_id][$this->dimensions] ) &&
|
|
$this == self::$thumbs[$this->post_id][$this->dimensions] ) return;
|
|
|
|
|
|
// post_id + dimensions must be unique so purge the old entry if one exists
|
|
$old_thumb = self::getThumb( $this->post_id, $this->dimensions );
|
|
if ( ! is_null( $old_thumb ) ) {
|
|
$old_thumb->delete( $old_thumb->relative_path != $this->relative_path );
|
|
}
|
|
|
|
DG_Logger::writeLog( DG_LogLevel::Detail, 'Saving thumb with post_id = ' . $this->post_id );
|
|
|
|
// perform save to DB
|
|
$values = array( 'post_id' => $this->post_id, 'meta_key' => self::$meta_key, 'meta_value' => $this->getMetaValue() );
|
|
$value_formats = array( '%d', '%s', '%s' );
|
|
$wpdb->insert( $wpdb->postmeta, $values, $value_formats );
|
|
$this->meta_id = $wpdb->insert_id;
|
|
|
|
self::initThumbs();
|
|
if ( ! isset( self::$thumbs[$this->post_id] ) ) {
|
|
self::$thumbs[$this->post_id] = array();
|
|
}
|
|
|
|
self::$thumbs[$this->post_id][$this->dimensions] = $this;
|
|
}
|
|
|
|
/**
|
|
* Deletes the current instances from the DB and filesystem.
|
|
*
|
|
* @param $delete_files bool Whether files for the thumb should be deleted.
|
|
*/
|
|
public function delete( $delete_files = true ) {
|
|
if ( ! isset( $this->meta_id ) ) return;
|
|
|
|
DG_Logger::writeLog( DG_LogLevel::Detail, 'Deleting thumb with post_id = ' . $this->post_id );
|
|
|
|
global $wpdb;
|
|
$wpdb->delete( $wpdb->postmeta, array( 'meta_id' => $this->meta_id ), array( '%d' ) );
|
|
self::cleanupThumbFiles( $this );
|
|
unset( $this->meta_id );
|
|
if ( 1 === sizeof( self::$thumbs[$this->post_id] ) ) {
|
|
unset( self::$thumbs[$this->post_id] );
|
|
} else {
|
|
unset( self::$thumbs[$this->post_id][$this->dimensions] );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Whether the given attachment has a thumb graphic.
|
|
*
|
|
* @param $ID int The id of the attachment to be checked.
|
|
* @param $dimensions string Optional. The dimensions for the thumbnail we're seeking.
|
|
* @param $success_matters bool Optional. Whether return value should be false when DG_Thumb exists, but is not successful.
|
|
* @return bool Whether the given attachment has a thumbnail image.
|
|
*/
|
|
public static function thumbExists($ID, $dimensions = null, $success_matters = true) {
|
|
$thumb = self::getThumb( $ID, $dimensions );
|
|
return ! is_null( $thumb ) && ( ! $success_matters || $thumb->isSuccess() );
|
|
}
|
|
|
|
/**
|
|
* Whether the given attachment has a thumb graphic.
|
|
*
|
|
* @param $ID int The id of the attachment to be checked.
|
|
* @param $dimensions string The dimensions for the thumbnail we're seeking.
|
|
* @return DG_Thumb|null The thumbnail at the requested dimensions.
|
|
*/
|
|
public static function getThumb($ID, $dimensions = null) {
|
|
$thumbs = self::getThumbs();
|
|
$ret = null;
|
|
if ( isset( $thumbs[$ID] ) && ( is_null( $dimensions ) || isset( $thumbs[$ID][$dimensions] ) ) ) {
|
|
$ret = ! is_null( $dimensions ) ? $thumbs[$ID][$dimensions] : reset( $thumbs[$ID] );
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Initializes the thumbs variable if not already initialized.
|
|
*/
|
|
private static function initThumbs() {
|
|
if ( !isset( self::$thumbs ) ) {
|
|
DG_Logger::writeLog( DG_LogLevel::Detail, 'Populating thumbnail cache.' );
|
|
global $wpdb;
|
|
self::$thumbs = array();
|
|
|
|
$meta_key = self::$meta_key;
|
|
$sql = "SELECT post_id, meta_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '$meta_key'";
|
|
foreach ( $wpdb->get_results( $sql ) as $row ) {
|
|
$key = $row->post_id;
|
|
$new = new DG_Thumb( $row );
|
|
if ( ! isset( self::$thumbs[$key] ) ) {
|
|
self::$thumbs[$key] = array();
|
|
} elseif ( isset( self::$thumbs[$key][$new->dimensions] ) ) {
|
|
// it is possible to end up with duplicate thumbnails -- cleanup here
|
|
$old = self::$thumbs[$key][$new->dimensions];
|
|
if ( $old->timestamp < $new->timestamp ) {
|
|
$old->delete();
|
|
} else {
|
|
$new->delete();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
self::$thumbs[$key][$new->dimensions] = $new;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets either a nested associative array mapping ID to dimension to thumb or an associative array mapping ID to thumb.
|
|
*
|
|
* @param $dimensions string WIDTHxHEIGHT
|
|
* @return DG_Thumb[]|DG_Thumb[][] The matched thumbs.
|
|
*/
|
|
public static function getThumbs($dimensions = null) {
|
|
self::initThumbs();
|
|
if ( is_null( $dimensions ) ) {
|
|
$ret = self::$thumbs;
|
|
} else {
|
|
$ret = array();
|
|
foreach ( self::$thumbs as $thumbs ) {
|
|
if ( isset( $thumbs[$dimensions] ) ) {
|
|
$thumb = $thumbs[$dimensions];
|
|
$ret[$thumb->post_id] = $thumb;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
/**
|
|
* Removes thumbs from the DB.
|
|
* @param $ids int[]|int|null Optional. The post IDs to be purged. If not given then all are purged.
|
|
* @param $blog_id null|int Optional. The blog to purge from. Defaults to active blog.
|
|
* @param $delete_files bool Whether files for the thumb should be deleted.
|
|
*/
|
|
public static function purgeThumbs( $ids = null, $blog_id = null, $delete_files = true ) {
|
|
global $wpdb;
|
|
|
|
if ( ! is_null( $ids ) ) {
|
|
$ids = (array)$ids;
|
|
}
|
|
|
|
$postmeta = $wpdb->get_blog_prefix( $blog_id ) . 'postmeta';
|
|
$meta_key = self::$meta_key;
|
|
|
|
self::initThumbs();
|
|
|
|
if ( ! is_array( $ids ) ) {
|
|
$sql = "DELETE FROM $postmeta WHERE meta_key = '$meta_key'";
|
|
$result = $wpdb->query( $sql );
|
|
|
|
if ( $result ) {
|
|
// cleanup filesystem
|
|
if ( $delete_files ) {
|
|
foreach ( self::$thumbs as $thumbs ) {
|
|
self::cleanupThumbFiles( $thumbs );
|
|
}
|
|
}
|
|
|
|
self::$thumbs = null;
|
|
}
|
|
} else if ( !empty( $ids ) ) {
|
|
$sql = "DELETE FROM $postmeta WHERE meta_key = '$meta_key' AND post_id IN(" . rtrim( str_repeat( '%d,', sizeof( $ids ) ), ',' ) . ")";
|
|
$result = $wpdb->query( $wpdb->prepare( $sql, $ids ) );
|
|
|
|
if ( $result ) {
|
|
foreach ( $ids as $id ) {
|
|
if ( isset( self::$thumbs[$id] ) ) {
|
|
self::cleanupThumbFiles( self::$thumbs[$id] );
|
|
unset( self::$thumbs[$id] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete all thumb entries that do not have an actual image associated with them due to failed generation.
|
|
*/
|
|
public static function purgeFailedThumbs() {
|
|
global $wpdb;
|
|
$wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '" . self::$meta_key . "' AND meta_value LIKE '%:%::'" );
|
|
|
|
// force re-query next time
|
|
self::$thumbs = null;
|
|
}
|
|
|
|
/**
|
|
* Removes meta data associated w/ attachment.
|
|
*
|
|
* @param $id int The post ID.
|
|
*/
|
|
public static function cleanupAttachmentMeta($id) {
|
|
$thumb = self::getThumb( $id );
|
|
if ( ! is_null( $thumb ) ) {
|
|
self::cleanupThumbFiles($thumb);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $thumbs DG_Thumb[]|DG_Thumb Removes files associated with given thumb(s).
|
|
*/
|
|
private static function cleanupThumbFiles($thumbs) {
|
|
if ( is_a( $thumbs, __CLASS__ ) ) {
|
|
$thumbs = array( $thumbs );
|
|
}
|
|
|
|
foreach ( $thumbs as $thumb ) {
|
|
if ( isset( $thumb->relative_path ) ) {
|
|
@unlink( $thumb->getPath() );
|
|
}
|
|
}
|
|
}
|
|
} |