Last active
October 11, 2023 15:10
-
-
Save perryholden/54bf085b983a9a423b50c3a047b63e08 to your computer and use it in GitHub Desktop.
Finds orphaned files from deleted products in Magento 2 (partially generated with ChatGPT v4)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Magento\Framework\App\Bootstrap; | |
require __DIR__ . '/app/bootstrap.php'; | |
/* | |
* There are a few instances where a file exists in the EAV tables, yet not in the media table, therefore, we should just keep these. | |
* These were generated by the following SQL (please update attribute IDs, if needed): | |
SELECT `value` AS 'image' | |
FROM catalog_product_entity_varchar | |
WHERE store_id = 0 | |
AND attribute_id = 87 | |
AND `value` IS NOT NULL AND `value` NOT IN ( | |
(SELECT m2.value | |
FROM catalog_product_entity_media_gallery_value m1 | |
INNER JOIN catalog_product_entity_media_gallery m2 ON m2.value_id = m1.value_id | |
AND m2.attribute_id = 90 | |
GROUP BY m1.entity_id) | |
) AND `value` <> 'no_selection' | |
*/ | |
$filesToKeep = [ | |
'/0/1/0123.jpg', | |
'/0/2/0234.jpg', | |
]; | |
$bootstrap = Bootstrap::create(BP, $_SERVER); | |
$objectManager = $bootstrap->getObjectManager(); | |
$state = $objectManager->get('Magento\Framework\App\State'); | |
$state->setAreaCode('frontend'); | |
// Filesystem and CSV dependencies | |
$fileSystem = $objectManager->create('\Magento\Framework\Filesystem'); | |
$mediaDirectory = $fileSystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); | |
$productMediaConfig = $objectManager->create('Magento\Catalog\Model\Product\Media\Config'); | |
$csvProcessor = $objectManager->create('Magento\Framework\File\Csv'); | |
$mediaGalleryResourceModel = $objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Gallery'); | |
// Fetch all images from the database | |
$connection = $mediaGalleryResourceModel->getConnection(); | |
$select = $connection->select()->from($mediaGalleryResourceModel->getMainTable(), 'value'); | |
$allDbImages = $connection->fetchCol($select); | |
// Path to the directory where product images are stored | |
$mediaGalleryPath = $productMediaConfig->getBaseMediaPath(); | |
$orphanedImages = []; | |
$allFiles = $mediaDirectory->readRecursively($mediaGalleryPath); | |
$totalFileSize = 0; | |
foreach ($allFiles as $file) { | |
$relativeFilePath = str_replace("catalog/product", '', $file); | |
if ( | |
is_file(BP . '/pub/media/' . $file) && | |
!in_array($relativeFilePath, $allDbImages) && | |
!in_array($relativeFilePath, $filesToKeep) && | |
(!str_starts_with($relativeFilePath, '/cache/')) && | |
(!str_starts_with($relativeFilePath, '/placeholder/')) | |
) { | |
if ($orphanedFileSize = filesize(BP . '/pub/media/' . $file)) { | |
$totalFileSize += $orphanedFileSize; | |
} | |
$orphanedImages[] = [$relativeFilePath]; | |
} | |
} | |
// If orphaned images are found, save to CSV | |
if (!empty($orphanedImages)) { | |
$csvFile = 'orphaned_images.csv'; | |
$csvProcessor->saveData($csvFile, $orphanedImages); | |
echo "Orphaned images saved to $csvFile\n"; | |
$approxSpace = human_filesize($totalFileSize); | |
echo "Approximate total space to recover: $approxSpace\n"; | |
} else { | |
echo "No orphaned images found.\n"; | |
} | |
function human_filesize($bytes, $decimals = 2) { | |
$sz = 'BKMGTP'; | |
$factor = floor((strlen($bytes) - 1) / 3); | |
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment