diff --git a/HomeSlide.php b/HomeSlide.php index 9253811..d6f5090 100644 --- a/HomeSlide.php +++ b/HomeSlide.php @@ -121,7 +121,7 @@ public function add($autodate = true, $null_values = false) } /** - * @return int + * @return bool * @throws PrestaShopDatabaseException * @throws PrestaShopException */ @@ -129,24 +129,25 @@ public function delete() { $res = true; - $images = $this->image; - foreach ($images as $image) { - if (preg_match('/sample/', $image) === 0) { - if ($image && file_exists(dirname(__FILE__) . '/images/' . $image)) { - $res &= @unlink(dirname(__FILE__) . '/images/' . $image); - } + // delete image files + foreach ($this->image as $image) { + $filepath = HomeSlider::getImageDir() . $image; + if ($image && file_exists($filepath)) { + $res = unlink($filepath) && $res; } } - $res &= $this->reOrderPositions(); + // reorder positions + $res = $this->reOrderPositions() && $res; - $res &= Db::getInstance()->execute(' + // delete slides + $res = Db::getInstance()->execute(' DELETE FROM `' . _DB_PREFIX_ . 'homeslider` WHERE `id_homeslider_slides` = ' . (int)$this->id - ); + ) && $res; - $res &= parent::delete(); - return $res; + // delete record + return parent::delete() && $res; } /** diff --git a/fixtures/fixtures.json b/fixtures/fixtures.json new file mode 100644 index 0000000..15b86a0 --- /dev/null +++ b/fixtures/fixtures.json @@ -0,0 +1,20 @@ +[ + { + "image": "sample-1.jpg", + "title": "Shop Tea", + "legend": "Shop Tea", + "description": "
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tristique in tortor et dignissim. Quisque non tempor leo. Maecenas egestas sem elit
- - - '; - } elseif ($i === 2) { - $slide->description[$language['id_lang']] = ' -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tristique in tortor et dignissim. Quisque non tempor leo. Maecenas egestas sem elit
- '; - } + $imageUrl = $this->processImage($dir . $entry['image'], $entry['image']); + foreach ($languages as $langId) { + $slide->title[$langId] = $entry['title']; + $slide->legend[$langId] = $entry['legend']; + $slide->url[$langId] = 'https://thirtybees.com'; + $slide->image[$langId] = $imageUrl; + $slide->description[$langId] = $entry['description']; } $slide->add(); } @@ -205,6 +182,9 @@ public function uninstall() $res = Configuration::deleteByName('HOMESLIDER_PAUSE') && $res; $res = Configuration::deleteByName('HOMESLIDER_LOOP') && $res; + // delete all images + static::cleanImages([]); + return $res; } @@ -406,9 +386,6 @@ protected function _postValidation() if (Tools::getValue('image_' . $language['id_lang']) != null && !Validate::isFileName(Tools::getValue('image_' . $language['id_lang']))) { $errors[] = $this->l('Invalid filename.'); } - if (Tools::getValue('image_old_' . $language['id_lang']) != null && !Validate::isFileName(Tools::getValue('image_old_' . $language['id_lang']))) { - $errors[] = $this->l('Invalid filename.'); - } } /* Checks title/url/legend/description for default lang */ @@ -425,9 +402,6 @@ protected function _postValidation() if (!Tools::isSubmit('has_picture') && (!isset($_FILES['image_' . $id_lang_default]) || empty($_FILES['image_' . $id_lang_default]['tmp_name']))) { $errors[] = $this->l('The image is not set.'); } - if (Tools::getValue('image_old_' . $id_lang_default) && !Validate::isFileName(Tools::getValue('image_old_' . $id_lang_default))) { - $errors[] = $this->l('The image is not set.'); - } } elseif (Tools::isSubmit('delete_id_slide') && (!Validate::isInt(Tools::getValue('delete_id_slide')) || !$this->slideExists((int)Tools::getValue('delete_id_slide')))) { /* Validation for deletion */ $errors[] = $this->l('Invalid slide ID'); @@ -452,7 +426,7 @@ protected function _postValidation() */ protected function _postProcess() { - $errors = array(); + $errors = []; $shop_context = Shop::getContext(); /* Processes Slider */ @@ -505,7 +479,7 @@ protected function _postProcess() $this->clearCache(); if (!$res) { - $errors[] = $this->displayError($this->l('The configuration could not be updated.')); + $errors[] = $this->l('The configuration could not be updated.'); } else { Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true) . '&conf=6&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name); } @@ -538,45 +512,31 @@ protected function _postProcess() /* Sets active */ $slide->active = (int)Tools::getValue('active_slide'); - /* Sets each langue fields */ + /* Sets each language fields */ $languages = Language::getLanguages(false); - foreach ($languages as $language) { - $slide->title[$language['id_lang']] = Tools::getValue('title_' . $language['id_lang']); - $slide->url[$language['id_lang']] = Tools::getValue('url_' . $language['id_lang']); - $slide->legend[$language['id_lang']] = Tools::getValue('legend_' . $language['id_lang']); - $slide->description[$language['id_lang']] = Tools::getValue('description_' . $language['id_lang']); + $langId = (int)$language['id_lang']; + $slide->title[$langId] = Tools::getValue('title_' . $langId); + $slide->url[$langId] = Tools::getValue('url_' . $langId); + $slide->legend[$langId] = Tools::getValue('legend_' . $langId); + $slide->description[$langId] = Tools::getValue('description_' . $langId); /* Uploads image and sets slide */ - $type = strtolower(substr(strrchr($_FILES['image_' . $language['id_lang']]['name'], '.'), 1)); - $imagesize = @getimagesize($_FILES['image_' . $language['id_lang']]['tmp_name']); - if (isset($_FILES['image_' . $language['id_lang']]) && - isset($_FILES['image_' . $language['id_lang']]['tmp_name']) && - !empty($_FILES['image_' . $language['id_lang']]['tmp_name']) && - !empty($imagesize) && - in_array( - strtolower(substr(strrchr($imagesize['mime'], '/'), 1)), array( - 'jpg', - 'gif', - 'jpeg', - 'png' - ) - ) && - in_array($type, array('jpg', 'gif', 'jpeg', 'png')) - ) { - $temp_name = tempnam(_PS_TMP_IMG_DIR_, 'PS'); - $salt = sha1(microtime()); - if ($error = ImageManager::validateUpload($_FILES['image_' . $language['id_lang']])) { - $errors[] = $error; - } elseif (!$temp_name || !move_uploaded_file($_FILES['image_' . $language['id_lang']]['tmp_name'], $temp_name)) { - return false; - } elseif (!ImageManager::resize($temp_name, dirname(__FILE__) . '/images/' . $salt . '_' . $_FILES['image_' . $language['id_lang']]['name'], null, null, $type)) { - $errors[] = $this->displayError($this->l('An error occurred during the image upload process.')); + if (isset($_FILES['image_' . $langId])) { + $fileEntry = $_FILES['image_' . $langId]; + $tempFile = null; + try { + $tempFile = $this->uploadImage($fileEntry); + if ($tempFile) { + $slide->image[$langId] = $this->processImage($tempFile, $fileEntry['name']); + } + } catch (Exception $e) { + $errors[] = sprintf($this->l('Failed to upload image for language %s: %s'), $language['name'], $e->getMessage()); + } finally { + if ($tempFile) { + unlink(@$tempFile); + } } - @unlink($temp_name); - $slide->image[$language['id_lang']] = $salt . '_' . $_FILES['image_' . $language['id_lang']]['name']; - } elseif (Tools::getValue('image_old_' . $language['id_lang']) != '') { - $slide->image[$language['id_lang']] = Tools::getValue('image_old_' . $language['id_lang']); } } @@ -585,11 +545,11 @@ protected function _postProcess() /* Adds */ if (!Tools::getValue('id_slide')) { if (!$slide->add()) { - $errors[] = $this->displayError($this->l('The slide could not be added.')); + $errors[] = $this->l('The slide could not be added.'); } } elseif (!$slide->update()) { /* Update */ - $errors[] = $this->displayError($this->l('The slide could not be updated.')); + $errors[] = $this->l('The slide could not be updated.'); } $this->clearCache(); } @@ -599,7 +559,7 @@ protected function _postProcess() $res = $slide->delete(); $this->clearCache(); if (!$res) { - $this->_html .= $this->displayError('Could not delete.'); + $errors[] = $this->l('Could not delete.'); } else { Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true) . '&conf=1&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name); } @@ -627,7 +587,8 @@ protected function _prepareHook() $slides = $this->getSlides(true); if (is_array($slides)) { foreach ($slides as &$slide) { - $slide['sizes'] = @getimagesize((dirname(__FILE__) . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . $slide['image'])); + $slide['imageUrl'] = static::getImageBaseUri() . $slide['image']; + $slide['sizes'] = @getimagesize(static::getImageDir() . $slide['image']); if (isset($slide['sizes'][3]) && $slide['sizes'][3]) { $slide['size'] = $slide['sizes'][3]; } @@ -836,7 +797,7 @@ public function getSlides($active = null) public function getAllImagesBySlidesId($id_slides, $active = null, $id_shop = null) { $this->context = Context::getContext(); - $images = array(); + $images = []; if (!isset($id_shop)) { $id_shop = $this->context->shop->id; @@ -919,7 +880,7 @@ public function renderList() array( 'link' => $this->context->link, 'slides' => $slides, - 'image_baseurl' => $this->_path . 'images/' + 'image_baseurl' => static::getImageBaseUri(), ) ); @@ -1042,7 +1003,7 @@ public function renderAddForm() 'fields_value' => $this->getAddFieldsValues(), 'languages' => $controller->getLanguages(), 'id_language' => $this->context->language->id, - 'image_baseurl' => $this->_path . 'images/' + 'image_baseurl' => static::getImageBaseUri(), ); $helper->override_folder = '/'; @@ -1302,4 +1263,112 @@ public function getSecureKey() { return Tools::encrypt($this->name); } + + /** + * Validates uploaded image file, and moves it to temp location + * + * @return string|false temp location + * + * @throws PrestaShopException + */ + protected function uploadImage($fileEntry) + { + if (empty($fileEntry['name']) || empty($fileEntry['tmp_name'])) { + return false; + } + // validate file type + $ext = strtolower(substr(strrchr($fileEntry['name'], '.'), 1)); + if (! in_array($ext, static::ALLOWED_EXTENSIONS)) { + throw new PrestaShopException(sprintf($this->l("Unsupported file extension %s"), $ext)); + } + if ($error = ImageManager::validateUpload($fileEntry)) { + throw new PrestaShopException($error); + } + $tempFile = tempnam(_PS_TMP_IMG_DIR_, $this->name . '_'); + if (! move_uploaded_file($fileEntry['tmp_name'], $tempFile)) { + throw new PrestaShopException($this->l("Failed to move file to temp location")); + } + return $tempFile; + } + + /** + * @param string $sourceFile + * + * @return string + * + * @throws PrestaShopException + */ + protected function processImage($sourceFile, $sourceFileName) + { + $imageSize = getimagesize($sourceFile); + if (! $imageSize) { + throw new PrestaShopException($this->l("Failed to resolve image size")); + } + $mimeType = strtolower(substr(strrchr($imageSize['mime'], '/'), 1)); + if (! in_array($mimeType, static::ALLOWED_EXTENSIONS)) { + throw new PrestaShopException(sprintf($this->l("Unsupported mime type %s"), $mimeType)); + } + + // resize file to target destination + $filename = md5(microtime()) . '_' . preg_replace('/[^a-zA-Z0-9._-]/', '', $sourceFileName); + $filepath = static::getImageDir() . $filename; + if (! ImageManager::resize($sourceFile, $filepath, null, null, $mimeType)) { + throw new PrestaShopException($this->l('An error occurred during the image resizing')); + } + return $filename; + } + + /** + * Helper method to delete unused image files from img directory + * + * @param array|null $imagesToKeep + * + * @throws PrestaShopDatabaseException + * @throws PrestaShopException + */ + public static function cleanImages($imagesToKeep = null) + { + if (is_null($imagesToKeep)) { + $imagesToKeep = array_column(Db::getInstance()->executeS((new DbQuery()) + ->select('DISTINCT(image) as image') + ->from('homeslider_slides_lang') + ), 'image'); + } + + $dir = static::getImageDir(); + foreach (scandir($dir) as $file) { + $ext = pathinfo($file, PATHINFO_EXTENSION); + if (in_array($ext, static::ALLOWED_EXTENSIONS)) { + if (! in_array($file, $imagesToKeep)) { + unlink($dir . $file); + } + } + } + } + + /** + * Returns path to image directory + * + * @return string + */ + public static function getImageDir() + { + $imageDir = rtrim(_PS_IMG_DIR_, '/') . '/homeslider/'; + // create directory if it doesn't exist yet + if (! file_exists($imageDir)) { + mkdir($imageDir); + } + return $imageDir; + } + + /** + * Returns base URI to images + * + * @return string + */ + public static function getImageBaseUri() + { + return rtrim(_PS_IMG_, '/') . '/homeslider/'; + } + } diff --git a/images/gray_next.png b/images/gray_next.png deleted file mode 100644 index 3552a60..0000000 Binary files a/images/gray_next.png and /dev/null differ diff --git a/images/gray_pager.png b/images/gray_pager.png deleted file mode 100644 index 9c3054d..0000000 Binary files a/images/gray_pager.png and /dev/null differ diff --git a/images/gray_prev.png b/images/gray_prev.png deleted file mode 100644 index 743d697..0000000 Binary files a/images/gray_prev.png and /dev/null differ diff --git a/images/sample-1.jpg b/images/sample-1.jpg deleted file mode 100644 index fe8545c..0000000 Binary files a/images/sample-1.jpg and /dev/null differ diff --git a/images/sample-2.jpg b/images/sample-2.jpg deleted file mode 100644 index 43b1171..0000000 Binary files a/images/sample-2.jpg and /dev/null differ diff --git a/images/sample-3.jpg b/images/sample-3.jpg deleted file mode 100644 index dd2a7ca..0000000 Binary files a/images/sample-3.jpg and /dev/null differ diff --git a/upgrade/index.php b/upgrade/index.php new file mode 100644 index 0000000..59283f8 --- /dev/null +++ b/upgrade/index.php @@ -0,0 +1,35 @@ + + * @author PrestaShop SA