Skip to content

Instantly share code, notes, and snippets.

@aleron75
Last active October 24, 2023 19:59
Show Gist options
  • Save aleron75/07ab2a950b2e3429a820 to your computer and use it in GitHub Desktop.
Save aleron75/07ab2a950b2e3429a820 to your computer and use it in GitHub Desktop.
Delete no more used Product Images on Magento 1
<?php
require_once 'abstract.php';
class Mage_Shell_CheckImages extends Mage_Shell_Abstract
{
const CATALOG_PRODUCT = '/catalog/product';
const CACHE = '/cache/';
protected function _glob_recursive($pattern, $flags = 0)
{
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
$files = array_merge($files, $this->_glob_recursive($dir . '/' . basename($pattern), $flags));
}
return $files;
}
public function run()
{
if ($this->getArg('help')) {
echo $this->usageHelp();
return;
}
$media = Mage::getBaseDir('media');
$debug = $this->getArg('debug');
$dryrun = $this->getArg('dry') ? true : false ;
$includeCache = $this->getArg('cache');
$imagesOnDb = array();
$imagesOnDisk = array();
$setup = new Mage_Core_Model_Resource_Setup('core_setup');
/** @var Varien_Db_Adapter_Pdo_Mysql $connection */
$connection = $setup->getConnection();
$sql = "SELECT DISTINCT value
FROM (
SELECT value
FROM `{$setup->getTable('catalog_product_entity_media_gallery')}`
WHERE attribute_id
IN (SELECT attribute_id FROM `{$setup->getTable('eav_attribute')}` WHERE `attribute_code` in ('media_gallery') AND entity_type_id = 4)
UNION
SELECT value
FROM `{$setup->getTable('catalog_product_entity_varchar')}`
WHERE attribute_id
IN (SELECT attribute_id FROM `{$setup->getTable('eav_attribute')}` WHERE `attribute_code` in ('image','small_image','thumbnail') AND entity_type_id = 4)
) AS T";
$result = $connection->query($sql);
foreach ($result->fetchAll() as $rec) {
$imagesOnDb[$rec['value']] = 1;
}
$imagesOnDb = array_keys($imagesOnDb);
if ($debug) print_r(array_slice($imagesOnDb, 0, 100));
if ($debug) echo $media . "/*\n";
$skip = strlen($media . self::CATALOG_PRODUCT);
foreach ($this->_glob_recursive($media . self::CATALOG_PRODUCT . '/*', GLOB_MARK) as $img) {
if (substr($img, -1) != '/') {
if ($includeCache || (substr($img, $skip, 7) != self::CACHE)) {
$imagesOnDisk[] = substr($img, $skip);
}
}
}
if ($debug) print_r(array_slice($imagesOnDisk, 0, 100));
$imagesToDelete = array_diff($imagesOnDisk, $imagesOnDb);
if ($debug) {
print_r($imagesToDelete);
} else {
foreach ($imagesToDelete as $x) {
if ($dryrun) {
echo 'rm '.$media . self::CATALOG_PRODUCT . $x.PHP_EOL;
} else {
@unlink($media . self::CATALOG_PRODUCT . $x);
}
}
}
if ($debug) {
echo "\r\n";
}
}
public function usageHelp()
{
return <<<USAGE
Usage: php -f check_images.php
debug debug mode
cache remove cache images too
dry dryrun
USAGE;
}
}
$shell = new Mage_Shell_CheckImages();
$shell->run();
@Schrank
Copy link

Schrank commented Oct 3, 2023

Because I want to know, wether it is debug or dryrun, I added some echo:

<?php
require_once 'abstract.php';

class Mage_Shell_CheckImages extends Mage_Shell_Abstract
{
    const CATALOG_PRODUCT = '/catalog/product';

    const CACHE = '/cache/';
    const PLACEHOLDER = '/placeholder/';

    protected function _glob_recursive($pattern, $flags = 0)
    {
        $files = glob($pattern, $flags);
        foreach (glob(dirname($pattern) . '/*', GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
            $files = array_merge($files, $this->_glob_recursive($dir . '/' . basename($pattern), $flags));
        }
        return $files;
    }

    public function run()
    {
        if ($this->getArg('help')) {
            echo $this->usageHelp();
            return;
        }

        $media = Mage::getBaseDir('media');
        $debug = $this->getArg('debug');
        $dryrun = $this->getArg('dry') ? true : false ;
        if($dryrun) {
                echo "Running in dry mode.\n";
        }
        if($debug) {
                echo "Running in debug mode.\n";
        }

        $includeCache = $this->getArg('cache');

        $imagesOnDb = array();
        $imagesOnDisk = array();
        $setup = new Mage_Core_Model_Resource_Setup('core_setup');
        /** @var Varien_Db_Adapter_Pdo_Mysql $connection */
        $connection = $setup->getConnection();
        
        $entityTypeIdSql = sprintf(
            "SELECT `entity_type_id` FROM `%s` WHERE `entity_type_code` = :entity_type_code;",
            $setup->getTable('eav/entity_type')
        );
        $entityTypeId = (int)$connection->fetchOne($entityTypeIdSql, array('entity_type_code' => Mage_Catalog_Model_Product::ENTITY));
        if (!$entityTypeId) {
            throw new RuntimeException(sprintf(
                "Could not find entity type code for entity %s",
                Mage_Catalog_Model_Product::ENTITY
            ));
        }

        $sql = "SELECT DISTINCT value
FROM (
    SELECT value
    FROM  `{$setup->getTable('catalog_product_entity_media_gallery')}`
    WHERE attribute_id
    IN (SELECT attribute_id FROM `{$setup->getTable('eav_attribute')}` WHERE `attribute_code` in ('media_gallery') AND entity_type_id = :entity_type_id)
    UNION
    SELECT value
    FROM  `{$setup->getTable('catalog_product_entity_varchar')}`
    WHERE attribute_id
    IN (SELECT attribute_id FROM `{$setup->getTable('eav_attribute')}` WHERE `attribute_code` in ('image','small_image','thumbnail') AND entity_type_id = :entity_type_id)
) AS T";
        $result = $connection->query($sql, array('entity_type_id' => $entityTypeId));
        foreach ($result->fetchAll() as $rec) {
            $imagesOnDb[$rec['value']] = 1;
        }
        $imagesOnDb = array_keys($imagesOnDb);
        if ($debug) print_r(array_slice($imagesOnDb, 0, 100));

        if ($debug) echo $media . "/*\n";
        $skip = strlen($media . self::CATALOG_PRODUCT);
        foreach ($this->_glob_recursive($media . self::CATALOG_PRODUCT . '/*', GLOB_MARK) as $img) {
            if (substr($img, -1) != '/') {
                if ((substr($img, $skip, 13) != self::PLACEHOLDER) && ($includeCache || (substr($img, $skip, 7) != self::CACHE))) {
                    $imagesOnDisk[] = substr($img, $skip);
                }
            }
        }
        if ($debug) print_r(array_slice($imagesOnDisk, 0, 100));

        $imagesToDelete = array_diff($imagesOnDisk, $imagesOnDb);
        if ($debug) {
            print_r($imagesToDelete);
            echo count($imagesOnDisk)." images on Disk\n";
            echo count($imagesOnDb)." images on DB\n";
            echo count($imagesToDelete)." images to delete\n";
        } else {
            foreach ($imagesToDelete as $x) {
                if ($dryrun) {
                    echo 'rm '.$media . self::CATALOG_PRODUCT . $x.PHP_EOL;
                } else {
                    @unlink($media . self::CATALOG_PRODUCT . $x);
                }
            }
        }

        if ($debug) {
            echo "\r\n";
        }

    }

    public function usageHelp()
    {
        return <<<USAGE
Usage: php -f check_images.php
    debug       debug mode
    cache       remove cache images too
    dry         dryrun


USAGE;
    }
}

$shell = new Mage_Shell_CheckImages();
$shell->run();

@ADDISON74
Copy link

Since my last post in 2016 I discovered the following extension for Magento 1/OpenMage: https://github.com/fballiano/openmage-image-cleaner.

This is by far the most advanced functional extension which has a lot of useful features. For a while I used ImaClean, but I removed it in favor of the extension mentioned above. It is installed in production and offers a complete visual control over what is deleted. It is not limited only to product pictures, but can also solve other places where could be orphaned images.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment