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 '