utf8_decode / utf8 / PHPExcel

Активист

Активист
Команда форума
Всем доброго вечера. Давно меня тут не было))

Подскажите маленько по теории:

Есть масса XLS файлов, разных. Есть прекрасный PHPExcel, есть примерно следующий код:
PHP:
<?php
class exchange_import_xls_rules_2 {
        protected $data = array();
        protected $PHPExcelReaderObject;


        /**
         * Get loaded PHPExcel Reader object (from loaded method)
         * @return PHPExcel
         */
        protected function _reader() {
                return $this->PHPExcelReaderObject;
        }
                
        public function load($filename, $sheet = 0) {
                try {
                        if (!file_exists($filename) || !is_readable($filename)) {
                                throw new Exception("{$filename} is no readable");
                        }

                        PHPExcel_Settings::setLocale("ru");
                        
                        $this->PHPExcelReaderObject = PHPExcel_IOFactory::load($filename);
                        /* $sheet = $objPHPExcel->setActiveSheetIndex(0);
                        
                        foreach ($sheet->getRowIterator() as $row) {
                                foreach ($row->getCellIterator() as $_cindex => $cell) {
                                        $this->data[$row->getRowIndex()][$_cindex+1] = utf2cp($cell->getCalculatedValue());
                                }
                        }*/
                        
                } catch(Exception $e) {
                        return $this;
                }
        
                return $this;
        }
        
        public function process(exchange_import_xls $import, $sheet = null) {
                // @todo sheet factory
                $this->process_type_sheet_1();
        }
        
        protected function process_type_sheet_1() {
                $sheet = $this->_reader()->setActiveSheetIndex(0);
                
                $categories = array();
                
                for ($row = 1; $row < $sheet->getHighestRow(); $row++) {
                        for ($column = 0; $column < PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn()); $column++) {
                                $value = iconv("utf8", "cp1251", $sheet->getCellByColumnAndRow($column, $row)->getCalculatedValue());
 if ($column == 1) {
                                        $font = $sheet->getStyleByColumnAndRow($column, $row)->getFont();
                                        
                                        if ($font->getName() == "Arial" && $font->getSize() == 14 && $font->getBold()) {
                                                $categories[] = array($value);
                                                echo "<h1>{$value}</h1>";
                                                continue;
                                        }
                                        
                                        if ($font->getName() == "Arial" && $font->getSize() == 10 && $font->getBold()) {
                                                $categories[1] = $value;
                                                echo "<h2>{$value}</h2>";
                                                 continue;
                                        }
                                }
                        } 
                } 
                
                
                var_dump($sheet->getHighestColumn());
                var_dump($sheet->getHighestRow());
                exit();
        }
                
}
Кодировка.
Собственно с 95% прайсов работает нормально.

Где-то для получения корректного value надо применить $value = utf8_decode($sheet->getCellByColumnAndRow($column, $row)->getCalculatedValue());
Причем на выходе CP1251. В мане "utf8_decode — Преобразует строку с ISO-8859-1 символами кодированную в UTF-8 в однобайтную ISO-8859-1", но кодировкой ISO-8859-1 там и не пахнет на выходе windows-1251.
(Видимо генератор такого прайса - 1C или иной софт, не понятна суть решения проблемы).


Собственно помогите понять в теории и практики смысл utf8_decode и то, как понять, для какого прайса ее применять, а для какого нет.

Вот небольшой дамп данных из такого прайса:
PHP:
echo "Claer: ".$sheet->getCellByColumnAndRow($column, $row)->getCalculatedValue()."<br>";
echo "Iconv: ", iconv("utf8", "cp1251", $sheet->getCellByColumnAndRow($column, $row)->getCalculatedValue())."<br>";
echo "MB: ", mb_convert_encoding($sheet->getCellByColumnAndRow($column, $row)->getCalculatedValue(), "cp1251", "utf8")."<br>";
echo "MB (from ISO): ", mb_convert_encoding($sheet->getCellByColumnAndRow($column, $row)->getCalculatedValue(), "cp1251", "iso-8859-1")."<br>";
echo "UTF8 Decode: ", utf8_decode($sheet->getCellByColumnAndRow($column, $row)->getCalculatedValue())."<br>";
Код:
Claer: ГЋГ±ГІГ ГІГЄГЁ Г’ГЊГ– ГГ  ñêëà äà õ
Iconv:
Notice: iconv() [function.iconv]: Detected an illegal character in input string in /var/www/sluxe.web.local/httpdocs/modules/exchange/objects/import_xls_rules_1.php on line 29

MB: ??????? ??? ?? ???????
MB (from ISO): ???±??? ?????? ?????? ??  ?±???«? ?¤? ?µ
UTF8 Decode: Остатки ТМЦ на складах
 

Активист

Активист
Команда форума
Может кому пригодится: суть проблемы заключается в том, что видимо уважаемые 1C-ники, не читают спецификаций, и обертывают cp1251 функцией utf8_encode, что делать ненужно. Но работает и пох.
Как профиксить не знаю, но нормализовал так:

PHP:
$v1 = "Latin symbols | ".(utf8_encode("Розничные цена (руб.)")).""; // broken
$v2 = "Latin symbols | ".(iconv("cp1251", "utf8", "Розничные цена (руб.)")).""; // valid

echo "Broked string charset detected: ".(mb_detect_encoding($v1, mb_detect_order()))." and ".(mb_check_encoding($v1, "utf8") ? "valid" : "invalid")."\n"; 
echo "Valid string charset detected: ".(mb_detect_encoding($v2, mb_detect_order()))." and ".(mb_check_encoding($v2, "utf8") ? "valid" : "invalid")."\n";

echo "\nOriginal:\n";
var_dump($v1, $v2);
echo "\nBroken:\n";
var_dump($v1, utf8_decode($v1));
echo "\nValid:\n";
var_dump($v2, utf8_decode($v2));
echo "\nNormalize:\n";
var_dump(utf8_to_cp1251($v1), utf8_to_cp1251($v2));

exit();

function utf8_to_cp1251($string) {
	return utf8_encode($decoded = utf8_decode($string)) === $string ? $decoded : iconv("utf8", "cp1251", $string);
}

/*

Broked string charset detected: UTF-8 and valid
Valid string charset detected: UTF-8 and valid

Original:
string(53) "Latin symbols | ÐîçГГЁГ·Гûå öåГГ  (ðóá.)"
string(53) "Latin symbols | Розничные цена (руб.)"

Broken:
string(53) "Latin symbols | ÐîçГГЁГ·Гûå öåГГ  (ðóá.)"
string(37) "Latin symbols | Розничные цена (руб.)"

Valid:
string(53) "Latin symbols | Розничные цена (руб.)"
string(37) "Latin symbols | ????????? ???? (???.)"

Normalize:
string(37) "Latin symbols | Розничные цена (руб.)"
string(37) "Latin symbols | Розничные цена (руб.)"

*/

// PHP 5.3.3-7+squeeze15
 

borodatych

недавненько
Здравствуйте.

Вы не поверите, до сих пор актуально.
Сам бы не догадался до utf8_encode / utf8_decode .
Как вы вообще к этому пришли?
 

AnrDaemon

Продвинутый новичок
В смысле "один урод использовал utf8_encode, а проверить на кириллице не додумался".
Причину, как и решение, я нашёл сам. Мне для этого гугл не нужен, где документация на PHP лежит, я и так знаю, и читать я ещё не разучился.
А в ней английским по белому написано, что utf8_* работает только с ISO-8859-1
 

borodatych

недавненько
@AnrDaemon, вы меня не правильно поняли.
Я потерял кучу времени на решение этого вопроса, пока гугл мне не отдал текущую страницу, где добрый человек поделился решением.
Как вы догадались, что именно "один урод использовал utf8_encode", а не что то другое?
Я до этой ситуации даже не знал о существовании utf8_encode и utf8_decode.
Вот что я спрашивал, что бы понять ход мыслей.
 

AnrDaemon

Продвинутый новичок
Как догадался? http://phpfaq.ru/debug
Если на строчке А у тебя всё окей, а на строчке Б - проблема, то проблема явно где-то между этими двумя строчками. Берём дебаггер и ищем проблему.
 

borodatych

недавненько
Как догадался? http://phpfaq.ru/debug
Если на строчке А у тебя всё окей, а на строчке Б - проблема, то проблема явно где-то между этими двумя строчками. Берём дебаггер и ищем проблему.
Вы меня наверное не услышали?!

То что проблема в кодировке, это я нашел, то есть вопрос про А и Б закрываем - место локализовано.
Идем дальше, проблема с кодировкой. И?
Что вам из вашей ссылки указало на то что нужно заюзать именно utf8_decode ?
var_dump ?
У меня нет идей, раскройте карты.
Я использую print_r вместо var_dump, но навряд ли var_dump показывает еще и кодировку! Или все же?!
 

fixxxer

К.О.
Партнер клуба
Да чисто по опыту видно, когда то, что должно быть в 1251, при преобразовании в utf8 выглядит как мусор с кучей букв Г, это оно самое.
 

AnrDaemon

Продвинутый новичок
Что вам из вашей ссылки указало на то что нужно заюзать именно utf8_decode ?
У меня была другая проблема. Я же писал.
Код:
Index: util.php
===================================================================
--- util.php    (revision 319)
+++ util.php    (revision 320)
@@ -30,5 +30,5 @@

 function ConvertToXmlAttribute( $value )
 {
-   return utf8_encode( htmlspecialchars( $value ) ) ;
+   return htmlspecialchars( iconv( NULL, 'UTF-8', $value ) );
 }
 
Сверху