Jump to content

[Solved] Error: some or all images could not be moved.


Recommended Posts

I'm running 1.4.4.0 and am attempting to convert to the new image storage system using the "Move Images" feature in the BO (Preferences tab, Images menu). I received the following error message: Error: some or all images could not be moved.

 

Anyone else have this problem and know what the work around is? I tried using write permissions of both 755 and 777 on the img directory and subdirectory with no luck.

 

Update: This was corrected by a change to classes/image.php - scroll down to see the fix. It will be incorporated into version 1.4.5

Link to comment
Share on other sites

Are there any errors logged in web server logs. How log does it take until you receive the error? It may be a script running time limitation. Check PHP settings for the max execution time and also memory limits. Are the images really not moved? Check manually. Is there anything special about the images that are not moved, or the folders in which they are?

Link to comment
Share on other sites

Are there any errors logged in web server logs. How log does it take until you receive the error? It may be a script running time limitation. Check PHP settings for the max execution time and also memory limits. Are the images really not moved? Check manually. Is there anything special about the images that are not moved, or the folders in which they are?

 

There are no errors logged on the server. The error message is almost instantaneous after clicking the "move images" button. I know of nothing special about the images or folders.

Link to comment
Share on other sites

OK, you already told you are using version 1.4.4, but please open the /classes/Image.php and check the version number from the header comment of the file around line 20. Should read

 

* @version  Release: $Revision: 7771 $

 

Is that correct? If so make a php file in your install/root directory, say test.php, and put the following into it

 

<?php
$a = scandir(dirname(__FILE__) . '/img/p');
if($c=count($a)) {
echo "found $c files and dirs\n";
}
else {
echo "problem scanning product images directory\n";
}	
if(mkdir('dummy_folder_ok_to_delete', 0755, true)) {
echo "folder created, (remember to delete it when done)\n";
}
else {
echo "cannot create folder\n";
}
?>

Visit test.php in your domain root. What happens?

Link to comment
Share on other sites

OK, here is on last attempt to see if an image can be copied from products folder to a dummy folder created. This code does, more or less, what the failing operation is doing. If it returns success, I cannot see any reason for moving images in PS UI should fail.

 

If the folder created in previous attempt,dummy_folder_ok_to_delete, is in root directory first delete it, then replace the contents of test.php with the following and run.

 

<?php

echo "<pre>";
$p = dirname(__FILE__) . '/img/p';
$a = scandir($p);
if ($c = count($a)) {
   echo "there are $c files and dirs in product images folder\n";
}
else {
   echo "problem scanning product images folder\n";
}
$base = 'dummy_folder_ok_to_delete';
if (mkdir($base, 0755, true)) {
   echo "dummy folder created, (remember to delete it when done)\n";
}
else {
   echo "cannot create a folder\n";
}
foreach ($a as $file) {
   if (preg_match('/^([0-9]+\-)([0-9]+)(\-(.*))?\.jpg$/', $file, $matches)) {
       echo "found a jpg, attempting to copy to dummy folder\n";
       if (rename($p . '/' . $file, $base . '/' . $file)) {
           echo "copy success\n";
           rename($base . '/' . $file, $p . '/' . $file); //move back
       }
       else {
           echo "cannot copy\n";
       }
       break;
   }
}
echo "</pre>";
?>

Link to comment
Share on other sites

I ran the new test.php and it resulted in the following message:

 

there are 85 files and dirs in product images folder

dummy folder created, (remember to delete it when done)

found a jpg, attempting to copy to dummy folder

copy success

 

I then tried to move the images, and get the same error message. I'm baffled....

Link to comment
Share on other sites

See the folders 2,3 and 4. Those are the folders created by conversion. They will contain further folders named with a number. So the conversion is in a partly done state and stalled for some reason when it reached to images with names starting with number 5. I also notice n-n.jpg's are skipped for some reason. I cannot see why. It is most likely a directory permission problem, if not top level folders in /img/p/ then the folders created within it. Depending on the number of products you have, several levels deep folders are created during conversion. I am afraid it is difficult to further diagnose w/o access to installation. If this was my installation, I would load the site in an IDE and run it in debug mode to see where it fails, short of this I am afraid I am out of suggestions. :(

Link to comment
Share on other sites

  • 2 weeks later...

Ok - thanks for the troubleshooting tips. I'm headed away this weekend and will follow up when I return.

 

Hey, just some info - I noticed that this problem is solved by deleting the standard prestashop pictures that are likely to be in your img/p folder if you upgraded, just like me.

If I deleted the pictures for macbook, for instance, the process would continue moving pictures until it hit, say, iPod pictures.

 

Then again, some pictures just would refuse to get moved anyways. Helped a bit - I just reuploaded the pictures that didn't want to get moved.

Link to comment
Share on other sites

Ok - thanks for the troubleshooting tips. I'm headed away this weekend and will follow up when I return.

 

Hey, just some info - I noticed that this problem is solved by deleting the standard prestashop pictures that are likely to be in your img/p folder if you upgraded, just like me.

If I deleted the pictures for macbook, for instance, the process would continue moving pictures until it hit, say, iPod pictures.

 

Then again, some pictures just would refuse to get moved anyways. Helped a bit - I just reuploaded the pictures that didn't want to get moved.

I tried restoring the stock images and moving them - same problem. I don't have that many pictures so will live with the old storage format.

Link to comment
Share on other sites

  • 3 weeks later...

I had a similar problem - I had over 30,000 image files in p. When I tried to move these to the new storage method the process failed, so I had a look at the functions which move the files. The functions are a bit limited in the way they handle errors. The main function also cannot cope if an image already exists with an image number it is trying to move (this can happen with bulk uploads when they go wrong and are then corrected and re-imported). Also the function does not check to see if the images it is moving are actually needed. Therefore I have rewritten the main function to handle every scenario I can think of. The script will create additional folder if needed to place duplicates (p->duplicates) and unused files (p->unused).

 

Try these at your own risk, however they work really well for me (PS 1.4.4.1). You may need to change the mkdir parts to set permissions to 777 rather than 755 (however, you should configure your hosting to work with 755 as you leave yourself open to hackers if you have to set ANY directories set to 777).

 

Replace the following function in classes->Image.php

 

public static function moveToNewFileSystem($max_execution_time = 0)

{

$start_time = time();

$image = null;

$product = null;

$default_lang = Configuration::get('PS_LANG_DEFAULT');

foreach (scandir(_PS_PROD_IMG_DIR_) as $file)

{

// matches the base product image or the thumbnails

if (preg_match('/^([0-9]+\-)([0-9]+)(\-(.*))?\.jpg$/', $file, $matches))

{

// don't recreate an image object for each image type

if (!$image || $image->id !== (int)$matches[2])

$image = new Image((int)$matches[2]);

 

if (!Validate::isLoadedObject($image))

{

//if it is not listed against any product we do not need it - put in the 'unused' folder

 

if(!file_exists(_PS_PROD_IMG_DIR_.'unused/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'unused', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'unused/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'unused/index.php');

}

}

 

 

$new_path = _PS_PROD_IMG_DIR_.'unused/'.$file;

rename(_PS_PROD_IMG_DIR_.$file, $new_path);

}

 

if (Validate::isLoadedObject($image))

{

// create the new folder if it does not exist

if (!$image->createImgFolder())

//return false;

return 'folder';

 

// check if it matches in the database against the correct product

$product = rtrim($matches[1], "-");

$sql = 'SELECT `id_product`

FROM `'._DB_PREFIX_.'image`

WHERE `id_image` = '.(int)$matches[2];

$number = Db::getInstance()->getValue($sql);

 

//if it is not listed against the correct product we do not need it - put in the 'unused' folder

if ($number != $product){

//return 'Does not match product listed in database for this image : '.$file//;

if(!file_exists(_PS_PROD_IMG_DIR_.'unused/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'unused', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'unused/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'unused/index.php');

}

}

$new_path = _PS_PROD_IMG_DIR_.'unused/'.$file;

rename(_PS_PROD_IMG_DIR_.$file, $new_path);

}

else{

 

// move the image

$new_path = _PS_PROD_IMG_DIR_.$image->getImgPath().(isset($matches[3]) ? $matches[3] : '').'.jpg';

 

// check if file already exists

if (file_exists($new_path)){

 

//if it is not listed against the correct product we do not need it - put in the 'unused' folder

if ($number != $product){

//return 'Does not match product listed in database for this image : '.$number;

if(!file_exists(_PS_PROD_IMG_DIR_.'unused/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'unused', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'unused/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'unused/index.php');

}

}

$new_path = _PS_PROD_IMG_DIR_.'unused/'.$file;

}

//if it is listed against the correct product then it is a duplicate already in the new storage system - put it in the 'duplicates' folder

else{

if(!file_exists(_PS_PROD_IMG_DIR_.'duplicates/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'duplicates', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'duplicates/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'duplicates/index.php');

}

}

$new_path = _PS_PROD_IMG_DIR_.'duplicates/'.$file.(isset($matches[3]) ? $matches[3] : '');

}

}

if (file_exists($new_path))

return 'A backed up copy of this duplicate or unused file already exists at this location : '.$new_path.' Please empty folders duplicates and unused in the img folder';

if (!@rename(_PS_PROD_IMG_DIR_.$file, $new_path) || !file_exists($new_path))

//return false;

return 'Could not move file : '.$file;

}

}

}

if ((int)$max_execution_time != 0 && (time() - $start_time > (int)$max_execution_time - 4))

return 'timeout';

}

return true;

}

 

Replace the following function admin->AdminImages.php

private function _moveImagesToNewFileSystem()

{

if (!Image::testFileSystem())

$this->_errors[] = Tools::displayError('Error: your server configuration is not compatible with the new image system. No images were moved');

else

{

ini_set('max_execution_time', $this->max_execution_time); // ini_set may be disabled, we need the real value

$this->max_execution_time = (int)ini_get('max_execution_time');

$result = Image::moveToNewFileSystem($this->max_execution_time);

if ($result === 'timeout')

$this->_errors[] = Tools::displayError('Not all images have been moved, server timed out before finishing. Click on \"Move images\" again to resume moving images');

//elseif ($result === false)

//$this->_errors[] = Tools::displayError('Error: some or all images could not be moved.');

elseif ($result != 1)

$this->_errors[] = Tools::displayError($result);

}

return (sizeof($this->_errors) > 0 ? false : true);

}

Link to comment
Share on other sites

Hi,

Thanks markb for reporting these changes to the forge. I implemented part of your fix (I want to keep the function as simple as possible) to make sure that you can move images even if there are unused demonstration images causing duplicates in the folder.

Next release of PrestaShop (1.4.5) will have the fix.

 

Regards,

Thomas

Link to comment
Share on other sites

Hi,

Thanks markb for reporting these changes to the forge. I implemented part of your fix (I want to keep the function as simple as possible) to make sure that you can move images even if there are unused demonstration images causing duplicates in the folder.

Next release of PrestaShop (1.4.5) will have the fix.

 

Regards,

Thomas

 

Thanks Mark and Thomas! I downloaded the image.php file from the forge and it worked great! Problem solved.

Link to comment
Share on other sites

  • 3 months later...

I had a similar problem - I had over 30,000 image files in p. When I tried to move these to the new storage method the process failed, so I had a look at the functions which move the files. The functions are a bit limited in the way they handle errors. The main function also cannot cope if an image already exists with an image number it is trying to move (this can happen with bulk uploads when they go wrong and are then corrected and re-imported). Also the function does not check to see if the images it is moving are actually needed. Therefore I have rewritten the main function to handle every scenario I can think of. The script will create additional folder if needed to place duplicates (p->duplicates) and unused files (p->unused).

 

Try these at your own risk, however they work really well for me (PS 1.4.4.1). You may need to change the mkdir parts to set permissions to 777 rather than 755 (however, you should configure your hosting to work with 755 as you leave yourself open to hackers if you have to set ANY directories set to 777).

 

Replace the following function in classes->Image.php

 

public static function moveToNewFileSystem($max_execution_time = 0)

{

$start_time = time();

$image = null;

$product = null;

$default_lang = Configuration::get('PS_LANG_DEFAULT');

foreach (scandir(_PS_PROD_IMG_DIR_) as $file)

{

// matches the base product image or the thumbnails

if (preg_match('/^([0-9]+\-)([0-9]+)(\-(.*))?\.jpg$/', $file, $matches))

{

// don't recreate an image object for each image type

if (!$image || $image->id !== (int)$matches[2])

$image = new Image((int)$matches[2]);

 

if (!Validate::isLoadedObject($image))

{

//if it is not listed against any product we do not need it - put in the 'unused' folder

 

if(!file_exists(_PS_PROD_IMG_DIR_.'unused/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'unused', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'unused/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'unused/index.php');

}

}

 

 

$new_path = _PS_PROD_IMG_DIR_.'unused/'.$file;

rename(_PS_PROD_IMG_DIR_.$file, $new_path);

}

 

if (Validate::isLoadedObject($image))

{

// create the new folder if it does not exist

if (!$image->createImgFolder())

//return false;

return 'folder';

 

// check if it matches in the database against the correct product

$product = rtrim($matches[1], "-");

$sql = 'SELECT `id_product`

FROM `'._DB_PREFIX_.'image`

WHERE `id_image` = '.(int)$matches[2];

$number = Db::getInstance()->getValue($sql);

 

//if it is not listed against the correct product we do not need it - put in the 'unused' folder

if ($number != $product){

//return 'Does not match product listed in database for this image : '.$file//;

if(!file_exists(_PS_PROD_IMG_DIR_.'unused/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'unused', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'unused/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'unused/index.php');

}

}

$new_path = _PS_PROD_IMG_DIR_.'unused/'.$file;

rename(_PS_PROD_IMG_DIR_.$file, $new_path);

}

else{

 

// move the image

$new_path = _PS_PROD_IMG_DIR_.$image->getImgPath().(isset($matches[3]) ? $matches[3] : '').'.jpg';

 

// check if file already exists

if (file_exists($new_path)){

 

//if it is not listed against the correct product we do not need it - put in the 'unused' folder

if ($number != $product){

//return 'Does not match product listed in database for this image : '.$number;

if(!file_exists(_PS_PROD_IMG_DIR_.'unused/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'unused', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'unused/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'unused/index.php');

}

}

$new_path = _PS_PROD_IMG_DIR_.'unused/'.$file;

}

//if it is listed against the correct product then it is a duplicate already in the new storage system - put it in the 'duplicates' folder

else{

if(!file_exists(_PS_PROD_IMG_DIR_.'duplicates/index.php')){

// Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.

$success = @mkdir(_PS_PROD_IMG_DIR_.'duplicates', 0755, true) || @chmod(_PS_PROD_IMG_DIR_.'unused', 0755);

 

// Create an index.php file in the new folder

if ($success && !file_exists(_PS_PROD_IMG_DIR_.'duplicates/index.php') && file_exists(_PS_PROD_IMG_DIR_.'index.php')){

copy(_PS_PROD_IMG_DIR_.'index.php', _PS_PROD_IMG_DIR_.'duplicates/index.php');

}

}

$new_path = _PS_PROD_IMG_DIR_.'duplicates/'.$file.(isset($matches[3]) ? $matches[3] : '');

}

}

if (file_exists($new_path))

return 'A backed up copy of this duplicate or unused file already exists at this location : '.$new_path.' Please empty folders duplicates and unused in the img folder';

if (!@rename(_PS_PROD_IMG_DIR_.$file, $new_path) || !file_exists($new_path))

//return false;

return 'Could not move file : '.$file;

}

}

}

if ((int)$max_execution_time != 0 && (time() - $start_time > (int)$max_execution_time - 4))

return 'timeout';

}

return true;

}

 

Replace the following function admin->AdminImages.php

private function _moveImagesToNewFileSystem()

{

if (!Image::testFileSystem())

$this->_errors[] = Tools::displayError('Error: your server configuration is not compatible with the new image system. No images were moved');

else

{

ini_set('max_execution_time', $this->max_execution_time); // ini_set may be disabled, we need the real value

$this->max_execution_time = (int)ini_get('max_execution_time');

$result = Image::moveToNewFileSystem($this->max_execution_time);

if ($result === 'timeout')

$this->_errors[] = Tools::displayError('Not all images have been moved, server timed out before finishing. Click on \"Move images\" again to resume moving images');

//elseif ($result === false)

//$this->_errors[] = Tools::displayError('Error: some or all images could not be moved.');

elseif ($result != 1)

$this->_errors[] = Tools::displayError($result);

}

return (sizeof($this->_errors) > 0 ? false : true);

}

Where can I find this file image.php, in my prestahop's folders? Also I'm not sure that I understand right, I have to replace all the code from image.php, or just a part of it?

 

Thank you!

Link to comment
Share on other sites

Where can I find this file image.php, in my prestahop's folders? Also I'm not sure that I understand right, I have to replace all the code from image.php, or just a part of it?

 

Thank you!

 

I found a file called image.php in "classes" directory.

Here the code from these file:

 

<?php
/*
* 2007-2011 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
*  @author PrestaShop SA <[email protected]>
*  @copyright  2007-2011 PrestaShop SA
*  @version  Release: $Revision: 7771 $
*  @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
*  International Registered Trademark & Property of PrestaShop SA
*/
class ImageCore extends ObjectModel
{
public  $id;
/** @var integer Image ID */
public   $id_image;

/** @var integer Product ID */
public  $id_product;

/** @var string HTML title and alt attributes */
public  $legend;

/** @var integer Position used to order images of the same product */
public  $position;

/** @var boolean Image is cover */
public  $cover;
/** @var string image extension */
public $image_format = 'jpg';

/** @var string path to index.php file to be copied to new image folders */
public $source_index;

/** @var string image folder */
protected $folder;

/** @var string image path without extension */
protected $existing_path;

protected $tables = array ('image', 'image_lang');

protected $fieldsRequired = array('id_product');
protected  $fieldsValidate = array('id_product' => 'isUnsignedId', 'position' => 'isUnsignedInt', 'cover' => 'isBool');
protected  $fieldsRequiredLang = array('legend');
protected  $fieldsSizeLang = array('legend' => 128);
protected  $fieldsValidateLang = array('legend' => 'isGenericName');

protected  $table = 'image';
protected  $identifier = 'id_image';

protected static $_cacheGetSize = array();

public function __construct($id = NULL, $id_lang = NULL)
{
 parent::__construct($id, $id_lang);
 $this->image_dir = _PS_PROD_IMG_DIR_;
 $this->source_index = _PS_PROD_IMG_DIR_.'index.php';
}

public function getFields()
{
 parent::validateFields();
 $fields['id_product'] = (int)($this->id_product);
 $fields['position'] = (int)($this->position);
 $fields['cover'] = (int)($this->cover);
 return $fields;
}

public function getTranslationsFieldsChild()
{
 parent::validateFieldsLang();
 return parent::getTranslationsFields(array('legend'));
}

public function delete()
{
 if (!parent::delete() ||
  !$this->deleteProductAttributeImage() ||
  !$this->deleteImage())
  return false;

 // update positions
 $result = Db::getInstance()->ExecuteS('
 SELECT *
 FROM `'._DB_PREFIX_.'image`
 WHERE `id_product` = '.(int)$this->id_product.'
 ORDER BY `position`');
 $i = 1;
 if ($result)
  foreach ($result AS $row)
  {
   $row['position'] = $i++;
   Db::getInstance()->AutoExecute(_DB_PREFIX_.$this->table, $row, 'UPDATE', '`id_image` = '.(int)($row['id_image']), 1);
  }

 return true;
}

/**
  * Return available images for a product
  *
  * @param integer $id_lang Language ID
  * @param integer $id_product Product ID
  * @return array Images
  */
public static function getImages($id_lang, $id_product)
{
 return Db::getInstance()->ExecuteS('
 SELECT *
 FROM `'._DB_PREFIX_.'image` i
 LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (i.`id_image` = il.`id_image`)
 WHERE i.`id_product` = '.(int)$id_product.' AND il.`id_lang` = '.(int)$id_lang.'
 ORDER BY i.`position` ASC');
}

/**
  * Return Images
  *
  * @return array Images
  */
public static function getAllImages()
{
 return Db::getInstance()->ExecuteS('
 SELECT `id_image`, `id_product`
 FROM `'._DB_PREFIX_.'image`
 ORDER BY `id_image` ASC');
}

/**
  * Return number of images for a product
  *
  * @param integer $id_product Product ID
  * @return integer number of images
  */
public static function getImagesTotal($id_product)
{
 $result = Db::getInstance()->getRow('
 SELECT COUNT(`id_image`) AS total
 FROM `'._DB_PREFIX_.'image`
 WHERE `id_product` = '.(int)($id_product));
 return $result['total'];
}

/**
  * Return highest position of images for a product
  *
  * @param integer $id_product Product ID
  * @return integer highest position of images
  */
public static function getHighestPosition($id_product)
{
 $result = Db::getInstance()->getRow('
 SELECT MAX(`position`) AS max
 FROM `'._DB_PREFIX_.'image`
 WHERE `id_product` = '.(int)($id_product));
 return $result['max'];
}

/**
  * Delete product cover
  *
  * @param integer $id_product Product ID
  * @return boolean result
  */
public static function deleteCover($id_product)
{
  if (!Validate::isUnsignedId($id_product))
   die(Tools::displayError());

 if (file_exists(_PS_TMP_IMG_DIR_.'product_'.$id_product.'.jpg'))
  unlink(_PS_TMP_IMG_DIR_.'product_'.$id_product.'.jpg');
 return Db::getInstance()->Execute('
 UPDATE `'._DB_PREFIX_.'image`
 SET `cover` = 0
 WHERE `id_product` = '.(int)($id_product));
}

/**
  *Get product cover
  *
  * @param integer $id_product Product ID
  * @return boolean result
  */
public static function getCover($id_product)
{
 return Db::getInstance()->getRow('
 SELECT * FROM `'._DB_PREFIX_.'image`
 WHERE `id_product` = '.(int)($id_product).'
 AND `cover`= 1');
}

/**
  * Copy images from a product to another
  *
  * @param integer $id_product_old Source product ID
  * @param boolean $id_product_new Destination product ID
  */
public static function duplicateProductImages($id_product_old, $id_product_new, $combinationImages)
{
 $imagesTypes = ImageType::getImagesTypes('products');
 $result = Db::getInstance()->ExecuteS('
 SELECT `id_image`
 FROM `'._DB_PREFIX_.'image`
 WHERE `id_product` = '.(int)($id_product_old));
 foreach ($result as $row)
 {
  $imageOld = new Image($row['id_image']);
  $imageNew = clone $imageOld;
  $imageNew->id_product = (int)($id_product_new);
  // A new id is generated for the cloned image when calling add()
  if ($imageNew->add())
	    {
   $new_path = $imageNew->getPathForCreation();
		 foreach ($imagesTypes AS $imageType)
		 {
 if (file_exists(_PS_PROD_IMG_DIR_.$imageOld->getExistingImgPath().'-'.$imageType['name'].'.jpg'))
 {
  if (!Configuration::get('PS_LEGACY_IMAGES'))
   $imageNew->createImgFolder();
  copy(_PS_PROD_IMG_DIR_.$imageOld->getExistingImgPath().'-'.$imageType['name'].'.jpg',
  $new_path.'-'.$imageType['name'].'.jpg');
 }
		 }
		    if (file_exists(_PS_PROD_IMG_DIR_.$imageOld->getExistingImgPath().'.jpg'))
			    copy(_PS_PROD_IMG_DIR_.$imageOld->getExistingImgPath().'.jpg', $new_path.'.jpg');
   self::replaceAttributeImageAssociationId($combinationImages, (int)($imageOld->id), (int)($imageNew->id));
	    }
  else
   return false;
 }
 return self::duplicateAttributeImageAssociations($combinationImages);
}
static protected function replaceAttributeImageAssociationId(&$combinationImages, $saved_id, $id_image)
{
 if (!isset($combinationImages['new']) OR !is_array($combinationImages['new']))
  return ;
 foreach ($combinationImages['new'] AS $id_product_attribute => $imageIds)
  foreach ($imageIds AS $key => $imageId)
   if ((int)($imageId) == (int)($saved_id))
 $combinationImages['new'][$id_product_attribute][$key] = (int)($id_image);
}
/**
* Duplicate product attribute image associations
* @param integer $id_product_attribute_old
* @return boolean
*/
public static function duplicateAttributeImageAssociations($combinationImages)
{
 if (!isset($combinationImages['new']) OR !is_array($combinationImages['new']))
  return true;
 $query = 'INSERT INTO `'._DB_PREFIX_.'product_attribute_image` (`id_product_attribute`, `id_image`) VALUES ';
 foreach ($combinationImages['new'] AS $id_product_attribute => $imageIds)
  foreach ($imageIds AS $imageId)
   $query .= '('.(int)($id_product_attribute).', '.(int)($imageId).'), ';
 $query = rtrim($query, ', ');
 return DB::getInstance()->Execute($query);
}
/**
  * Reposition image
  *
  * @param integer $position Position
  * @param boolean $direction Direction
  */
public function positionImage($position, $direction)
{
 $position = (int)($position);
 $direction = (int)($direction);

 // temporary position
 $high_position = Image::getHighestPosition($this->id_product) + 1;

 Db::getInstance()->Execute('
 UPDATE `'._DB_PREFIX_.'image`
 SET `position` = '.(int)($high_position).'
 WHERE `id_product` = '.(int)($this->id_product).'
 AND `position` = '.($direction ? $position - 1 : $position + 1));

 Db::getInstance()->Execute('
 UPDATE `'._DB_PREFIX_.'image`
 SET `position` = `position`'.($direction ? '-1' : '+1').'
 WHERE `id_image` = '.(int)($this->id));

 Db::getInstance()->Execute('
 UPDATE `'._DB_PREFIX_.'image`
 SET `position` = '.$this->position.'
 WHERE `id_product` = '.(int)($this->id_product).'
 AND `position` = '.(int)($high_position));
}

public static function getSize($type)
{
 if (!isset(self::$_cacheGetSize[$type]) OR self::$_cacheGetSize[$type] === NULL)
  self::$_cacheGetSize[$type] = Db::getInstance()->getRow('SELECT `width`, `height` FROM '._DB_PREFIX_.'image_type WHERE `name` = \''.pSQL($type).'\'');
  return self::$_cacheGetSize[$type];
}

/**
  * Clear all images in tmp dir
  */
public static function clearTmpDir()
{
 foreach (scandir(_PS_TMP_IMG_DIR_) AS $d)
  if (preg_match('/(.*)\.jpg$/', $d))
   unlink(_PS_TMP_IMG_DIR_.$d);
}
/**
 * Delete Image - Product attribute associations for this image
 */
public function deleteProductAttributeImage()
{
 return Db::getInstance()->Execute('
  DELETE
  FROM `'._DB_PREFIX_.'product_attribute_image`
  WHERE `id_image` = '.(int)($this->id)
 );
}

/**
 * Delete the product image from disk and remove the containing folder if empty
 * Handles both legacy and new image filesystems
 */
public function deleteImage()
{
 if (!$this->id)
  return false;

 // Delete base image
 if (file_exists($this->image_dir.$this->getExistingImgPath().'.'.$this->image_format))
  unlink($this->image_dir.$this->getExistingImgPath().'.'.$this->image_format);
 else
  return false;

 $files_to_delete = array();

 // Delete auto-generated images
 $imageTypes = ImageType::getImagesTypes();
 foreach ($imageTypes AS $imageType)
  $files_to_delete[] = $this->image_dir.$this->getExistingImgPath().'-'.$imageType['name'].'.'.$this->image_format;

 // Delete watermark image
 $files_to_delete[] = $this->image_dir.$this->getExistingImgPath().'-watermark.'.$this->image_format;
 // delete index.php
 $files_to_delete[] = $this->image_dir.$this->getImgFolder().'index.php';
 // Delete tmp images
 $files_to_delete[] = _PS_TMP_IMG_DIR_.'product_'.$this->id_product.'.'.$this->image_format;
 $files_to_delete[] = _PS_TMP_IMG_DIR_.'product_mini_'.$this->id_product.'.'.$this->image_format;

 foreach ($files_to_delete as $file)
  if (file_exists($file) && !@unlink($file))
   return false;

 // Can we delete the image folder?
 if (is_dir($this->image_dir.$this->getImgFolder()))
 {
  $delete_folder = true;
  foreach (scandir($this->image_dir.$this->getImgFolder()) as $file)
   if (($file != '.' && $file != '..'))
   {
 $delete_folder = false;
 break;
   }
 } 
 if (isset($delete_folder) && $delete_folder)
  @rmdir($this->image_dir.$this->getImgFolder());
 return true;
}

/**
 * Recursively deletes all product images in the given folder tree and removes empty folders.
 *
 * @param string $path folder containing the product images to delete
 * @param string $format image format
 * @return bool success
 */
public static function deleteAllImages($path, $format='jpg')
{
 if (!$path || !$format || !is_dir($path))
  return false;
 foreach (scandir($path) as $file)
 {
  if (preg_match('/^[0-9]+(\-(.*))?\.'.$format.'$/', $file))
   unlink($path.$file);
  elseif (is_dir($path.$file) && (preg_match('/^[0-9]$/', $file)))
   self::deleteAllImages($path.$file.'/', $format);
 }

 // Can we remove the image folder?
 $remove_folder = true;
 foreach (scandir($path) as $file)
  if (($file != '.' && $file != '..'&& $file != 'index.php'))
  {
   $remove_folder = false;
   break;
  }
 if ($remove_folder)
 {
  // we're only removing index.php if it's a folder we want to delete
  if (file_exists($path.'index.php'))
   @unlink ($path.'index.php');
  @rmdir($path);
 }

 return true;
}

/**
 * Returns image path in the old or in the new filesystem
 *
 * @ returns string image path
 */
public function getExistingImgPath()
{
 if (!$this->id)
  return false;

 if (!$this->existing_path)
 {
  if (Configuration::get('PS_LEGACY_IMAGES') && file_exists(_PS_PROD_IMG_DIR_.$this->id_product.'-'.$this->id.'.'.$this->image_format))
   $this->existing_path = $this->id_product.'-'.$this->id;
  else
   $this->existing_path = $this->getImgPath();
 }
 return $this->existing_path;
}

/**
 * Returns the path to the folder containing the image in the new filesystem
 *
 * @return string path to folder
 */
public function getImgFolder()
{
 if (!$this->id)
  return false;

 if (!$this->folder) 
  $this->folder = self::getImgFolderStatic($this->id);
 return $this->folder;
}

/**
 * Create parent folders for the image in the new filesystem
 *
 * @return bool success
 */
public function createImgFolder()
{
 if (!$this->id)
  return false;
 if (!file_exists(_PS_PROD_IMG_DIR_.$this->getImgFolder()))
 {
  // Apparently sometimes mkdir cannot set the rights, and sometimes chmod can't. Trying both.
  $success = @mkdir(_PS_PROD_IMG_DIR_.$this->getImgFolder(), 0755, true)
  || @chmod(_PS_PROD_IMG_DIR_.$this->getImgFolder(), 0755);

  // Create an index.php file in the new folder
  if ($success
   && !file_exists(_PS_PROD_IMG_DIR_.$this->getImgFolder().'index.php')
   && file_exists($this->source_index))
   return @copy($this->source_index, _PS_PROD_IMG_DIR_.$this->getImgFolder().'index.php');
 }
 return true;
}

/**
 * Returns the path to the image without file extension
 *
 * @return string path
 */
public function getImgPath()
{
 if (!$this->id)
  return false;

 $path = $this->getImgFolder().$this->id;
 return $path;
}

/**
 * Returns the path to the folder containing the image in the new filesystem
 *
 * @param mixed $id_image
 * @return string path to folder
 */
public static function getImgFolderStatic($id_image)
{
 if (!is_numeric($id_image))
  return false;
 $folders = str_split((string)$id_image);
 return implode('/', $folders).'/';
}
/**
 * Move all legacy product image files from the image folder root to their subfolder in the new filesystem.
 * If max_execution_time is provided, stops before timeout and returns string "timeout".
 * If any image cannot be moved, stops and returns "false"
 *
 * @return mixed success or timeout
 */
public static function moveToNewFileSystem($max_execution_time = 0)
{
 $start_time = time();
 $image = null;
 foreach (scandir(_PS_PROD_IMG_DIR_) as $file)
 {
  // matches the base product image or the thumbnails
  if (preg_match('/^([0-9]+\-)([0-9]+)(\-(.*))?\.jpg$/', $file, $matches))
  {
   // don't recreate an image object for each image type
   if (!$image || $image->id !== (int)$matches[2])
 $image = new Image((int)$matches[2]);

   if (Validate::isLoadedObject($image))
   {
 // create the new folder if it does not exist
 if (!$image->createImgFolder())
  return false;

 // move the image
 $new_path = _PS_PROD_IMG_DIR_.$image->getImgPath().(isset($matches[3]) ? $matches[3] : '').'.jpg';
 if (file_exists($new_path))
  return false;
 if (!@rename(_PS_PROD_IMG_DIR_.$file, $new_path) || !file_exists($new_path))
  return false;
   }
  }
  if ((int)$max_execution_time != 0 && (time() - $start_time > (int)$max_execution_time - 4))
   return 'timeout';
 }
 return true;
}

public static function testFileSystem()
{
 $safe_mode = ini_get('safe_mode');
 if ($safe_mode)
  return false;
 $folder1 = _PS_PROD_IMG_DIR_.'testfilesystem/';
 $test_folder = $folder1.'testsubfolder/';
 if (file_exists($test_folder))
 {
  @rmdir($test_folder);
  @rmdir($folder1);
 }
 if (file_exists($test_folder))
  return false;
 @mkdir($test_folder, 0755, true);
 @chmod($test_folder, 0755);
 if (!is_writeable($test_folder))
  return false;
 @rmdir($test_folder);
 @rmdir($folder1);
 if (file_exists($folder1))
  return false;
 return true;
}

/**
 * Returns the path where a product image should be created (without file format)
 *
 * @return string path
 */
public function getPathForCreation()
{
 if (!$this->id)
  return false;
 if (Configuration::get('PS_LEGACY_IMAGES'))
 {
  if (!$this->id_product)
   return false;
  $path = $this->id_product.'-'.$this->id;
 } else
 {
  $path = $this->getImgPath();
  $this->createImgFolder();
 }
 return _PS_PROD_IMG_DIR_.$path;
}
}

 

My problem is the same like the others that write here before me. When I want to upload an image of a pruduct, I get an red writed error, something like this "Error while copying image." and my image isn't displayed in the product description.

Link to comment
Share on other sites

  • 3 months later...
  • 3 weeks later...
  • 4 months later...
  • 9 months later...

Hello.

 

I was also running 1.4.4.1 and the product base had gotten quite large.

I needed to move the images in order to upgrade, the suggested fix worked excellent.

 

One note though, the AdminImages.php file is actually located in admin/tabs/

 

Many thanks!

Dragos.

Link to comment
Share on other sites

  • 2 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...