@@ -29,7 +29,7 @@ class Image extends \Magento\Framework\Model\AbstractModel
2929 /**
3030 * Config path for the jpeg image quality value
3131 */
32- const XML_PATH_JPEG_QUALITY = 'system/upload_configuration/jpeg_quality ' ;
32+ public const XML_PATH_JPEG_QUALITY = 'system/upload_configuration/jpeg_quality ' ;
3333
3434 /**
3535 * @var int
@@ -836,7 +836,37 @@ public function getWatermarkHeight()
836836 public function clearCache ()
837837 {
838838 $ directory = $ this ->_catalogProductMediaConfig ->getBaseMediaPath () . '/cache ' ;
839- $ this ->_mediaDirectory ->delete ($ directory );
839+ $ directoryToDelete = $ directory ;
840+ // Fixes issue when deleting cache directory at the same time that images are being
841+ // lazy-loaded on storefront leading to new directories and files generation in the cache directory
842+ // that would prevent deletion of the cache directory.
843+ // RCA: the method delete() recursively enumerates and delete all subdirectories and files before deleting
844+ // the target directory, which gives other processes time to create directories and files in the same directory.
845+ // Solution: Rename the directory to simulate deletion and delete the destination directory afterward
846+
847+ try {
848+ //generate name in format: \.[0-9A-ZA-z-_]{3} (e.g .QX3)
849+ $ tmpDirBasename = strrev (strtr (base64_encode (random_bytes (2 )), '+/= ' , '-_. ' ));
850+ $ tmpDirectory = $ this ->_catalogProductMediaConfig ->getBaseMediaPath () . '/ ' . $ tmpDirBasename ;
851+ //delete temporary directory if exists
852+ if ($ this ->_mediaDirectory ->isDirectory ($ tmpDirectory )) {
853+ $ this ->_mediaDirectory ->delete ($ tmpDirectory );
854+ }
855+ //rename the directory to simulate deletion and delete the destination directory
856+ if ($ this ->_mediaDirectory ->isDirectory ($ directory ) &&
857+ true === $ this ->_mediaDirectory ->getDriver ()->rename (
858+ $ this ->_mediaDirectory ->getAbsolutePath ($ directory ),
859+ $ this ->_mediaDirectory ->getAbsolutePath ($ tmpDirectory )
860+ )
861+ ) {
862+ $ directoryToDelete = $ tmpDirectory ;
863+ }
864+ } catch (\Throwable $ exception ) {
865+ //ignore exceptions thrown during renaming
866+ $ directoryToDelete = $ directory ;
867+ }
868+
869+ $ this ->_mediaDirectory ->delete ($ directoryToDelete );
840870
841871 $ this ->_coreFileStorageDatabase ->deleteFolder ($ this ->_mediaDirectory ->getAbsolutePath ($ directory ));
842872 $ this ->clearImageInfoFromCache ();
@@ -870,6 +900,7 @@ protected function _fileExists($filename)
870900 public function getResizedImageInfo ()
871901 {
872902 try {
903+ $ image = null ;
873904 if ($ this ->isBaseFilePlaceholder () == true ) {
874905 $ image = $ this ->imageAsset ->getSourceFile ();
875906 } else {
@@ -920,6 +951,7 @@ private function getImageSize($imagePath)
920951 {
921952 $ imageInfo = $ this ->loadImageInfoFromCache ($ imagePath );
922953 if (!isset ($ imageInfo ['size ' ])) {
954+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
923955 $ imageSize = getimagesize ($ imagePath );
924956 $ this ->saveImageInfoToCache (['size ' => $ imageSize ], $ imagePath );
925957 return $ imageSize ;
0 commit comments