Как справиться с разными кодировками файлов xls в PHP? - PullRequest
1 голос
/ 21 марта 2011

Я разрабатываю php-скрипт, включающий разбор данных из файлов xls.Я использую библиотеку phpexcelreader .Все в основном работает, но я наткнулся на странную проблему.Некоторые файлы анализируются неправильно.Похоже, что файлы XLS могут использовать различные кодировки символов внутри.По крайней мере, тогда я передаю вывод из моего скрипта через iconv -f cp1251 -t utf8, строки исправляются.

Phpexcelreader имеет опцию для задания выходной кодировки, но, похоже, ему не хватает возможности обнаружить входную кодировку.Есть идеи?

Ответы [ 3 ]

2 голосов
/ 21 марта 2011

Свойство _defaultEncoding объекта рабочей книги может содержать кодировку, используемую файлом Excel, и затем она используется для обработки преобразования в UTF-16LE читателем, но при этом не предпринимается никаких усилий для идентификации самой внутренней кодировки .

Если вы определите

define('SPREADSHEET_EXCEL_READER_TYPE_CODEPAGE',  0x0042);

среди других определений SPREADSHEET_EXCEL_READER_TYPE, а затем измените оператор switch, начиная со строки 464, чтобы включить регистр для SPREADSHEET_EXCEL_READER_TYPE_CODEPAGE. Логика для этого случая должна быть примерно такой:

$length = $this->_GetInt2d($this->_data, $pos + 2);
$recordData = substr($this->_data, $pos + 4, $length);

// move stream pointer to next record
$pos += 4 + $length;

// offset: 0; size: 2; code page identifier
$codepage = $this->_GetInt2d($recordData, 0);
$codepage = $this->_CodePageNumberToName($codepage)

Воссоздайте метод _GetInt2d (который, кажется, был удален из кода в какой-то момент) как

function _GetInt2d($data, $pos)
{
    return ord($data[$pos]) | (ord($data[$pos + 1]) << 8);
}

и создайте метод _CodePageNumberToName для возврата имени кодовой страницы из ее числового значения:

function _CodePageNumberToName($codePage = '1252')
{
    switch ($codePage) {
        case 367:   return 'ASCII';     break;  //  ASCII
        case 437:   return 'CP437';     break;  //  OEM US
        case 720:   throw new Exception('Code page 720 not supported.');
                                        break;  //  OEM Arabic
        case 737:   return 'CP737';     break;  //  OEM Greek
        case 775:   return 'CP775';     break;  //  OEM Baltic
        case 850:   return 'CP850';     break;  //  OEM Latin I
        case 852:   return 'CP852';     break;  //  OEM Latin II (Central European)
        case 855:   return 'CP855';     break;  //  OEM Cyrillic
        case 857:   return 'CP857';     break;  //  OEM Turkish
        case 858:   return 'CP858';     break;  //  OEM Multilingual Latin I with Euro
        case 860:   return 'CP860';     break;  //  OEM Portugese
        case 861:   return 'CP861';     break;  //  OEM Icelandic
        case 862:   return 'CP862';     break;  //  OEM Hebrew
        case 863:   return 'CP863';     break;  //  OEM Canadian (French)
        case 864:   return 'CP864';     break;  //  OEM Arabic
        case 865:   return 'CP865';     break;  //  OEM Nordic
        case 866:   return 'CP866';     break;  //  OEM Cyrillic (Russian)
        case 869:   return 'CP869';     break;  //  OEM Greek (Modern)
        case 874:   return 'CP874';     break;  //  ANSI Thai
        case 932:   return 'CP932';     break;  //  ANSI Japanese Shift-JIS
        case 936:   return 'CP936';     break;  //  ANSI Chinese Simplified GBK
        case 949:   return 'CP949';     break;  //  ANSI Korean (Wansung)
        case 950:   return 'CP950';     break;  //  ANSI Chinese Traditional BIG5
        case 1200:  return 'UTF-16LE';  break;  //  UTF-16 (BIFF8)
        case 1250:  return 'CP1250';    break;  //  ANSI Latin II (Central European)
        case 1251:  return 'CP1251';    break;  //  ANSI Cyrillic
        case 0:                                 //  CodePage is not always correctly set when the xls file was saved by Apple's Numbers program
        case 1252:  return 'CP1252';    break;  //  ANSI Latin I (BIFF4-BIFF7)
        case 1253:  return 'CP1253';    break;  //  ANSI Greek
        case 1254:  return 'CP1254';    break;  //  ANSI Turkish
        case 1255:  return 'CP1255';    break;  //  ANSI Hebrew
        case 1256:  return 'CP1256';    break;  //  ANSI Arabic
        case 1257:  return 'CP1257';    break;  //  ANSI Baltic
        case 1258:  return 'CP1258';    break;  //  ANSI Vietnamese
        case 1361:  return 'CP1361';    break;  //  ANSI Korean (Johab)
        case 10000: return 'MAC';       break;  //  Apple Roman
        case 32768: return 'MAC';       break;  //  Apple Roman
        case 32769: throw new Exception('Code page 32769 not supported.');
                                        break;  //  ANSI Latin I (BIFF2-BIFF3)
        case 65001: return 'UTF-8';     break;  //  Unicode (UTF-8)
    }
}

И сохранить возвращаемое значение в $ _defaultEncoding

В качестве альтернативы, переключитесь на считыватель Excel, который может правильно обрабатывать кодовую страницу

0 голосов
/ 19 апреля 2018

для персидского языка я добавил одну строку после строки 568 или в другой версии 336.

$retstr = ($asciiEncoding) ? $retstr : $this->_encodeUTF16($retstr);

$retstr=iconv("UTF-16LE","UTF-8", $retstr);

этот код поддерживает персидский язык, но вы больше не можете использовать английский.

0 голосов
/ 06 апреля 2011

Мои 2 цента:

Я только что заменил encodeUTF16 на этот

 function _encodeUTF16($string, $check = false) {
    if ($check) {
        $from = api_detect_encoding($string);
        $string = api_convert_encoding($string, $this->_defaultEncoding, $from);
        return $string;    
    }
    $string =  api_convert_encoding($string, $this->_defaultEncoding, 'UTF-16LE');
    return $string;

и измените строку 568

$retstr = ($asciiEncoding) ? $this->_encodeUTF16($retstr, true) : $this->_encodeUTF16($retstr);

эти функции api_detect_encoding и api_convert_encoding можно найти в этой библиотеке:

http://code.google.com/p/chamilo/source/browse/main/inc/lib/internationalization.lib.php?repo=classic

...