yf_manage_shop_upload_images admin module

Fileplugins/shop/admin_modules/manage_shop/yf_manage_shop_upload_images.class.php
Useadmin URL ?object=manage_shop_upload_images

Public properties

A site sets them in its config with $PROJECT_CONF['manage_shop_upload_images']['NAME'] = ...;

PropertyDefaultDescription
$ALLOWED_MIME_TYPES ['application/zip' => 'zip', 'application/x-rar' => 'rar', 'application/x-tar' => 'tar', 'application/x-gzip' => 'gz']
$ARCHIVE_FOLDER null
$CONFINE_SERVER_PATH
bool
false SECURITY: "from server path" takes only a file inside ARCHIVE_FOLDER or SERVER_PATH_DIRS (realpath, so give an absolute path: a relative one resolves against the working directory); default false keeps any readable path, 4.0 flips
$MAX_IMAGE_SIZE 8196
$SAVE_PATH null
$SERVER_PATH_DIRS
array
[] More directories CONFINE_SERVER_PATH accepts, e.g. the FTP drop folder of the suppliers
$SUPPLIER_ID null

Public methods 8

public function resize_and_save_image($img, $id, $md5)
    public function resize_and_save_image($img, $id, $md5)
    {
        ini_set('memory_limit', '200M');
        $dirs = sprintf('%06s', $id);
        $dir2 = substr($dirs, -3, 3);
        $dir1 = substr($dirs, -6, 3);
        $ext = pathinfo($img, PATHINFO_EXTENSION);
        $new_path = $this->SAVE_PATH . $dir1 . '/' . $dir2 . '/';
        if ( ! file_exists($new_path)) {
            mkdir($new_path, 0777, true);
        }
        db()->begin();
        db()->insert(db('shop_product_images'), [
                        'product_id' => $id,
                        'md5' => $md5,
                        'date_uploaded' => ($_SERVER['REQUEST_TIME'] ?? null),
                ]);
        $i = db()->insert_id();

        $real_name = $new_path . 'product_' . $id . '_' . $i . '.jpg';
        $thumb_name = $new_path . 'product_' . $id . '_' . $i . module('manage_shop')->THUMB_SUFFIX . '.jpg';
        $big_name = $new_path . 'product_' . $id . '_' . $i . module('manage_shop')->FULL_IMG_SUFFIX . '.jpg';
        $watermark_name = PROJECT_PATH . SITE_WATERMARK_FILE;

        common()->make_thumb($img, $real_name, module('manage_shop')->BIG_X, module('manage_shop')->BIG_Y);
        common()->make_thumb($img, $thumb_name, module('manage_shop')->THUMB_X, module('manage_shop')->THUMB_Y);
        common()->make_thumb($img, $big_name, module('manage_shop')->BIG_X, module('manage_shop')->BIG_Y, $watermark_name);

        $A = db()->query_fetch('SELECT COUNT(*) AS cnt FROM ' . db('shop_product_images') . ' WHERE product_id=' . $id . ' AND is_default=1 AND active=1');
        if ($A['cnt'] == 0) {
            $A = db()->query_fetch('SELECT id FROM ' . db('shop_product_images') . ' WHERE product_id=' . $id . ' ORDER BY id DESC');
            db()->query('UPDATE ' . db('shop_product_images') . ' SET is_default=1 WHERE id=' . $A['id']);
        }
        db()->query('UPDATE `' . db('shop_products') . "` SET `image`='1' WHERE `id`=" . $id);
        db()->commit();
        module('manage_shop')->_product_images_add_revision('import', $id, $i);

        return $thumb_name;
    }
public function search_product_by_filename($folder, $supplier_id = false)
    public function search_product_by_filename($folder, $supplier_id = false)
    {
        $filename = basename($folder);
        $ext = pathinfo($filename, PATHINFO_EXTENSION);
        $filename = ltrim($filename, ' .-_+=/\|,!@#%~&*()');
        if (strpos($filename, '_')) {
            $articul = explode('_', $filename);
        } elseif (strpos($filename, '.')) {
            $articul = explode('.', $filename);
        } else {
            return 'Wrong filename';
        }
        if ( ! empty($articul[0])) {
            $articul = _es(strip_tags($articul[0]));
            $sql = 'SELECT id FROM ' . db('shop_products') . '
                                WHERE articul IN ("' . $articul . '","' . pathinfo($filename, PATHINFO_FILENAME) . '")
                                    AND supplier_id=' . $supplier_id;
            $product = db()->query_fetch($sql);
        } else {
            return 'Articul_not_found';
        }
        if (empty($product)) {
            return 'Product_not_found';
        }
        $md5 = md5_file($folder);
        $db_item = db()->query_fetch('SELECT id FROM ' . db('shop_product_images') . ' WHERE product_id=' . $product['id'] . " AND md5='" . $md5 . "'");
        if ( ! empty($db_item)) {
            return 'Dublicate image';
        }
        module('manage_shop')->_product_check_first_revision('product_images', $product['id']);
        $thumb_name = $this->resize_and_save_image($folder, $product['id'], $md5);
        return [
                        'status' => 'Success',
                        'img' => $thumb_name,
                        'id' => $product['id'],
                ];
    }

upload_images

public function upload_images()
    public function upload_images()
    {
        $SUPPLIER_ID = $this->SUPPLIER_ID;
        $ADMIN_INFO = db()->query_fetch('SELECT * FROM ' . db('sys_admin') . ' WHERE id=' . (int) (main()->ADMIN_ID));
        $SUPPLIER_INFO = db()->query_fetch('SELECT * FROM ' . db('shop_suppliers') . ' WHERE id=' . (int) $SUPPLIER_ID);
        $post_server_path = $this->_post_server_path();
        if (empty($_FILES) && empty($post_server_path)) {
            if ( ! $SUPPLIER_ID) {
                $suppliers = db()->get_2d('SELECT id, name FROM ' . db('shop_suppliers'));
                $form = form('', ['enctype' => 'multipart/form-data'])
                                        ->file('archive')
                                        ->select_box('supplier', $suppliers, ['desc' => 'Supplier', 'show_text' => 1])
                                        ->text('server_path', 'from server path')
                                        ->save('', 'Upload');
            } else {
                $form = form('', ['enctype' => 'multipart/form-data'])
                                        ->file('archive')
                                        ->save('', 'Upload');
            }
            return $form;
        }
        $SUPPLIER_ID = $this->_upload_supplier_id();
        $archive_name = null;
        $file_type = null;
        $uploaded = null;
        $new_name = null;
        if ($post_server_path) {
            $server_path = $this->_server_path($post_server_path);
            if ($server_path !== '' && file_exists($server_path) && is_readable($server_path)) {
                $archive_name = $server_path;
                $file_type = mime_content_type($archive_name);
                $uploaded = true;
            }
        } else {
            $file = ($_FILES['archive'] ?? null);
            file_put_contents($this->ARCHIVE_FOLDER . date('d-m-Y') . '.log', "\n[" . $file['name'] . "]\n", FILE_APPEND);
            $new_name = md5(rand() . microtime()) . '.' . pathinfo($file['name'], PATHINFO_EXTENSION);
            rename($file['name'], $new_name);
            $archive_name = $this->ARCHIVE_FOLDER . $new_name;
            $file_type = $file['type'];
            $uploaded = common()->upload_archive($archive_name);
        }
        if ( ! $uploaded) {
            return js_redirect('./?object=' . ($_GET['object'] ?? null) . '&action=' . ($_GET['action'] ?? null));
        }
        $EXTRACT_PATH = $this->ARCHIVE_FOLDER . $SUPPLIER_ID . '_id_' . date('H_i_s');
        if ( ! file_exists($EXTRACT_PATH)) {
            mkdir($EXTRACT_PATH, 0777, true);
        }
        $full_archive_name = escapeshellarg($archive_name);

        $tar = 'tar -xvf ' . $full_archive_name . ' -C ' . escapeshellarg($EXTRACT_PATH);
        $gz = 'tar -xzf ' . $full_archive_name . ' -C ' . escapeshellarg($EXTRACT_PATH);

        $ext = $this->_archive_ext($file_type);
        if ($ext == 'rar') {
            common()->rar_extract($archive_name, $EXTRACT_PATH);
        }
        if ($ext == 'zip') {
            common()->zip_extract($archive_name, $EXTRACT_PATH);
        }
        if ($ext == 'tar' || $ext == 'gz') {
            exec($ext == 'gz' ? $gz : $tar);
        }

        $result_files = _class('dir')->scan_dir($EXTRACT_PATH, true, '-f /\.(jpg|jpeg|png|gif|bmp)$/', '/__MACOSX/');
        $items = null;
        foreach ($result_files as $k => $v) {
            $status = $this->search_product_by_filename($v, $SUPPLIER_ID);
            $result = is_array($status) ? $status['status'] : $status;
            $filename = str_replace($EXTRACT_PATH, '', $v);
            $product_id = is_array($status) ? $status['id'] : '???';
            $items[] = [
                                'number' => $k,
                                'filename' => $filename,
                                'status' => $result,
                                'image' => is_array($status) ? str_replace(PROJECT_PATH, WEB_PATH, $status['img']) : '',
                                'edit_url' => is_array($status) ? './?object=manage_shop&action=product_edit&id=' . $status['id'] : '',
                        ];
            $log_str = $product_id . ' | ' . $result . ' | ' . $filename . ";\n";
            file_put_contents($this->ARCHIVE_FOLDER . date('d-m-Y') . '.log', $log_str, FILE_APPEND);
        }
        $replace = [
                        'items' => $items,
                ];
        _class('dir')->delete_dir($EXTRACT_PATH, true);
        $new_name && unlink($this->ARCHIVE_FOLDER . $new_name);
        common()->admin_wall_add(['archive with images uploaded by ' . $SUPPLIER_INFO['name'] . ' ' . $ADMIN_INFO['first_name'] . ' ' . $ADMIN_INFO['last_name']]);

        return tpl()->parse('manage_shop/upload_archive', $replace);
    }

Methods starting with _ hooks and helpers; not routable as page actions

_archive_ext

public function _archive_ext($mime_type)

Archive type of a MIME type, null when it is not allowed.

    public function _archive_ext($mime_type)
    {
        return is_string($mime_type) ? ($this->ALLOWED_MIME_TYPES[$mime_type] ?? null) : null;
    }

_init

public function _init()
    public function _init()
    {
        $this->ARCHIVE_FOLDER = PROJECT_PATH . 'uploads/tmp/';
        $this->SAVE_PATH = PROJECT_PATH . 'uploads/shop/products/';
        $this->SUPPLIER_ID = (int) db()->get_one('SELECT supplier_id FROM ' . db('shop_admin_to_supplier') . ' WHERE admin_id=' . (int) (main()->ADMIN_ID));
        set_time_limit(0);
    }
public function _post_server_path()

Posted "from server path" value; the supplier and server path fields are only offered to an admin without an assigned supplier, so an assigned admin's post is ignored.

    public function _post_server_path()
    {
        return $this->SUPPLIER_ID ? '' : ($_POST['server_path'] ?? '');
    }

_server_path

public function _server_path($path)

Archive path typed in "from server path", '' when it is refused.

    public function _server_path($path)
    {
        if ( ! is_string($path)) {
            return '';
        }
        $path = strip_tags(ltrim($path, ' .-_+=|,!@#%~&*();:\'"'));
        if ( ! $this->CONFINE_SERVER_PATH) {
            return $path;
        }
        // realpath() throws a ValueError on a NUL byte
        $real = $path !== '' && strpos($path, "\0") === false ? realpath($path) : false;
        if ($real === false || ! is_file($real)) {
            return '';
        }
        foreach (array_merge([$this->ARCHIVE_FOLDER], (array) $this->SERVER_PATH_DIRS) as $dir) {
            $real_dir = is_string($dir) && $dir !== '' && strpos($dir, "\0") === false ? realpath($dir) : false;
            if ($real_dir !== false && strpos($real, rtrim($real_dir, '/') . '/') === 0) {
                return $real;
            }
        }
        return '';
    }
public function _upload_supplier_id()

Supplier of an upload: the one assigned in shop_admin_to_supplier, else the posted one.

    public function _upload_supplier_id()
    {
        if ($this->SUPPLIER_ID) {
            return (int) $this->SUPPLIER_ID;
        }
        return (int) ($_POST['supplier'] ?? 0);
    }