Skip to content

Commit

Permalink
Fix image cache invalidation
Browse files Browse the repository at this point in the history
  • Loading branch information
iherwig committed Jul 10, 2024
1 parent 2f1bb46 commit bb57584
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 20 deletions.
43 changes: 24 additions & 19 deletions src/wcmf/lib/io/ImageUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use wcmf\lib\core\ObjectFactory;
use wcmf\lib\util\URIUtil;
use wcmf\lib\util\StringUtil;

if (!class_exists('\Intervention\Image\ImageManager')) {
throw new \wcmf\lib\config\ConfigurationException(
Expand Down Expand Up @@ -39,7 +40,7 @@ class ImageUtil {
* Create an HTML image tag using srcset and sizes attributes.
* The image locations in the srcset attribute will point to the frontend cache directory
* (_FrontendCache_ configuration section).
* @param $imageFile The image file location relative to the upload directory
* @param $imageFile The image file location inside the upload directory relative to the executed script
* @param $widths Array of sorted width values to be used in the srcset attribute
* @param $type Indicates how width values should be used (optional, default: w)
* - w: Values will be used as pixels, e.g. widths="1600,960" results in srcset="... 1600w, ... 960w"
Expand Down Expand Up @@ -186,7 +187,7 @@ public static function getImageTag($imageFile, $widths, $type='w', $sizes='', $f
* @param $location
* @param $returnLocation Boolean indicating if only the file location should be returned (optional)
* @param $callback Function called, after the cached image is created, receives the original and cached image as parameters (optional)
* @return String, if returnLocation is true
* @return string, if returnLocation is true
*/
public static function getCachedImage($location, $returnLocation=false, $callback=null) {
$location = rawurldecode($location);
Expand Down Expand Up @@ -231,7 +232,7 @@ public static function getCachedImage($location, $returnLocation=false, $callbac

/**
* Get the cache location for the given image, width and optionally type and quality
* @param $imageFile Image file located inside the upload directory of the application given as path relative to WCMF_BASE
* @param $imageFile The image file location inside the upload directory relative to the executed script
* @param $width
* @param $type
* @param $quality
Expand Down Expand Up @@ -290,22 +291,24 @@ public static function extractTransformationInfo($file) {

/**
* Delete the cached images for the given image file
* @param $imageFile Image file located inside the upload directory of the application given as path relative to WCMF_BASE
* @param $imageFile The image file location inside the upload directory as stored in the database
*/
public static function invalidateCache($imageFile) {
if (strlen($imageFile) > 0) {
$imageFile = URIUtil::makeRelative($imageFile, self::getMediaRootRelative());
$imageFile = URIUtil::makeRelative(URIUtil::makeAbsolute($imageFile, WCMF_BASE), self::getMediaRoot());

// get file name and cache directory
$baseName = FileUtil::basename($imageFile);
$directory = self::getCacheDir($imageFile);

// delete matches of the form ([0-9]+)-$fixedFile
if (is_dir($directory)) {
$typesPattern = '('.join('|', self::SUPPORTED_FORMATS).')';
$typesPattern = '('.join('|', self::SUPPORTED_FORMATS).')(@[0-9]+)?';
foreach (FileUtil::getFiles($directory) as $file) {
$matches = [];
if (preg_match('/^([0-9]+|'.$typesPattern.')(-'.$typesPattern.')?-/', $file, $matches) && $matches[1].'-'.$baseName === $file) {
// regex for matching the transformation prefix of the file ($matches[0])
$prefixRegex = '/^(([0-9]+|'.$typesPattern.')(-'.$typesPattern.')?-)/';
if (preg_match($prefixRegex, $file, $matches) && strpos($file, $matches[0].$baseName) === 0) {
unlink($directory.$file);
}
}
Expand All @@ -323,44 +326,46 @@ private static function getImageManager() {
/**
* Get the cache directory for the given source image file
* @param $imageFile
* @return String
* @return string
*/
private static function getCacheDir($imageFile) {
$mediaRoot = self::getMediaRootRelative();
return self::getCacheRoot().dirname(substr($imageFile, strlen($mediaRoot))).'/';
return self::getCacheRoot().dirname($imageFile).'/';
}

/**
* Get the source directory for the given cached image location
* @param $location
* @return String
* @return string
*/
private static function getSourceDir($location) {
return self::getMediaRootRelative().dirname($location).'/';
return self::makeRelative(self::getMediaRoot()).dirname($location).'/';
}

/**
* Get the absolute image cache root directory
* @return String
* @return string
*/
private static function getCacheRoot() {
$config = ObjectFactory::getInstance('configuration');
return $config->getDirectoryValue('cacheDir', 'FrontendCache').self::IMAGE_CACHE_SECTION.'/';
}

/**
* Get the media root directory relative to the executed script
* @return String
* Get the absolute media root directory
* @return string
*/
private static function getMediaRootRelative() {
// images are located in the same or subdirectory of the directory of the executed script
return '';
private static function getMediaRoot() {
// images are located in the common parent directory of the media and cache directory
$config = ObjectFactory::getInstance('configuration');
$mediaRootAbs = $config->getDirectoryValue('uploadDir', 'Media');
$cacheRootAbs = $config->getDirectoryValue('cacheDir', 'FrontendCache');
return StringUtil::longestCommonPrefix([$mediaRootAbs, $cacheRootAbs]);
}

/**
* Make the current location relative to the executed script
* @param $location
* @return String
* @return string
*/
private static function makeRelative($location) {
if (self::$scriptDirAbs == null) {
Expand Down
15 changes: 15 additions & 0 deletions src/wcmf/lib/util/StringUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,5 +437,20 @@ public static function guidv4() {

return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

/**
* Find the longest common prefix
* Code from https://stackoverflow.com/questions/1336207/finding-common-prefix-of-array-of-strings#answer-35838357
* @param mixed $stringList
* @return string
*/
public static function longestCommonPrefix(array $stringList): string {
sort($stringList);
$s1 = $stringList[0];
$s2 = $stringList[count($stringList)-1];
$len = min(strlen($s1), strlen($s2));
for ($i=0; $i<$len && $s1[$i]==$s2[$i]; $i++);
return substr($s1, 0, $i);
}
}
?>
5 changes: 4 additions & 1 deletion src/wcmf/lib/util/URIUtil.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ class URIUtil {
* code from http://www.webmasterworld.com/forum88/334.htm
* @param $absUri Absolute URI at which the path should end, may have a trailing filename
* @param $base Absolute URI from which the relative should start
* @return String
* @return string
*/
public static function makeRelative($absUri, $base) {
if ($absUri == $base) {
return '';
}
// normalize slashes and remove drive names
list($absUri, $base) = self::normalizePaths(
self::removeProtocols(self::normalizeSlashes([$absUri, $base])));
Expand Down

0 comments on commit bb57584

Please sign in to comment.