PhpExcel и изображения

Темы, не касающиеся фреймворка, но относящиеся к программированию в целом.
Ответить
eche
Сообщения: 36
Зарегистрирован: 2012.05.13, 11:50

PhpExcel и изображения

Сообщение eche »

Всем привет! Парсю excel файл с помощью PhpExcel .в файле каталог товаров. Название, описание, фото. И все бы ничего, но в excel фото не привязывается к конкретной ячейке. Phpexcel возвращает массив изображений. А как сопоставить изображение конкретному товару ума не приложу... Может кто сталкивался с подобным? Подскажите, пожалуйста как сделать?
Skiller
Сообщения: 627
Зарегистрирован: 2011.11.27, 00:21

Re: PhpExcel и изображения

Сообщение Skiller »

Приведи код подробней
eche
Сообщения: 36
Зарегистрирован: 2012.05.13, 11:50

Re: PhpExcel и изображения

Сообщение eche »

Код работает, массив с изображениями создается, текст из ячеек Excel (название товара и пр.) тоже парсится. Вся проблема в том, как сопоставить изображения товарам, поскольку в Икселе отсутствует привязка картинок к ячейкам. Вот в чем вопрос.
Skiller
Сообщения: 627
Зарегистрирован: 2011.11.27, 00:21

Re: PhpExcel и изображения

Сообщение Skiller »

Хм, 2007 или 2010 ? может от их форматов тоже зависит?
eche
Сообщения: 36
Зарегистрирован: 2012.05.13, 11:50

Re: PhpExcel и изображения

Сообщение eche »

Excel 2010. Картинки в массив добавляются в том порядке, в котором они были добавлены в документ Excel (то есть a[0]="картинка 1", a[1]="картинка 2",..., a[n]="картинка n"). Есть другой массив с названиями товаров (то есть b[0]="товар 1", b[1]="товар 2",..., b[n]="товар n"). Проблема заключается в том, чтобы сопоставить картинку и товар (то есть необходимо связать "картинку 3" и "товар 3").

Все бы ничего, но если пользователь изменит, например, "картинку 3", то она добавится в массив под последним номером и будет уже сопоставляться с последним товаром, а не с "товаром 3", как это должно быть. Поэтому-то у меня и возник вопрос, как связать картинку и товар.
Skiller
Сообщения: 627
Зарегистрирован: 2011.11.27, 00:21

Re: PhpExcel и изображения

Сообщение Skiller »

>>Все бы ничего, но если пользователь изменит, например, "картинку 3"...
В Exel?O_o Если ты про массив который php, то почему бы не сделать массив a[] этот где индексы будут индексы товаров?м?Не совсем возможно понял вопрос :(
eche
Сообщения: 36
Зарегистрирован: 2012.05.13, 11:50

Re: PhpExcel и изображения

Сообщение eche »

Да в excel. Файл выглядит так.A1-товар, B1-описание этого товара. C1-картинка(но это весьма условно т.к картинка не закреплена за ячейкой). Теперь рассмотрим пример. Заполняет пользователь эту таблицу товар1 ,описал его, вставил картинку,товар2 ,описал его, вставил картинку, товар3 ,описал его, вставил картинку. Потом смотрит, что-то не красивая картинка для товара 2 уберу ее и вставлю другую, убирает картинку для товара два и вставляет вместо нее другую картинку. Загружает файл на сервер и тут я начинаю парсить. Открываю файл беру значение из ячейки A1(Это имя первого товара ) и B1(это описание товара), дальше мне нужна картинка этого товара , но взять ее из С1 я не могу т.к. Картинка не привязана к ячейке и значение ячейки C1 будет NULL, но я могу взять эту картинку из массива картинок, только этот массив составляется не в порядке следования картинок в документе, а в порядке их добавления и поскольку пользователь поменял картинку для товара 2 элементы в нем будут в след порядке картинка 1 товара картинка 3 товара, картинка второго товара, поэтому я не знаю какой элемент в этом массиве соответствует товару 1
Если ты про массив который php, то почему бы не сделать массив a[] этот где индексы будут индексы товаров?
Дак ,собственно, вопрос в этом и заключается как сделать этот массив?
Аватара пользователя
mihnayan
Сообщения: 43
Зарегистрирован: 2012.03.15, 22:51
Контактная информация:

Re: PhpExcel и изображения

Сообщение mihnayan »

ИМХО в данном случае ничего не получиться, так как в Экселе действительно картинка ставиться "поверх" листа и не включена ни в какую из ячеек. Менять требования к пользователю по составлению файла Эксель. Или выцепить координаты картинок в файле и выяснить, как они расположены в визуальном порядке. Вообщем простым парсером не обойтись.
Любая техническая система должна быть идиотоустойчивой (с) один из университетских преподов
Skiller
Сообщения: 627
Зарегистрирован: 2011.11.27, 00:21

Re: PhpExcel и изображения

Сообщение Skiller »

Думаю mihnayan прав, наврятли получится такое сделать
stepanich
Сообщения: 3
Зарегистрирован: 2012.05.31, 17:29

Re: PhpExcel и изображения

Сообщение stepanich »

Нет это не возможно сделать...
sergasd
Сообщения: 45
Зарегистрирован: 2011.02.17, 20:24

Re: PhpExcel и изображения

Сообщение sergasd »

Писал недавно нечто похожее. У изображения есть метод getCoordinates(), который возвращает имя ячейки, в которой находится изображение.
Вот пример класса для импорта. Использовать его в таком виде не выйдет, но можно выдернуть оттуда импорт картинок. Формат файла xlsx.

Код: Выделить всё

<?php
/**
 * @class BaseImport
 * Класс для импорта продукции из excel файла
 *
 * @autor sergasd
 */



class BaseImport
{
    /**
     * @var ADB
    */
    private $db;

    /**
     * @var BaseLog
    */
    private $log;

    private $curentRow = 0;

    /**
     * @var PHPExcel
    */
    private $file;
    /**
     * @var PHPExcel_Worksheet
    */
    private $sheet;

    private $size = 0;

    private $images = array();




    private $fieldsMap = array(
        'name'     => 'A',
        'price'    => 'B',
        'vendor'   => 'C',
        'razmers'  => 'D',
        'page_id'  => 'F',
        'descr_s'  => 'G',
    );

    private $unsafeFields = array('name' => '', 'page_id' => '');

    private $settings = array(
        'basePath' => '',
        'baseUrl' => '',
        'postFileName' => '',
        'copyFileName' => '',
        'offset'     => '',
        'importSize' => 5,
        'importInterval' => 100,
        'imageField' => 'E',
        'imagesPath' => '',
        'resortFile' => '',
        'waitingMessage' => 'Ждите, идет загрузка',
    );






    /**
     * @param ADB $db
     * @param array $settings
    */
    public function __construct($db, $settings)
    {
        $this->db = $db;
        $this->settings = array_merge($this->settings, $settings);

        $this->log = new BaseLog($this->getOption('reportFile'));

        if(isset($_FILES[$this->getOption('postFileName')]))
        {
            move_uploaded_file($_FILES[$this->getOption('postFileName')]['tmp_name'], $this->getOption('copyFileName'));
        }

        $this->loadFile();
        $this->import($this->getOption('offset'));
    }

    /**
     * Возвращает настройку
     *
     * @param string $name
     * @param mixed $default
     * @return mixed
    */
    private function getOption($name, $default = '')
    {
        return isset($this->settings[$name]) ? $this->settings[$name] : $default;
    }




    /**
     * Загружает файл импорта и выполняет инициализацию
    */
    protected function loadFile()
    {
        $this->file = PHPExcel_IOFactory::load($this->getOption('copyFileName'));
        $this->sheet = $this->file->getActiveSheet();
        $this->size = sizeof($this->sheet->toArray());

        //prepare images
        foreach($this->sheet->getDrawingCollection() as $drawing)
        {
            $this->images[$drawing->getCoordinates()] = $drawing;
        }
    }

    /**
     * Импортирует некоторое кол-во строк из файла
     *
     * @param int $offset
    */
    protected function import($offset = 2)
    {
        if($offset == 2)
        {
            $this->log->deleteReport();
            $this->log->beginNewReport();
        }

        for($i = $offset; $i < $offset + $this->getOption('importSize'); $i++)
        {
            $this->curentRow = $i;
            if($this->checkFinish($i))
            {
                $this->finish();
            }

            $this->importRow($i);
        }

        $this->redirect();
    }



    /**
     * Импортирует отдельную строку из файла по ее номеру
     *
     * @param int $rowNumber
    */
    protected function importRow($rowNumber = 1)
    {
        $rowData = array();
        foreach($this->fieldsMap as $k => $v)
        {
            $rowData[$k] = $this->findCellValue($rowNumber, $k);
        }

        $this->updateRow($rowData);
    }


    /**
     * Обновляет информацию по продукту или создает новый продукт
     *
     * @param array $rowData
    */
    public function updateRow($rowData = array())
    {
        $category = $this->findCategory($rowData['page_id']);
        $categoryName = $rowData['page_id'];

        if($category === false)
        {
            $this->log->addMessage('error', 'Категория не найдена <strong>' . $categoryName . '</strong>');
            return;
        }

        $item = $this->findProduct($category, $rowData['name']);


        if($item === false)
        {
            //new product
            $this->log->addMessage('success', 'Добавлен новый товар в категорию <strong>' . $categoryName . '</strong> ' . $rowData['name']);
            $rowData['page_id'] = $category;
            $this->insertProduct($rowData);
        }
        else
        {
            //update product
            $this->log->addMessage('success', 'Обновлен товар в категории <strong>' . $categoryName . '</strong> ' . $rowData['name']);
            $rowData = array_diff_key($rowData, $this->unsafeFields);
            $this->updateProduct($item['id'], $rowData);
        }

    }

   /**
     * Находит ид категории по ее имени
     *
     * @param string $category
     * @return int | boolean
    */
    public function findCategory($category = '')
    {
        $category = array_reverse( explode('/', trim($category)) );

        $sql = 'SELECT `t1`.`name`, `t1`.`id` FROM `page` `t1` ';
        $sqlWhere = '';

        for($i = 1; $i < sizeof($category); $i++)
        {
            $nextTableAlias = $i + 1;
            $sql .= "JOIN `page` `t{$nextTableAlias}` ON(`t{$i}`.`parent_id` = `t{$nextTableAlias}`.`id`) ";

            $sqlWhere .= " AND `t{$nextTableAlias}`.`name` = '" . $this->db->quote($category[$i]) . "' ";
        }

        $sql .= 'WHERE t1.`name` = \'' . $this->db->quote($category[0]) . '\' ' . $sqlWhere . ' LIMIT 1';

        $result = $this->db->sgQuery($sql);

        return empty($result) ? false : $result[0]['id'];
    }

    /**
     * Находит продукт по ид категории и имени продукта
     *
     * @param int $categoryId
     * @param string $itemName
     * @return mixed
    */
    public function findProduct($categoryId = 0, $itemName = '')
    {
        $categoryId = intval($categoryId, 10);
        $result = $this->db->sgQuery(
        "SELECT * FROM `mod_prod_item` `t`
         WHERE `t`.`name` = '" .$this->db->quote($itemName). "' AND `page_id` = {$categoryId}
         LIMIT 1");

        return empty($result) ? false : $result[0];
    }


    /**
     * Вставляет в базу данных новый продукт
     *
     * @param array $rowData
    */
    public function insertProduct($rowData = array())
    {
        $names = array_keys($rowData);
        foreach($names as &$name)
        {
            $name = '`' . $name . '`';
        }
        $names = join(', ', $names);

        $values = array_values($rowData);
        foreach($values as &$value)
        {
            $value = "'" . $this->db->quote($value) . "'";
        }
        $values = join(', ', $values);


        $sql = "INSERT INTO `mod_prod_item` ({$names}) VALUES({$values})";

        $this->db->sgQuery($sql);

        $this->saveImage($this->db->insertId());
    }


    /**
     * Сохраняет изображение продукта
     *
     * @param int $productId
    */
    protected function saveImage($productId = 0)
    {
        $image = file_get_contents($this->getImagePathForRow($this->curentRow));

        file_put_contents($this->getOption('imagesPath') . "/p{$productId}.jpg" , $image);
        file_put_contents($this->getOption('imagesPath') . "/p_1_{$productId}.jpg" , $image);
        file_put_contents($this->getOption('imagesPath') . "/p_2_{$productId}.jpg" , $image);
        file_put_contents($this->getOption('imagesPath') . "/p_3_{$productId}.jpg" , $image);
    }


    /**
     * Обновляет информацию по продукту
     *
     * @param int $productId
     * @param array $updateData
    */
    public function updateProduct($productId, $updateData = array())
    {
        $productId = intval($productId, 10);
        $sql = 'UPDATE `mod_prod_item` SET ';

        foreach($updateData as $k => $v)
        {
            $sql .= "`{$k}` = '" . $this->db->quote($v) . "', ";
        }

        $sql = rtrim($sql, ' ,');
        $sql .= " WHERE `id` = {$productId} LIMIT 1";

        $this->db->sgQuery($sql);
    }

    /**
     * Находит значение ячейки по номеру строки и названию поля
     *
     * @param int $row
     * @param string $fieldName
     * @return mixed
    */
    protected function findCellValue($row, $fieldName)
    {
        $cellName = $this->fieldsMap[$fieldName] . $row;
        return iconv('utf-8', 'windows-1251', $this->sheet->getCell($cellName)->getValue());
    }

    /**
     * Возвращает изображение для номера строки
     *
     * @param int $row
     * @return mixed
    */
    protected function getImagePathForRow($row)
    {
        $cell = $this->getOption('imageField') . $row;
        return isset($this->images[$cell]) ? $this->images[$cell]->getPath() : false;
    }



    /**
     * Проверка закончен импорт или нет
     *
     * @param int $rowNum
     * @return boolean
    */
    protected function checkFinish($rowNum = 0)
    {
        return $rowNum > $this->size;
    }




    /**
     * Функция вызывается при завершении итерации импорта
    */
    protected function redirect()
    {
        $this->log->addAllMessages();

        $url = '/site_engine/edit/index2.php?' . http_build_query(array(
            'subpage' => 'automate',
            'type'    => 'xlsximport',
            'offset'  => $this->curentRow,
        ));

        $js = <<<EOD
        <script>
        (function(){
            setTimeout(function(){
                window.location.href = "{$url}";
            }, {$this->getOption('importInterval')});
        })();
        </script>
EOD;
        echo $this->getOption('waitingMessage') . $js;
        die;
    }

    /**
     * Функция вызывается при завершении импорта
    */
    protected function finish()
    {
        $this->log->addAllMessages();

        echo '
        <a style="text-decoration:underline;" target="_blank" href="' . $this->getOption('baseUrl') . '/file/automate/xlsx/report.html">Смотреть отчет</a> <br />
        <a style="text-decoration:underline;" href="/site_engine/edit/index2.php?subpage=automate" >Назад</a>';

        $this->log->endReport();
        die;
    }
}

 
eche
Сообщения: 36
Зарегистрирован: 2012.05.13, 11:50

Re: PhpExcel и изображения

Сообщение eche »

Огромное спасибо!
Ответить