Paculop
Paculop

Reputation: 51

How to remove Prestashop useless images at img/p/

At Prestashop when I remove some products, the images remains at their directory /img/p/ so at the moment my images directory it's close to being 2GB. Found this script to delete useless and BBDD unlinked images on Prestashop but I don't know why It's only detecting the orphan images but not removing them. Maybe the unlink function is disabled on the php configuration? Is it possible? Or the code is wrong? Is there another way to do this kind of cleanup?

    <?php
// root path of the shop
$shop_root='/home/myweb/public_html/';
// limit number of image files to check, set to 10 for testing
$limit=1000000000;


include $shop_root . '/config/settings.inc.php';
$pdo = new PDO( 'mysql:host='._DB_SERVER_.';dbname='._DB_NAME_, _DB_USER_, _DB_PASSWD_ );
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$r=$pdo->query('select count(1) cnt from ps_image')->fetch();
echo 'count images database: '.$r['cnt'] . "<Br />";

// reset some counters
$cnt_files=0;
$cnt_checked=0;
$cnt_not_found=0;
$cnt_found=0;

for($ii=1; ($ii<=9) && ($cnt_files != $limit); $ii++)
{
        $path=$shop_root.'img/p/'.$ii;
        delImage($path);
        for($jj=0; ($jj<=9) && ($cnt_files != $limit); $jj++)
        {       
                $path=$shop_root.'img/p/'.$ii.'/'.$jj;
                delImage($path);
                for($kk=0; ($kk<=9) && ($cnt_files != $limit); $kk++)
                {
                        $path=$shop_root.'img/p/'.$ii.'/'.$jj.'/'.$kk;
                        delImage($path);
                        for($ll=0; ($ll<=9) && ($cnt_files != $limit); $ll++)
                        {
                                $path=$shop_root.'img/p/'.$ii.'/'.$jj.'/'.$kk.'/'.$ll;
                                delImage($path);
                        }       
                }
        }

}
echo 'files: '.$cnt_files.' checked: '.$cnt_checked.' not_found: '.$cnt_not_found.' found: '.$cnt_found;

function delImage($imageDir)
{
        global $limit, $pdo, $cnt_files, $cnt_checked, $cnt_not_found, $cnt_found;
        if ($handle = @opendir($imageDir)) {                    //@ is wriiten to avoid warning message and is handled in else condition
                echo $imageDir."<BR />";
                while ($cnt_files != $limit && false !== ($entry = readdir($handle))) {
                        if ($entry != "." && $entry != "..") {
                                $cnt_files++;
                                $pi = explode('-',$entry);
                                if($pi[0]>0 && !empty($pi[1])) {
                                        $cnt_checked++;
                                        if(!checkExistsDb($pdo,$pi[0])) {
                                                $cnt_not_found++;
                                                echo 'rm '.$imageDir.'/'.$entry."<BR />";
                                                unlink($imageDir.'/'.$entry);
                                        } else {
                                                $cnt_found++;
                                        }
                                }
                        }
                }
                        closedir($handle);
  }
        else
        {
                echo $imageDir." doesn't exist".'<BR />';
        }

}

function checkExistsDb($pdo, $id_image) {
        $r=$pdo->query($q='select \'ok\' ok, (select id_image from ps_image where id_image = '.(int)$id_image.') id_image');
        $row=$r->fetch();
        if($row['ok']!='ok') die( 'Problem with query, please correct');
        return $row['id_image']?true:false;
}
?>

Here's an output piece:

/home/myweb/public_html/img/p/9/9/7
/home/myweb/public_html/img/p/9/9/7/0 doesn't exist
/home/myweb/public_html/img/p/9/9/7/1 doesn't exist
/home/myweb/public_html/img/p/9/9/7/2 doesn't exist
/home/myweb/public_html/img/p/9/9/7/3 doesn't exist
/home/myweb/public_html/img/p/9/9/7/4 doesn't exist
/home/myweb/public_html/img/p/9/9/7/5 doesn't exist
/home/myweb/public_html/img/p/9/9/7/6 doesn't exist
/home/myweb/public_html/img/p/9/9/7/7 doesn't exist
/home/myweb/public_html/img/p/9/9/7/8 doesn't exist
/home/myweb/public_html/img/p/9/9/7/9 doesn't exist
/home/myweb/public_html/img/p/9/9/8
/home/myweb/public_html/img/p/9/9/8/0 doesn't exist
/home/myweb/public_html/img/p/9/9/8/1 doesn't exist
/home/myweb/public_html/img/p/9/9/8/2 doesn't exist
/home/myweb/public_html/img/p/9/9/8/3 doesn't exist
/home/myweb/public_html/img/p/9/9/8/4 doesn't exist
/home/myweb/public_html/img/p/9/9/8/5 doesn't exist
/home/myweb/public_html/img/p/9/9/8/6 doesn't exist
/home/myweb/public_html/img/p/9/9/8/7 doesn't exist
/home/myweb/public_html/img/p/9/9/8/8 doesn't exist
/home/myweb/public_html/img/p/9/9/8/9 doesn't exist
/home/myweb/public_html/img/p/9/9/9
/home/myweb/public_html/img/p/9/9/9/0 doesn't exist
/home/myweb/public_html/img/p/9/9/9/1 doesn't exist
/home/myweb/public_html/img/p/9/9/9/2 doesn't exist
/home/myweb/public_html/img/p/9/9/9/3 doesn't exist
/home/myweb/public_html/img/p/9/9/9/4 doesn't exist
/home/myweb/public_html/img/p/9/9/9/5 doesn't exist
/home/myweb/public_html/img/p/9/9/9/6 doesn't exist
/home/myweb/public_html/img/p/9/9/9/7 doesn't exist
/home/myweb/public_html/img/p/9/9/9/8 doesn't exist
/home/myweb/public_html/img/p/9/9/9/9 doesn't exist
files: 29013 checked: 22290 not_found: 0 found: 22290

Upvotes: 4

Views: 4676

Answers (4)

Eryk Wr&#243;bel
Eryk Wr&#243;bel

Reputation: 445

Try this. I spent a lot of time to develop this after many failures from different solutions. For me it is the safest method.

<?php
####PUT THIS FILE INTO YOUR MAIN SHOP FOLDER####

// root path of the shop, almost no one needs to change something here.
$shop_root = $_SERVER['DOCUMENT_ROOT']."/"; // need to have slash / at the end
$image_folder = 'img/p/'; // also needs slash at the ennd
$scan_dir = $shop_root.$image_folder;

include_once($shop_root.'config/config.inc.php');
include $shop_root . 'config/settings.inc.php';

#---------------------------------------------#
$last_id = (int)Db::getInstance()->getValue('
    SELECT id_image FROM '._DB_PREFIX_.'image ORDER BY id_image DESC
');

$counted_images = Db::getInstance()->executeS('
    SELECT count(*) as qnt FROM '._DB_PREFIX_.'image
');
$counted_images = (int)$counted_images[0]['qnt'];


echo 'There was '.$last_id.' images in database but only '.$counted_images.' is used right now. Lets check how many of them are eating up our storage without no reason.<br>';

//$limit = 150; // for testing
$limit = $last_id; // for production

$removed_images = 0;

for ($i=1; $i <= $limit; $i++) {
    if (!imageExistsInDB($i)){
        $imageDir = str_split($i);
        $imageDir = implode('/', $imageDir);
        $path = $scan_dir.$imageDir;
        deleteImagesFromPath($path);
    }
}

function deleteImagesFromPath($path) {
    global $removed_images;
    $images = glob($path . '/*.{jpg,png,gif,jpeg}', GLOB_BRACE);
    if ($images){
        foreach ($images as $file) {
            if (is_file($file)) {
                unlink($file);
            }
        }
        $removed_images++;
        echo 'Deleted images from folder ' . $path . '/' ."<br/>";
    }
}

function imageExistsInDB($id_image){
    return Db::getInstance()->getValue('
        SELECT id_image FROM '._DB_PREFIX_.'image WHERE id_image = '.(int)$id_image
    );
}

echo '--------------------------------------<br>';
if  ($removed_images > 0)
    echo 'Hurray! We removed '.$removed_images.' product images!';
else
    echo 'Everything is ok with Your images. I did not removed any of them or I made it before. Good Job Presta!';

Upvotes: 1

Divyesh Prajapati
Divyesh Prajapati

Reputation: 985

For your information, when you delete the product Prestashop automatically delete all the images associated with the product.

I have also checked your script and it worked fine for me by changing $shop_root and adding configuration file.

require(dirname(__FILE__).'/config/config.inc.php'); // root path of the shop $shop_root = $_SERVER['DOCUMENT_ROOT']."/";

You need to check folder permission and check why it's not allowing to unlink images.

Upvotes: 0

l2f
l2f

Reputation: 1

It will never work because you remove the root of your path: you remove: /home/myweb/public_html/img/p/9/9/7 and after you want to remove: /home/myweb/public_html/img/p/9/9/7/0 but /home/myweb/public_html/img/p/9/9/7 doesn't exist :)

To work do this:

for($ii=1; ($ii<=9) && ($cnt_files != $limit); $ii++)
{
    $pathRacine=$shop_root.'img/p/'.$ii;
    //delImage($path);
    for($jj=0; ($jj<=9) && ($cnt_files != $limit); $jj++)
    {
            $path1=$shop_root.'img/p/'.$ii.'/'.$jj;
            //delImage($path);
            for($kk=0; ($kk<=9) && ($cnt_files != $limit); $kk++)
            {
                    $path2=$shop_root.'img/p/'.$ii.'/'.$jj.'/'.$kk;
                    //delImage($path);
                    for($ll=0; ($ll<=9) && ($cnt_files != $limit); $ll++)
                    {
                            $path3=$shop_root.'img/p/'.$ii.'/'.$jj.'/'.$kk.'/'.$ll;

                            delImage($path3);
                    }

                    delImage($path2);
            }

            delImage($path1);
    }

    delImage($pathRacine);
}

And do not use the same variable name everywhere

Upvotes: 0

Prescol
Prescol

Reputation: 627

Check the files permissions. If php user has not permissions to delete files of other users the function unlink will not work.

Upvotes: 0

Related Questions