1<?php
2/**
3 * Copyright since 2007 PrestaShop SA and Contributors
4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
5 *
6 * NOTICE OF LICENSE
7 *
8 * This source file is subject to the Open Software License (OSL 3.0)
9 * that is bundled with this package in the file LICENSE.md.
10 * It is also available through the world-wide-web at this URL:
11 * https://opensource.org/licenses/OSL-3.0
12 * If you did not receive a copy of the license and are unable to
13 * obtain it through the world-wide-web, please send an email
14 * to license@prestashop.com so we can send you a copy immediately.
15 *
16 * DISCLAIMER
17 *
18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
19 * versions in the future. If you wish to customize PrestaShop for your
20 * needs please refer to https://devdocs.prestashop.com/ for more information.
21 *
22 * @author    PrestaShop SA and Contributors <contact@prestashop.com>
23 * @copyright Since 2007 PrestaShop SA and Contributors
24 * @license   https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
25 */
26
27namespace PrestaShop\PrestaShop\Core\Shop;
28
29use Configuration;
30use Context;
31use ImageManager;
32use PrestaShopException;
33use Shop;
34use Tools;
35
36/**
37 * Class LogoUploader used to manage upload of Shop logos and favicon.
38 */
39class LogoUploader
40{
41    /**
42     * @var Shop
43     */
44    private $shop;
45
46    /**
47     * @var array
48     */
49    private $errors = [];
50
51    public function __construct(Shop $shop)
52    {
53        $this->shop = $shop;
54    }
55
56    public function updateHeader()
57    {
58        if ($this->update('PS_LOGO', 'logo')) {
59            list($width, $height) = getimagesize(_PS_IMG_DIR_ . Configuration::get('PS_LOGO'));
60            Configuration::updateValue('SHOP_LOGO_HEIGHT', (int) round($height));
61            Configuration::updateValue('SHOP_LOGO_WIDTH', (int) round($width));
62        }
63    }
64
65    public function updateMail()
66    {
67        $this->update('PS_LOGO_MAIL', 'logo_mail');
68    }
69
70    public function updateInvoice()
71    {
72        $this->update('PS_LOGO_INVOICE', 'logo_invoice');
73    }
74
75    public function updateFavicon()
76    {
77        $shopId = (int) $this->shop->id;
78        if ($shopId == Configuration::get('PS_SHOP_DEFAULT')) {
79            $this->uploadIco('PS_FAVICON', _PS_IMG_DIR_ . 'favicon.ico');
80        }
81        if ($this->uploadIco('PS_FAVICON', _PS_IMG_DIR_ . 'favicon-' . $shopId . '.ico')) {
82            Configuration::updateValue('PS_FAVICON', 'favicon-' . $shopId . '.ico');
83        }
84
85        Configuration::updateGlobalValue('PS_FAVICON', 'favicon.ico');
86    }
87
88    /**
89     * Generic function which allows logo upload.
90     *
91     * @param string $fieldName
92     * @param string $logoPrefix
93     * @param array<string,array<string,string>> $files[] the array of files to avoid use $_POST
94     *
95     * @return bool
96     *
97     * @throws PrestaShopException in case of upload failure
98     */
99    public function update($fieldName, $logoPrefix, array $files = [])
100    {
101        $files = empty($files) ? $_FILES : $files;
102
103        if (isset($files[$fieldName]['tmp_name'], $files[$fieldName]['tmp_name'], $files[$fieldName]['size'])) {
104            if ($error = ImageManager::validateUpload($files[$fieldName], Tools::getMaxUploadSize())) {
105                throw new PrestaShopException($error);
106            }
107            $tmpName = tempnam(_PS_TMP_IMG_DIR_, 'PS');
108
109            if (!$tmpName || !move_uploaded_file($files[$fieldName]['tmp_name'], $tmpName)) {
110                throw new PrestaShopException(sprintf('%Upload of temporary file to %s has failed.', $tmpName));
111            }
112
113            $fileExtension = ($fieldName == 'PS_STORES_ICON') ? '.gif' : '.jpg';
114            $logoName = $this->getLogoName($logoPrefix, $fileExtension);
115
116            if ($fieldName == 'PS_STORES_ICON') {
117                if (!@ImageManager::resize($tmpName, _PS_IMG_DIR_ . $logoName, null, null, 'gif', true)) {
118                    throw new PrestaShopException(sprintf('An error occurred while attempting to copy shop icon %s.', $logoName));
119                }
120            } else {
121                if (!@ImageManager::resize($tmpName, _PS_IMG_DIR_ . $logoName)) {
122                    throw new PrestaShopException(sprintf('An error occurred while attempting to copy shop logo %s.', $logoName));
123                }
124            }
125
126            $idShop = $this->shop->id;
127            $idShopGroup = null;
128
129            if (!count($this->errors) && @filemtime(_PS_IMG_DIR_ . Configuration::get($fieldName))) {
130                if (Shop::isFeatureActive()) {
131                    $this->updateInMultiShopContext($idShop, $idShopGroup, $fieldName);
132                } else {
133                    @unlink(_PS_IMG_DIR_ . Configuration::get($fieldName));
134                }
135            }
136
137            Configuration::updateValue($fieldName, $logoName, false, $idShopGroup, $idShop);
138            unlink($tmpName);
139
140            return true;
141        }
142
143        return false;
144    }
145
146    private function updateInMultiShopContext(&$idShop, &$idShopGroup, $fieldName)
147    {
148        if (Shop::getContext() == Shop::CONTEXT_SHOP) {
149            $idShop = Shop::getContextShopID();
150            $idShopGroup = Shop::getContextShopGroupID();
151            Shop::setContext(Shop::CONTEXT_ALL);
152            $logoAll = Configuration::get($fieldName);
153            Shop::setContext(Shop::CONTEXT_GROUP);
154            $logoGroup = Configuration::get($fieldName);
155            Shop::setContext(Shop::CONTEXT_SHOP);
156            $logoShop = Configuration::get($fieldName);
157            if ($logoAll != $logoShop && $logoGroup != $logoShop && $logoShop != false) {
158                @unlink(_PS_IMG_DIR_ . Configuration::get($fieldName));
159            }
160        } elseif (Shop::getContext() == Shop::CONTEXT_GROUP) {
161            $idShopGroup = Shop::getContextShopGroupID();
162            Shop::setContext(Shop::CONTEXT_ALL);
163            $logoAll = Configuration::get($fieldName);
164            Shop::setContext(Shop::CONTEXT_GROUP);
165            if ($logoAll != Configuration::get($fieldName)) {
166                @unlink(_PS_IMG_DIR_ . Configuration::get($fieldName));
167            }
168        }
169    }
170
171    public function uploadIco($name, $destination, $files = [])
172    {
173        $files = empty($files) ? $_FILES : $files;
174
175        if (isset($files[$name]['tmp_name']) && !empty($files[$name]['tmp_name'])) {
176            if ($error = ImageManager::validateIconUpload($files[$name])) {
177                throw new PrestaShopException($error);
178            } elseif (!copy($_FILES[$name]['tmp_name'], $destination)) {
179                throw new PrestaShopException(Context::getContext()->getTranslator()->trans('An error occurred while uploading the favicon: cannot copy file "%s" to folder "%s".', [$files[$name]['tmp_name'], $destination], 'Admin.Design.Notification'));
180            }
181        }
182
183        return !count($this->errors);
184    }
185
186    /**
187     * @param string $logoPrefix
188     * @param string $fileExtension
189     *
190     * @return string
191     */
192    private function getLogoName($logoPrefix, $fileExtension)
193    {
194        $shopId = $this->shop->id;
195
196        $logoName = $logoPrefix
197            . '-'
198            . (int) Configuration::get('PS_IMG_UPDATE_TIME')
199            . (int) $shopId . $fileExtension;
200
201        if ($this->shop->getContext() == Shop::CONTEXT_ALL
202            || $shopId == 0
203            || Shop::isFeatureActive() == false
204        ) {
205            $logoName = $logoPrefix . '-' . (int) Configuration::get('PS_IMG_UPDATE_TIME') . $fileExtension;
206        }
207
208        return $logoName;
209    }
210}
211