* @copyright PrestaShop * @license http://www.opensource.org/licenses/osl-3.0.php Open-source licence 3.0 * @version 1.3 * */ include_once(realpath(PS_ADMIN_DIR.'/../').'/classes/AdminTab.php'); class AdminImages extends AdminTab { private $start_time = 0; private $max_execution_time = 7200; public function __construct() { $this->table = 'image_type'; $this->className = 'ImageType'; $this->lang = false; $this->edit = true; $this->delete = true; $this->fieldsDisplay = array( 'id_image_type' => array('title' => $this->l('ID'), 'align' => 'center', 'width' => 25), 'name' => array('title' => $this->l('Name'), 'width' => 140, 'size' => 16), 'width' => array('title' => $this->l('Width'), 'align' => 'right', 'suffix' => ' px', 'width' => 50, 'size' => 5), 'height' => array('title' => $this->l('Height'), 'align' => 'right', 'suffix' => ' px', 'width' => 50, 'size' => 5) ); parent::__construct(); } public function displayList() { parent::displayList(); $this->displayRegenerate(); } public function postProcess() { global $currentIndex; if (Tools::getValue('submitRegenerate'.$this->table)) { if ($this->tabAccess['edit'] === '1') { if ($this->_regenerateThumbnails(Tools::getValue('type'), Tools::getValue('erase'))) Tools::redirectAdmin($currentIndex.'&conf=9'.'&token='.$this->token); } else $this->_errors[] = Tools::displayError('You do not have permission to edit anything here.'); } else parent::postProcess(); } protected function _childValidation() { if (!Tools::getValue('id_image_type') AND Validate::isImageTypeName($typeName = Tools::getValue('name')) AND ImageType::typeAlreadyExists($typeName)) $this->_errors[] = Tools::displayError('this name already exists'); } public function displayForm($isMainTab = true) { global $currentIndex; parent::displayForm(); $obj = $this->loadObject(true); echo $obj->id ? $this->displayWarning($this->l('After modification, do not forget to regenerate thumbnails')) : ''; echo '
'.($obj->id ? '' : '').'
'.$this->l('Images').'
*

'.$this->l('Letters only (e.g., small, medium, large, extra-large)').'

*

'.$this->l('Maximum image width in pixels').'

*

'.$this->l('Maximum image height in pixels').'

getFieldValue($obj, 'products') ? 'checked="checked" ' : '').'/> getFieldValue($obj, 'products') ? 'checked="checked" ' : '').'/>

'.$this->l('This type will be applied to product images').'

getFieldValue($obj, 'categories') ? 'checked="checked" ' : '').'/> getFieldValue($obj, 'categories') ? 'checked="checked" ' : '').'/>

'.$this->l('This type will be applied to category images').'

getFieldValue($obj, 'manufacturers') ? 'checked="checked" ' : '').'/> getFieldValue($obj, 'manufacturers') ? 'checked="checked" ' : '').'/>

'.$this->l('This type will be applied to manufacturer images').'

getFieldValue($obj, 'suppliers') ? 'checked="checked" ' : '').'/> getFieldValue($obj, 'suppliers') ? 'checked="checked" ' : '').'/>

'.$this->l('This type will be applied to suppliers images').'

getFieldValue($obj, 'scenes') ? 'checked="checked" ' : '').'/> getFieldValue($obj, 'scenes') ? 'checked="checked" ' : '').'/>

'.$this->l('This type will be applied to scenes images').'

* '.$this->l('Required field').'
'; } /** * Display form for thumbnails regeneration * * @global string $currentIndex Current URL in order to keep current Tab */ public function displayRegenerate() { global $currentIndex; $types = array( 'categories' => $this->l('Categories'), 'manufacturers' => $this->l('Manufacturers'), 'suppliers' => $this->l('Suppliers'), 'scenes' => $this->l('Scenes'), 'products' => $this->l('Products') ); echo '

'.$this->l('Regenerate thumbnails').'

'.$this->l('Regenerates thumbnails for all existing product images').'.

'; $this->displayWarning($this->l('Please be patient, as this can take several minutes').'
'.$this->l('Be careful! Manually generated thumbnails will be erased by automatically generated thumbnails.')); echo '
'.$this->l('Regenerate thumbnails').'
'; foreach ($types as $k => $type) { $formats = ImageType::getImagesTypes($k); echo ' '; } echo '

'.$this->l('Uncheck this checkbox only if your server timed out and you need to resume the regeneration.').'

 
'; } /** * Delete resized image then regenerate new one with updated settings */ private function _deleteOldImages($dir, $type, $product = false) { $toDel = scandir($dir); foreach ($toDel AS $d) foreach ($type as $imageType) if (preg_match('/^[0-9]+\-'.($product ? '[0-9]+\-' : '').$imageType['name'].'\.jpg$/', $d) OR preg_match('/^([[:lower:]]{2})\-default\-(.*)\.jpg$/', $d)) if (file_exists($dir.$d)) unlink($dir.$d); } // Regenerate images private function _regenerateNewImages($dir, $type, $productsImages = false) { $errors = false; $toRegen = scandir($dir); if (!$productsImages) { foreach ($toRegen as $image) if (preg_match('/^[0-9]*\.jpg$/', $image)) foreach ($type AS $k => $imageType) { // Customizable writing dir $newDir = $dir; if ($imageType['name'] == 'thumb_scene') $newDir .= 'thumbs/'; if (!file_exists($newDir.substr($image, 0, -4).'-'.stripslashes($imageType['name']).'.jpg')) if (!imageResize($dir.$image, $newDir.substr($image, 0, -4).'-'.stripslashes($imageType['name']).'.jpg', intval($imageType['width']), intval($imageType['height']))) $errors = true; if (time() - $this->start_time > $this->max_execution_time - 4) // stop 4 seconds before the tiemout, just enough time to process the end of the page on a slow server return 'timeout'; } } else { $productsImages = Image::getAllImages(); foreach ($productsImages AS $k => $image) if (file_exists($dir.$image['id_product'].'-'.$image['id_image'].'.jpg')) foreach ($type AS $k => $imageType) { if (!file_exists($dir.$image['id_product'].'-'.$image['id_image'].'-'.stripslashes($imageType['name']).'.jpg')) if (!imageResize($dir.$image['id_product'].'-'.$image['id_image'].'.jpg', $dir.$image['id_product'].'-'.$image['id_image'].'-'.stripslashes($imageType['name']).'.jpg', intval($imageType['width']), intval($imageType['height']))) $errors = true; if (time() - $this->start_time > $this->max_execution_time - 4) // stop 4 seconds before the tiemout, just enough time to process the end of the page on a slow server return 'timeout'; } } return $errors; } // Regenerate no-pictures images private function _regenerateNoPictureImages($dir, $type, $languages) { $errors = false; foreach ($type AS $k => $imageType) foreach ($languages AS $language) { $file = $dir.$language['iso_code'].'.jpg'; if (!file_exists($file)) $file = _PS_PROD_IMG_DIR_.Language::getIsoById(intval(Configuration::get('PS_LANG_DEFAULT'))).'.jpg'; if (!file_exists($dir.$language['iso_code'].'-default-'.stripslashes($imageType['name']).'.jpg')) if (!imageResize($file, $dir.$language['iso_code'].'-default-'.stripslashes($imageType['name']).'.jpg', intval($imageType['width']), intval($imageType['height']))) $errors = true; } return $errors; } // Hook watermark optimization private function _regenerateWatermark($dir) { $result = Db::getInstance()->ExecuteS(' SELECT m.`name` FROM `'._DB_PREFIX_.'module` m LEFT JOIN `'._DB_PREFIX_.'hook_module` hm ON hm.`id_module` = m.`id_module` LEFT JOIN `'._DB_PREFIX_.'hook` h ON hm.`id_hook` = h.`id_hook` WHERE h.`name` = \'watermark\' AND m.`active` = 1'); if ($result AND sizeof($result)) { $productsImages = Image::getAllImages(); foreach ($productsImages AS $k => $image) if (file_exists($dir.$image['id_product'].'-'.$image['id_image'].'.jpg')) foreach ($result AS $k => $module) { if ($moduleInstance = Module::getInstanceByName($module['name']) AND is_callable(array($moduleInstance, 'hookwatermark'))) call_user_func(array($moduleInstance, 'hookwatermark'), array('id_image' => $image['id_image'], 'id_product' => $image['id_product'])); if (time() - $this->start_time > $this->max_execution_time - 4) // stop 4 seconds before the tiemout, just enough time to process the end of the page on a slow server return 'timeout'; } } } private function _regenerateThumbnails($type = 'all', $deleteOldImages = false) { $this->start_time = time(); 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'); $languages = Language::getLanguages(); $process = array( array('type' => 'categories', 'dir' => _PS_CAT_IMG_DIR_), array('type' => 'manufacturers', 'dir' => _PS_MANU_IMG_DIR_), array('type' => 'suppliers', 'dir' => _PS_SUPP_IMG_DIR_), array('type' => 'scenes', 'dir' => _PS_SCENE_IMG_DIR_), array('type' => 'products', 'dir' => _PS_PROD_IMG_DIR_), ); // Launching generation process foreach ($process as $k => $proc) { if ($type != 'all' && $type != $proc['type']) continue ; // Getting format generation $formats = ImageType::getImagesTypes($proc['type']); if ($type != 'all') { $format = strval(Tools::getValue('format_'.$type)); if ($format != 'all') foreach ($formats as $k => $form) if ($form['id_image_type'] != $format) unset($formats[$k]); } if ($deleteOldImages) $this->_deleteOldImages($proc['dir'], $formats, ($proc['type'] == 'products' ? true : false)); if (($return = $this->_regenerateNewImages($proc['dir'], $formats, ($proc['type'] == 'products' ? true : false))) === true) $this->_errors[] = Tools::displayError('Cannot write ').$proc['type'].Tools::displayError(' images. Please check the folder\'s writing permissions.'); elseif ($return == 'timeout') $this->_errors[] = Tools::displayError('Only part of the images have been regenerated, server timed out before the end.'); else { if ($proc['type'] == 'products') if ($this->_regenerateWatermark($proc['dir']) == 'timeout') $this->_errors[] = Tools::displayError('Server timed out, the watermark may not have been applied on all your images.'); if (!count($this->_errors)) if ($this->_regenerateNoPictureImages($proc['dir'], $formats, $languages)) $this->_errors[] = Tools::displayError('Cannot write no-picture image to (').$proc['type'].Tools::displayError(') images folder. Please check the folder\'s writing permissions.'); } } return (sizeof($this->_errors) > 0 ? false : true); } }