diff --git a/models/Database.php b/models/Database.php index aaa0dfc..8507fa7 100644 --- a/models/Database.php +++ b/models/Database.php @@ -488,7 +488,7 @@ class Database /** * This function can be used to insert data into the database in a secure way. */ - public function insert($method = 'replace', $table, $columns, $data) + public function insert($method, $table, $columns, $data) { // With nothing to insert, simply return. if (empty($data)) diff --git a/models/GenericTable.php b/models/GenericTable.php index df54bda..0ead368 100644 --- a/models/GenericTable.php +++ b/models/GenericTable.php @@ -43,7 +43,7 @@ class GenericTable $this->start = empty($options['start']) || !is_numeric($options['start']) || $options['start'] < 0 || $options['start'] > $this->recordCount ? 0 : $options['start']; // Figure out where we are on the whole, too. - $numPages = ceil($this->recordCount / $this->items_per_page); + $numPages = max(1, ceil($this->recordCount / $this->items_per_page)); $this->currentPage = min(ceil($this->start / $this->items_per_page) + 1, $numPages); // Let's bear a few things in mind... @@ -234,7 +234,9 @@ class GenericTable else $pattern = $options['data']['pattern']; - if (!is_numeric($rowData[$options['data']['timestamp']])) + if (!isset($rowData[$options['data']['timestamp']])) + $timestamp = 0; + elseif (!is_numeric($rowData[$options['data']['timestamp']])) $timestamp = strtotime($rowData[$options['data']['timestamp']]); else $timestamp = (int) $rowData[$options['data']['timestamp']]; diff --git a/models/Image.php b/models/Image.php index c8205f8..73fa459 100644 --- a/models/Image.php +++ b/models/Image.php @@ -67,14 +67,33 @@ class Image extends Asset return EXIF::fromFile($this->getPath()); } - public function getPath() + public function getImageUrls($width = null, $height = null) { - return ASSETSDIR . '/' . $this->subdir . '/' . $this->filename; + $image_urls = []; + if (isset($width) || isset($height)) + { + $thumbnail = new Thumbnail($this); + $image_urls[1] = $this->getThumbnailUrl($width, $height, false); + + // Can we afford to generate double-density thumbnails as well? + if ((!isset($width) || $this->image_width >= $width * 2) && + (!isset($height) || $this->image_height >= $height * 2)) + $image_urls[2] = $this->getThumbnailUrl($width * 2, $height * 2, false); + else + $image_urls[2] = $this->getThumbnailUrl($this->image_width, $this->image_height, true); + } + else + $image_urls[1] = $this->getUrl(); + + return $image_urls; } - public function getUrl() + public function getInlineImage($width = null, $height = null, $className = 'inline-image') { - return ASSETSURL . '/' . $this->subdir . '/' . $this->filename; + $image_urls = $this->getImageUrls($width, $height); + + return ''; } /** @@ -141,7 +160,8 @@ class Image extends Asset } return Registry::get('db')->query(' - DELETE FROM assets_thumbs + UPDATE assets_thumbs + SET filename = NULL WHERE id_asset = {int:id_asset}', ['id_asset' => $this->id_asset]); } diff --git a/models/PageIndex.php b/models/PageIndex.php index 6033c9a..0c988cc 100644 --- a/models/PageIndex.php +++ b/models/PageIndex.php @@ -63,9 +63,9 @@ class PageIndex lower current/cont. pgs. center upper */ - $this->num_pages = ceil($this->recordCount / $this->items_per_page); + $this->num_pages = max(1, ceil($this->recordCount / $this->items_per_page)); $this->current_page = min(ceil($this->start / $this->items_per_page) + 1, $this->num_pages); - if ($this->num_pages == 0) + if ($this->num_pages <= 1) { $this->needsPageIndex = false; return; diff --git a/models/Thumbnail.php b/models/Thumbnail.php index b650854..d35c260 100644 --- a/models/Thumbnail.php +++ b/models/Thumbnail.php @@ -9,6 +9,7 @@ class Thumbnail { private $image; + private $image_meta; private $thumbnails; private $properly_initialised; @@ -23,7 +24,7 @@ class Thumbnail const CROP_MODE_SLICE_CENTRE = 4; const CROP_MODE_SLICE_BOTTOM = 5; - public function __construct($image) + public function __construct(Image $image) { $this->image = $image; $this->image_meta = $image->getMeta(); @@ -45,51 +46,45 @@ class Thumbnail $thumb_selector = $this->width . 'x' . $this->height . $this->filename_suffix; if (!empty($this->thumbnails[$thumb_selector])) { - $thumb_path = '/' . $this->image->getSubdir() . '/' . $this->thumbnails[$thumb_selector]; - if (file_exists(THUMBSDIR . $thumb_path)) - return THUMBSURL . $thumb_path; + $thumb_filename = $this->image->getSubdir() . '/' . $this->thumbnails[$thumb_selector]; + if (file_exists(THUMBSDIR . '/' . $thumb_filename)) + return THUMBSURL . '/' . $thumb_filename; } // Do we have a custom thumbnail on file? $custom_selector = 'custom_' . $this->width . 'x' . $this->height; if (isset($this->image_meta[$custom_selector])) { - $custom_thumb_path = '/' . $this->image->getSubdir() . '/' . $this->image_meta[$custom_selector]; - if (file_exists(ASSETSDIR . $custom_thumb_path)) + $custom_filename = $this->image->getSubdir() . '/' . $this->image_meta[$custom_selector]; + if (file_exists(ASSETSDIR . '/' . $custom_filename)) { - // Ensure destination thumbnail directory exists. - if (!file_exists($this->image->getSubdir())) - @mkdir(THUMBSDIR . '/' . $this->image->getSubdir(), 0755, true); - // Copy the custom thumbail to the general thumbnail directory. - copy(ASSETSDIR . $custom_thumb_path, THUMBSDIR . $custom_thumb_path); + copy(ASSETSDIR . '/' . $custom_filename, THUMBSDIR . '/' . $custom_filename); // Let's remember this for future reference. $this->markAsGenerated($this->image_meta[$custom_selector]); - return THUMBSURL . $custom_thumb_path; + return THUMBSURL . '/' . $custom_filename; } else throw new UnexpectedValueException('Custom thumbnail expected, but missing in file system!'); } // Is this the right moment to generate a thumbnail, then? - if ($generate && array_key_exists($thumb_selector, $this->thumbnails)) + if ($generate) { - return $this->generate(); + if (array_key_exists($thumb_selector, $this->thumbnails)) + return $this->generate(); + else + throw new Exception("Trying to generate a thumbnail not previously queued by the system\n" . + print_r(func_get_args(), true)); } // If not, queue it for generation at another time, and return a URL to generate it with. - elseif (!$generate) - { - $this->markAsQueued(); - return BASEURL . '/thumbnail/' . $this->image->getId() . '/' . $this->width . 'x' . $this->height . $this->filename_suffix . '/'; - } - - // Still here..? What are you up to? ..Sneaking? else { - throw new Exception("Trying to generate a thumbnail for selector " . $thumb_selector . ", which does not appear to have been requested by the system.\n" . print_r(func_get_args(), true)); + $this->markAsQueued(); + return BASEURL . '/thumbnail/' . $this->image->getId() . '/' . $thumb_selector . '/'; } } @@ -260,14 +255,18 @@ class Thumbnail '_' . $this->width . 'x' . $this->height . $this->filename_suffix . '.' . $ext; // Ensure the thumbnail subdirectory exists. - if (!is_dir(THUMBSDIR . '/' . $this->image->getSubdir())) - mkdir(THUMBSDIR . '/' . $this->image->getSubdir(), 0755, true); + $target_dir = THUMBSDIR . '/' . $this->image->getSubdir(); + if (!is_dir($target_dir)) + mkdir($target_dir, 0755, true); + + if (!is_writable($target_dir)) + throw new Exception('Thumbnail directory is not writable!'); // No need to preserve every detail. $thumb->setImageCompressionQuality(80); // Save it in a public spot. - $thumb->writeImage(THUMBSDIR . '/' . $this->image->getSubdir() . '/' . $thumb_filename); + $thumb->writeImage($target_dir . '/' . $thumb_filename); // Let's remember this for future reference... $this->markAsGenerated($thumb_filename); @@ -278,7 +277,6 @@ class Thumbnail // Finally, return the URL for the generated thumbnail image. return THUMBSURL . '/' . $this->image->getSubdir() . '/' . $thumb_filename; } - // Blast! Curse your sudden but inevitable betrayal! catch (ImagickException $e) { throw new Exception('ImageMagick error occurred while generating thumbnail. Output: ' . $e->getMessage()); @@ -336,10 +334,16 @@ class Thumbnail if ($success) { $thumb_selector = $this->width . 'x' . $this->height . $this->filename_suffix; - $this->thumbnails[$thumb_selector] = $filename !== 'NULL' ? $filename : ''; - } + $this->thumbnails[$thumb_selector] = $filename !== 'NULL' ? $filename : null; - return $success; + // For consistency, write new thumbnail filename to parent Image object. + // TODO: there could still be an inconsistency if multiple objects exists for the same image asset. + $this->image->getThumbnails()[$thumb_selector] = $this->thumbnails[$thumb_selector]; + + return $success; + } + else + throw new UnexpectedValueException('Thumbnail queuing query failed'); } private function markAsQueued() diff --git a/templates/PhotoPage.php b/templates/PhotoPage.php index 2fdfbaf..800c521 100644 --- a/templates/PhotoPage.php +++ b/templates/PhotoPage.php @@ -65,11 +65,9 @@ class PhotoPage extends SubTemplate '; if ($this->photo->isPortrait()) - echo ' - '; + echo $this->photo->getInlineImage(null, 960); else - echo ' - '; + echo $this->photo->getInlineImage(1280, null); echo ' diff --git a/templates/PhotosIndex.php b/templates/PhotosIndex.php index 2d91129..1e8c793 100644 --- a/templates/PhotosIndex.php +++ b/templates/PhotosIndex.php @@ -90,8 +90,14 @@ class PhotosIndex extends SubTemplate Edit'; echo ' - - '; + + width() >= $width * 2 && $image->height() >= $height * 2) + echo ' srcset="', $image->getThumbnailUrl($width * 2, $height * 2, $crop, $fit), ' 2x"'; + + echo ' alt="" title="', $image->getTitle(), '">'; if ($this->show_labels) echo '