Rhapsody Posted August 1, 2011 Share Posted August 1, 2011 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 More sharing options...
phrasespot Posted August 4, 2011 Share Posted August 4, 2011 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 More sharing options...
Rhapsody Posted August 4, 2011 Author Share Posted August 4, 2011 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 More sharing options...
phrasespot Posted August 4, 2011 Share Posted August 4, 2011 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 More sharing options...
Rhapsody Posted August 4, 2011 Author Share Posted August 4, 2011 The file installed is the same 7771 version you reference. The following is returned when I run test.php found 85 files and dirs folder created, (remember to delete it when done) Link to comment Share on other sites More sharing options...
phrasespot Posted August 5, 2011 Share Posted August 5, 2011 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 More sharing options...
Rhapsody Posted August 5, 2011 Author Share Posted August 5, 2011 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 More sharing options...
phrasespot Posted August 5, 2011 Share Posted August 5, 2011 I'm baffled.... Same here.. What you have in the /img/p/ directory? Give me a directory listing of that dir please. Link to comment Share on other sites More sharing options...
Rhapsody Posted August 5, 2011 Author Share Posted August 5, 2011 attached is a screenshot of the directory listing from cpanel. More after that, but should give you the idea. See the top directories where I changed directory from 755 to 777 permissions, but no change in the problem. Link to comment Share on other sites More sharing options...
phrasespot Posted August 5, 2011 Share Posted August 5, 2011 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 More sharing options...
Rhapsody Posted August 5, 2011 Author Share Posted August 5, 2011 Ok - thanks for the troubleshooting tips. I'm headed away this weekend and will follow up when I return. Link to comment Share on other sites More sharing options...
gregzkij Posted August 15, 2011 Share Posted August 15, 2011 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 More sharing options...
Rhapsody Posted August 20, 2011 Author Share Posted August 20, 2011 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 More sharing options...
markb Posted September 5, 2011 Share Posted September 5, 2011 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 More sharing options...
psyray Posted September 8, 2011 Share Posted September 8, 2011 Hi thanks for your post, it works really fine on 1.4.4.1 Link to comment Share on other sites More sharing options...
Thomas Didierjean Posted September 8, 2011 Share Posted September 8, 2011 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 More sharing options...
Rhapsody Posted September 9, 2011 Author Share Posted September 9, 2011 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 More sharing options...
cool cellphone case Posted September 11, 2011 Share Posted September 11, 2011 Thanks Mark and Thomas! I downloaded the image.php file from the forge and it worked great! Problem solved. where did you download it? could you please send me the link, thanks a lot, i have same problem, thanks. i try to replace the parts in the class-image.php but it won't work. do i have change other parts? Link to comment Share on other sites More sharing options...
shacker Posted September 18, 2011 Share Posted September 18, 2011 you need to g oto sourceforge.net, and search the prestashop projectn and download from here Link to comment Share on other sites More sharing options...
boy2litle Posted January 12, 2012 Share Posted January 12, 2012 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 More sharing options...
boy2litle Posted January 12, 2012 Share Posted January 12, 2012 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 More sharing options...
cyremia Posted April 12, 2012 Share Posted April 12, 2012 Any fix on this? Link to comment Share on other sites More sharing options...
mir-aus Posted May 3, 2012 Share Posted May 3, 2012 I have another problem, I can send the request to move img to new store, but Google does not index any of them!! any suggestion.? Link to comment Share on other sites More sharing options...
rseigel Posted September 11, 2012 Share Posted September 11, 2012 I found a fix that worked for me. Simply delete all the files in the img/tmp folder. Mine had a zillion in there and deleting them seemed to fix the issue. Link to comment Share on other sites More sharing options...
DragoshDX Posted July 7, 2013 Share Posted July 7, 2013 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 More sharing options...
ircykk Posted September 25, 2013 Share Posted September 25, 2013 Thank you markb! You saved my day! Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now