2011-03-21 12 views
1

我正在開發一個涉及解析xls文件數據的php腳本。我正在使用庫phpexcelreader。所有主要工作,但我偶然發現一個奇怪的問題。某些文件被錯誤地解析。看起來xls文件可能在內部使用不同的字符編碼。至少,然後我通過iconv -f cp1251 -t utf8從我的腳本管道輸出,字符串得到糾正。如何應對PHP中不同編碼的xls文件?

Phpexcelreader有一個用於指定輸出編碼的選項,但看起來像缺少能力檢測輸入編碼。有任何想法嗎?

回答

2

工作簿對象的_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

唉..謝謝你這樣詳細的解釋。你確定_defaultEncoding是表示內部編碼嗎?看起來工作表中的數據被轉碼爲UTF16-LE的_defaultEncoding(_encodeUTF16函數) – 2011-03-21 13:45:42

+0

順便提一下,您提到了另外的讀者,您能否提出一個好的建議?我需要的只是讀取未格式化的單元格數據和維度。 – 2011-03-21 13:50:46

+0

PHPExcel是我在PHP中使用電子表格數據時推薦的庫;但我確實有偏見,因爲我是開發人員之一 – 2011-03-21 14:04:28

0

我的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可以在這個LIB中找到:

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