Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案
post by tommy @ 11 八月, 2006 19:22
PEAR 中, 有個可以讓 PHP 產生 Excel 檔案的東西: Spreadsheet_Excel_Writer, 透過這個物件, 我們可以產生一個正確的 Excel 檔案出來. 而在 0.9.0 版中, 加上了 Unicode 的支援, 我們只要把 BIFF 的版本設為 8, 然後用 setInputEncoding() 指定要使用的編碼就可以存成一個 UNICODE 的 Excel 檔案.

不過, 我們發現, 在資料筆數較少, 檔案較小的時候, 運作十分正常. 不過, 當筆數大到一定的大小之後, 所產生的檔案, 使用 Microsoft Excel 打開時, 會出現損毀的情形, 其中的內容是正確無誤, 不過格式都會不見. (據說用 OpenOffice 打開時會告知是 SST 錯誤)

今天在 PEAR 的網站中, 看到幾個月之前, 有人提出了一個解決方法, 修改 Workbook.php 中的下列兩個 function 如下:

    /**
* Calculate
* Handling of the SST continue blocks is complicated by the need to include an
* additional continuation byte depending on whether the string is split between
* blocks or whether it starts at the beginning of the block. (There are also
* additional complications that will arise later when/if Rich Strings are
* supported).
*
* @access private
*/
function _calculateSharedStringsSizes()
{
/* Iterate through the strings to calculate the CONTINUE block sizes.
For simplicity we use the same size for the SST and CONTINUE records:
8228 : Maximum Excel97 block size
-4 : Length of block header
-8 : Length of additional SST header information
-8 : Arbitrary number to keep within _add_continue() limit
= 8208
*/
$continue_limit = 8208;
$block_length = 0;
$written = 0;
$this->_block_sizes = array();
$continue = 0;

foreach (array_keys($this->_str_table) as $string) {
$string_length = strlen($string);
$headerinfo = unpack("vlength/Cencoding", $string);
$encoding = $headerinfo["encoding"];
$split_string = 0;

// Block length is the total length of the strings that will be
// written out in a single SST or CONTINUE block.
$block_length += $string_length;

// We can write the string if it doesn't cross a CONTINUE boundary
if ($block_length < $continue_limit) {
$written += $string_length;
continue;
}

// Deal with the cases where the next string to be written will exceed
// the CONTINUE boundary. If the string is very long it may need to be
// written in more than one CONTINUE record.
while ($block_length >= $continue_limit) {

// We need to avoid the case where a string is continued in the first
// n bytes that contain the string header information.
$header_length = 3; // Min string + header size -1
$space_remaining = $continue_limit - $written - $continue;


/* TODO: Unicode data should only be split on char (2 byte)
boundaries. Therefore, in some cases we need to reduce the
amount of available
*/
$align = 0;

# Only applies to Unicode strings
if ($encoding == 1) {
# Min string + header size -1
$header_length = 4;

if ($space_remaining > $header_length) {
# String contains 3 byte header => split on odd boundary
if (!$split_string && $space_remaining % 2 != 1) {
$space_remaining--;
$align = 1;
}
# Split section without header => split on even boundary
else if ($split_string && $space_remaining % 2 == 1) {
$space_remaining--;
$align = 1;
}

$split_string = 1;
}
}


if ($space_remaining > $header_length) {
// Write as much as possible of the string in the current block
$written += $space_remaining;

// Reduce the current block length by the amount written
$block_length -= $continue_limit - $continue - $align;

// Store the max size for this block
$this->_block_sizes[] = $continue_limit - $align;

// If the current string was split then the next CONTINUE block
// should have the string continue flag (grbit) set unless the
// split string fits exactly into the remaining space.
if ($block_length > 0) {
$continue = 1;
} else {
$continue = 0;
}
} else {
// Store the max size for this block
$this->_block_sizes[] = $written + $continue;

// Not enough space to start the string in the current block
$block_length -= $continue_limit - $space_remaining - $continue;
$continue = 0;

}

// If the string (or substr) is small enough we can write it in the
// new CONTINUE block. Else, go through the loop again to write it in
// one or more CONTINUE blocks
if ($block_length < $continue_limit) {
$written = $block_length;
} else {
$written = 0;
}
}
}

// Store the max size for the last block unless it is empty
if ($written + $continue) {
$this->_block_sizes[] = $written + $continue;
}


/* Calculate the total length of the SST and associated CONTINUEs (if any).
The SST record will have a length even if it contains no strings.
This length is required to set the offsets in the BOUNDSHEET records since
they must be written before the SST records
*/

$tmp_block_sizes = array();
$tmp_block_sizes = $this->_block_sizes;

$length = 12;
if (!empty($tmp_block_sizes)) {
$length += array_shift($tmp_block_sizes); # SST
}
while (!empty($tmp_block_sizes)) {
$length += 4 + array_shift($tmp_block_sizes); # CONTINUEs
}

return $length;
}

/**
* Write all of the workbooks strings into an indexed array.
* See the comments in _calculate_shared_string_sizes() for more information.
*
* The Excel documentation says that the SST record should be followed by an
* EXTSST record. The EXTSST record is a hash table that is used to optimise
* access to SST. However, despite the documentation it doesn't seem to be
* required so we will ignore it.
*
* @access private
*/
function _storeSharedStringsTable()
{
$record = 0x00fc; // Record identifier
$length = 0x0008; // Number of bytes to follow
$total = 0x0000;

// Iterate through the strings to calculate the CONTINUE block sizes
$continue_limit = 8208;
$block_length = 0;
$written = 0;
$continue = 0;

// sizes are upside down
$tmp_block_sizes = $this->_block_sizes;
// $tmp_block_sizes = array_reverse($this->_block_sizes);

# The SST record is required even if it contains no strings. Thus we will
# always have a length
#
if (!empty($tmp_block_sizes)) {
$length = 8 + array_shift($tmp_block_sizes);
}
else {
# No strings
$length = 8;
}



// Write the SST block header information
$header = pack("vv", $record, $length);
$data = pack("VV", $this->_str_total, $this->_str_unique);
$this->_append($header . $data);




/* TODO: not good for performance */
foreach (array_keys($this->_str_table) as $string) {

$string_length = strlen($string);
$headerinfo = unpack("vlength/Cencoding", $string);
$encoding = $headerinfo["encoding"];
$split_string = 0;

// Block length is the total length of the strings that will be
// written out in a single SST or CONTINUE block.
//
$block_length += $string_length;


// We can write the string if it doesn't cross a CONTINUE boundary
if ($block_length < $continue_limit) {
$this->_append($string);
$written += $string_length;
continue;
}

// Deal with the cases where the next string to be written will exceed
// the CONTINUE boundary. If the string is very long it may need to be
// written in more than one CONTINUE record.
//
while ($block_length >= $continue_limit) {

// We need to avoid the case where a string is continued in the first
// n bytes that contain the string header information.
//
$header_length = 3; // Min string + header size -1
$space_remaining = $continue_limit - $written - $continue;


// Unicode data should only be split on char (2 byte) boundaries.
// Therefore, in some cases we need to reduce the amount of available
// space by 1 byte to ensure the correct alignment.
$align = 0;

// Only applies to Unicode strings
if ($encoding == 1) {
// Min string + header size -1
$header_length = 4;

if ($space_remaining > $header_length) {
// String contains 3 byte header => split on odd boundary
if (!$split_string && $space_remaining % 2 != 1) {
$space_remaining--;
$align = 1;
}
// Split section without header => split on even boundary
else if ($split_string && $space_remaining % 2 == 1) {
$space_remaining--;
$align = 1;
}

$split_string = 1;
}
}


if ($space_remaining > $header_length) {
// Write as much as possible of the string in the current block
$tmp = substr($string, 0, $space_remaining);
$this->_append($tmp);

// The remainder will be written in the next block(s)
$string = substr($string, $space_remaining);

// Reduce the current block length by the amount written
$block_length -= $continue_limit - $continue - $align;

// If the current string was split then the next CONTINUE block
// should have the string continue flag (grbit) set unless the
// split string fits exactly into the remaining space.
//
if ($block_length > 0) {
$continue = 1;
} else {
$continue = 0;
}
} else {
// Not enough space to start the string in the current block
$block_length -= $continue_limit - $space_remaining - $continue;
$continue = 0;
}

// Write the CONTINUE block header
if (!empty($this->_block_sizes)) {
$record = 0x003C;
$length = array_shift($tmp_block_sizes);

$header = pack('vv', $record, $length);
if ($continue) {
$header .= pack('C', $encoding);
}
$this->_append($header);
}

// If the string (or substr) is small enough we can write it in the
// new CONTINUE block. Else, go through the loop again to write it in
// one or more CONTINUE blocks
//
if ($block_length < $continue_limit) {
$this->_append($string);
$written = $block_length;
} else {
$written = 0;
}
}
}
}
 

我們試用後, 目前看起來一切都正常.

Del.icio.us Furl HEMiDEMi Technorati MyShare
commons icon [1] 請問如何輸出成字串 ?? [ 回覆 ]

請問一下, Excel 產生後, 要如何轉成字串,
才能用Email 的方式寄出!
我上網找了很久,都沒找到!
因為轉成字串, 就能每天自動跑報表出來,Email給所有人
!!

commons icon [2] [ 回覆 ]

都用 pear 的 Spreadsheet_Excel_Writer 了, 應該也不差再用一個 Mail_mime 物件.
http://pear.php.net/manual/en/package.mail.mail-mime.php

commons icon [3] [ 回覆 ]

http://tw.myblog.yahoo.com/c9993/article?mid=20&prev=157&next=155&l=f&fid=7

搭配一下應該就OK了

commons icon [4] PEAR 的 Excel 檔案 的問題 [ 回覆 ]

tommy~
請問一下你試用後正常~那你的檔案有測到多大的呢??
我有用你介紹的方式執行,初期正常,但我今天檔案到54kb就又出現原來的問題~!故有此一問!!謝謝!

commons icon [5] [ 回覆 ]

幾百 K 吧, 可能有上到幾 MB 吧. 我們的客戶之後都沒反應過有不正常的情形了.
如果只是 54K 就有問題, 比較像是沒改之前的情形.

我記得我們沒改之前, 當初好像多數在 200K 左右會出問題.

commons icon [6] [ 回覆 ]

謝謝!這讓我頭痛了半天......

commons icon [7] RE:PEAR 的 Excel 檔案 的問題 [ 回覆 ]

sorry~!!我打錯了~!
是154kb~!!
謝謝tommy的提醒,確實是我沒有改過去!現在ok了(我一直以為我有改過!)

commons icon [8] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

tommy 您好:

當我在使用 Spreadsheet_Excel_Writer 時,
每當把 *.xls 下載完後,想要直接開啟,
都會出現一個 Microsoft Excel 的警告視窗,
內容為
"Microsoft Excel 無法使用 *.xls , 可能是因為這個檔案是唯讀的,或者存放它的地方是唯讀的,或是伺服器沒有回應"

當我按"取消"的時候,會出現 2 個狀況,

1.直接修復,並且提示"Excel 嘗試回復您的公式和數值,但是部份資料可能已經遺失或損毀",但是檔案內容都正確;

2.修復失敗,我得使用開啟舊檔,選擇"開啟並修復"-->"抽選資料"-->"復原公式",
之後 Excel 直接修復,並出現 敘述 1 的狀況;

我的測試程式

require_once 'Spreadsheet/Excel/Writer.php';

// Creating a workbook
$workbook = new Spreadsheet_Excel_Writer();
// Creating a worksheet
$worksheet =& $workbook->addWorksheet('Reporter');
$workbook->setVersion(8);
$worksheet->setInputEncoding('utf-8');

$x = 0;
$y = 0;
$worksheet->write($x, $y++, '群組');
$worksheet->write($x, $y++, '報表月份');
$worksheet->write($x, $y++, '應發獎金');

// hide gridlines so they don't mess with our Excel art.
$worksheet->hideGridLines();

// sending HTTP headers
$workbook->send('sales_reporter.xls');

$workbook->close();

這個狀況我一直處理不掉,請問這個狀況該如何處理呢??

commons icon [9] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我用你上頭寫的程式, 在我的環境並不會有問題.
不過建議 $workbook->setVersion(8); 寫在產生 worksheet 之前 (不過好像之後也不會有問題).

另外, 下載的檔案, 不要直接用 excel 打開來, 先存起來. 然後再看看格式是不是正確的 excel 檔案.
也許用 notepad 先看一下, 也許是你的系統的 php 會有些錯誤 (警告? 提示?) 訊息出來吧, 這樣子會變成在那 excel 檔案前面出現那些字串, 格式自然會有問題.

commons icon [10] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

對了, 程式我放這兒, 可以自己試看看:
http://www.teatime.com.tw/~tommy/test/excel.php
source code 可以用這個看 (只是一個 soft link 到同一個檔案):
http://www.teatime.com.tw/~tommy/test/excel.phps

commons icon [11] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

tommy 您好:

真的是ok;
怪事了,為什麼在我的環境卻是有問題的,
請問可否給我一些想法呢???

是否安裝pear套件時,有什麼地方應該注意的呢??

謝謝您;

commons icon [12] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

另外補充:
我都是先存檔之後再開啟檔案的;

commons icon [13] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我有使用notepad打開檔案,
開頭是
"俵遄??",
看不出是否是錯誤...

commons icon [14] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我猜測是你的那個 php 檔案因為是 UTF-8 編碼的, 在 Windows 下頭, 多數的編輯器會在檔案前面加上 BOM 字元 (3 bytes), 而那些字元會被送出, 所以產生的 excel 檔案會多那幾個 bytes, 格式自然也就不對了.

如果你確定不是因為 BOM 造成的問題. 就把你有問題的檔案與我這兒產生正常的檔案用 binary mode 比較一下看看吧. 或者把有問題的檔案 email 給我看看吧.

commons icon [15] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

謝謝您寶貴的意見,我再試試看..

commons icon [16] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

非常感謝....問題解決!!!!

commons icon [17] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

Tommy大大你好
請教,如何在Linux環境安裝Spreadsheet_Excel_Writer
我server上已用yum安裝了PHP,也download了OLE及Spreadsheet_Excel_Writer的tar檔
查了google都是教人用win環境安裝,Linux環境要怎麼安裝呢?
謝謝

commons icon [18] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

linux 下頭與 window 下沒什麼不同吧.
如果你是用 tarball 裝的, 那只好裝了一個之後跑看看有少什麼再裝缺的東西吧. 或者學著用 pear 裝吧. 這些東西本來就是 pear 裡頭的東西, 一個指令應該就會把缺的都裝上去.
http://pear.php.net/manual/en/

或者直接找有包含這些東西的 linux 發行版本吧. 例如 Debian (UBuntu 應該也有, 反正也可以用 Debian 的套件庫).

commons icon [19] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

感謝Tommy大大
我install pear就可以把OLE及Spreadsheet_Excel_Writerj都安裝起來了
也可以正常運作了,
感謝

commons icon [20] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

Tommy大大,
我是從Spreadsheet_Excel_Writer的那個bug討論的thread裡面找到你這裡來的。我安裝好了Spreadsheet_Excel_Writer以及OLE後按照你的http://www.teatime.com.tw/~tommy/test/excel.phps 裡面的方法生成出來的excel文檔,正文內容看上去都OK,但是下面sheetname裡面包含的中文都亂掉了。請問您有遇見過這種情況么?
謝謝!

commons icon [21] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

名稱的問題請參考另外一篇.
http://blog.teatime.com.tw/1/post/301

commons icon [22] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

太贊了!感謝T大大!

commons icon [23] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我已經patch 了以上的補丁,但是仍然發生錯誤
Fatal error: Call to undefined method Spreadsheet_Excel_Writer_Worksheet::setBIFF8InputEncoding() in C:\Program Files\EasyPHP 3.0\www\yamao1\Spreadsheet\Excel\Writer\Workbook.php on line 363

commons icon [24] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

有錯.... 表示沒 patch 好吧.

commons icon [25] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

可否email給我一個patch好的workbook.php...
感謝TOMMY大神。

commons icon [26] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]
commons icon [27] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

抓 http://www.teatime.com.tw/~tommy/files/Spreadsheet_Excel_Writer-0.9.1_patched.tgz 這個吧.

commons icon [28] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

已經copy 了, 但是excel 內的中文變成問號(?????)
本人的php 程式是先撈數據庫的資料,然後生成excel檔,數據庫的中文資料都變為亂碼了。本人用phpmyadmin,所有數據庫校驗及varchar,text為utf-8 unicode編碼, 是否數據庫編碼的影響?
程式碼如下:

commons icon [29] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

// include class file
include 'Spreadsheet/Excel/Writer.php';
session_start();
$_SESSION["m_computer_code"] = "vch";

$savename = date("YmdHis");

// initialize reader object
$workbook = new Spreadsheet_Excel_Writer("sheets/".$_SESSION["m_computer_code"]."$savename.xls");

$workbook->setVersion(8, 'utf-8');
$worksheet =& $workbook->addWorksheet('International worksheet');
$worksheet->setInputEncoding('UTF-8');
// attempt a connection
try {
$pdo = new PDO("mysql:dbname=phpcart;host=localhost;charset=utf-8", "admin", "Yamao1946");
} catch (PDOException $e) {
die("ERROR: Could not connect: " . $e->getMessage());
}

// read data from database
// convert into spreadsheet
$rowCount = 0;
$sql = "SELECT * FROM `directadd` WHERE `m_computer_code`='". $_SESSION["m_computer_code"]."'";
if ($result = $pdo->query($sql)) {
// get header row
for ($x=0; $xcolumnCount(); $x++) {
$meta = $result->getColumnMeta($x);
$worksheet->write($rowCount, $x, $meta['name']);
}
// get data rows
$rowCount++;
while($row = $result->fetch()) {
foreach ($row as $key => $value) {
$worksheet->write($rowCount, $key, $value);
}
$rowCount++;
}
} else {
echo "ERROR: Could not execute $sql. " . print_r($pdo->errorInfo());
}

// close connection
unset($pdo);

// save file to disk
$workbook->close();

commons icon [30] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

經本人嘗試,如果是static的資料,無論是繁體和簡體都能正常顯示在Excel中。但是經過撈數據庫的步驟後,所生出來的Excel的中文資料都變成問號。

commons icon [31] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

也許你資料庫內抓出來的資料編碼不對吧.
以你上頭的程式來看, 只有使用 utf-8 才會正確的被存到 excel 檔案中.

commons icon [32] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我的phpmyadmin 所有item的校對都是utf8 unicode 而且default character set 都是uft8,所有的設定都是一致的, 究竟為甚麼生成的excel 中文會變成問號? 救命呀! TOMMY 大神

commons icon [33] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

自己想辦法確認那些字是正確的吧. 畢竟如果是你自己打上去的字可以正確的出來, 表示不是這個模組的問題.

自己把資料庫抓出來的資料寫到檔案上去看看是那一種編碼的字吧.

commons icon [34] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

問題已解決!原來要正確顯示由數據庫中所撈的中文字,需要在連接數據後,查詢語句之前,加上
mysql_query('set names utf8;');由於我使用pdo函式連接數據庫,需要改為$pdo->query('set names utf8;')。加了後,所有繁中,簡中都能夠顯示。總之,感謝TOMMY大神的PATCH。

commons icon [35] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

萬分感謝!!@@

commons icon [36] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

呀.. 多謝大大發表這個excel writer
本人把這個套件install在pear 了
但是使用以下php碼就發生了exception

Warning: Cannot modify header information - headers already sent by (output started at D:\xampplite\htdocs\test\excel.php:2) in D:\xampplite\php\PEAR\Spreadsheet\Excel\Writer.php on line 67

Warning: Cannot modify header information - headers already sent by (output started at D:\xampplite\htdocs\test\excel.php:2) in D:\xampplite\php\PEAR\Spreadsheet\Excel\Writer.php on line 68

Warning: Cannot modify header information - headers already sent by (output started at D:\xampplite\htdocs\test\excel.php:2) in D:\xampplite\php\PEAR\Spreadsheet\Excel\Writer.php on line 69

Warning: Cannot modify header information - headers already sent by (output started at D:\xampplite\htdocs\test\excel.php:2) in D:\xampplite\php\PEAR\Spreadsheet\Excel\Writer.php on line 70

Warning: Cannot modify header information - headers already sent by (output started at D:\xampplite\htdocs\test\excel.php:2) in D:\xampplite\php\PEAR\Spreadsheet\Excel\Writer.php on line 71

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 18 bytes) in D:\xampplite\php\PEAR\Spreadsheet\Excel\Writer\Workbook.php on line 1308

本人是使用xampplite 套件的...是不是預設設定的問題嗎?

commons icon [37] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

1. 應該是 BOM 造成的吧.
2. 把 php 可以使用的記憶體在 php.ini 中加大吧.

commons icon [38] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

:| 多謝大大回覆 原來xampplite 需要預設date_default_timezone_set('Asia/Hong_Kong') ;
加了這句後能夠下載了
不過為什麼活頁簿的名稱是亂碼?

commons icon [39] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

名稱是亂碼的修正請參考這兒另一篇與 spreadsheet_excel 有關的文吧.

commons icon [40] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我打上了補丁, 成功生成中文字不亂碼的excel檔, 但是行數總數到達400後,

打開excel,會出現錯誤:找到無法讀取的錯誤...
Excel 已回復您的公式及儲存格數值,但部分資料可能已經遺失。

Excel 發現某些錯誤,這些錯誤可能會造成一些復原的資料被放在錯誤的儲存格中。請仔細檢查您的復原資料。

最後出來的結果,183行以後的數據不完整,有些格有料,有些格沒有料。

請問如何解決, 並我看到了worksheet.php中的$colmax = 256; 是否說明spreadsheet_excel_writer,只能最多出256行?

我試過把256改為1024, 結果都是一樣,出現缺漏。

commons icon [41] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

改的不完整吧.
如果是正確的改法, 應該不會出現這個問題. 至少我試過的檔案比你說的大多了, 並不會有問題.

commons icon [42] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

Thanks for your unwarp version of fix. It has helped me to fix the Workshop.php and it works fine now on my UTF-8 Excel.

commons icon [43] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

Tommy,
请问我用Spreadsheet_Excel_Writer 导出的Excel打开要经过验证,如果点击是后,里面全是乱码?根本不知道里面是什么东西?

commons icon [44] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

要看你怎麼寫的.
如果是存在 unicode 的格式, 對 excel 來說, 最後轉成的編碼會是 utf16-le 的內碼吧.

commons icon [45] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我这边程序里面已经进行了转码,我在程序里面也设置了,我们自己在程序里面也写转码函数,函数代码如下: function setInputEncoding($encoding)
{
if ($encoding != 'UTF-16LE' && ! function_exists('iconv')) {
$this->raiseError("Using an input encoding other than UTF-16LE requires PHP support for iconv");
}
$this->_input_encoding = $encoding;
}
下面是我写入Excel文件的一段代码:
require_once 'Spreadsheet/Excel/Writer.php';
$workBook = new Spreadsheet_Excel_Writer();
$workBook -> setTempDir(G_UPLOADPATH);
$workBook -> setVersion(8);
$formatExcelHeaders = & $workBook -> addFormat(array('Size' => 14, 'Bold' => 1, 'HAlign' => 'left'));
$headerFormat = & $workBook -> addFormat(array('border' => 0, 'bold' => '1', 'size' => '11', 'color' => 'black', 'fgcolor' => 22, 'align' => 'center'));
$formatContent = & $workBook -> addFormat(array('HAlign' => 'left', 'Valign' => 'top', 'TextWrap' => 1));
$headerBigFormat = & $workBook -> addFormat(array('HAlign' => 'center', 'FgColor' => 22, 'Size' => 16, 'Bold' => 1));
$titleCenterFormat = & $workBook -> addFormat(array('HAlign' => 'center', 'Size' => 11, 'Bold' => 1));
$titleLeftFormat = & $workBook -> addFormat(array('HAlign' => 'left', 'Size' => 11, 'Bold' => 1));
$fieldLeftFormat = & $workBook -> addFormat(array('HAlign' => 'left', 'Size' => 10));
$fieldRightFormat = & $workBook -> addFormat(array('HAlign' => 'right', 'Size' => 10));
$fieldCenterFormat = & $workBook -> addFormat(array('HAlign' => 'center', 'Size' => 10));
//first tab
$workSheet = & $workBook -> addWorksheet(" Bruce.xing General Statistics");
$workSheet -> setInputEncoding('utf-8');

commons icon [46] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

你的 code 我看不出來有什麼問題.
那個 setInputEncoding() 應該不是自己寫的吧, 應該是 Spreadsheet_Excel_Writer 本身的才對.

如果你的 Spreadsheet_Excel_Writer 是 patch 過的版本, 應該只要用 utf-8 就能產生正確的內容才對.

參考一下這個 sample:
http://www.teatime.com.tw/~tommy/test/excel.txt

如果要執行的結果可以點這個:
http://www.teatime.com.tw/~tommy/test/excel.php

如果你用的 patch 不包含下面網頁說的這個:
http://blog.teatime.com.tw/1/post/301
要記得把
$workbook->setVersion(8, 'utf-8');
改成
$workbook->setVersion(8);
才可以用. (當然這樣子 header/footer 與 sheet 名稱就不能用 unicode)

commons icon [47] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

Tommy:
我的发现程序里面已经加那个patch,并且我用你给程序在我的环境运行了,我打开Excel的结果是这样的:
"Џࡱက;  "

" "
"̇AB䄽%r8X""1ȀArial1ȀArial1ȀArial1ȀArial1ȀArial1Ȁ Arial������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������ ������    ‸3f̀̿fff̙̙̀̌̿̿̿̀̿̀3f3̌̀̀fff3f3f33333f33333惀test 測試 1243pD}1XhgNɡ|vNsёľbhgN^ѓVYё0

commons icon [48] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

看起來應該是 Excel 的內容沒錯.
會是 BOM 的問題嗎? 你的 php code 那一個檔案不能用有 BOM 的格式來存, 否則產生的內容最前面會多出 BOM 的那三個字元, 會造成 Excel 不認得那個檔案.

commons icon [49] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

我这边没有用BOM,BOM是什么东西?下面这个方法是我这边自己重写的Send方法: function send($filename)
{
header("Content-type: application/vnd.ms-excel");
header("Content-Disposition: attachment; filename=\"$filename\"");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
header("Pragma: public");
}

commons icon [50] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

google 一下 UTF-8 BOM 就知道了. (不知道不表示沒用到, 只要有用支援 BOM 的 Editor, 就可能會幫你加上去)
你要先確定你所有用到的 php 檔案都沒有 BOM, 才可能會得到正確的結果.

commons icon [51] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

Tommy,
我确认过了,我所用到PHP页面没有被动的被加上BOM。

commons icon [52] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

那我就猜不出來是什麼原因了.

你的檔案前幾個位元內容是這個嗎? (16 進位)
D0 CF 11 E0 A1 B1 1A E1
如果是, 就應該不是 BOM 的問題.

commons icon [53] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

Tommy,
用PEAR的Spreadsheet_Excel_Writer导出Excel文件对系统和PHP的版本有要求吗?还有Apache有要求吗? 谢谢!

commons icon [54] Re:使用 Spreadsheet_Excel_Writer 產生 UNICODE 的 Excel 檔案 [ 回覆 ]

求教…本身有個base excel file入面有d data, 個file只有100幾kb, 但當我入完d資料, 只係d數字, 或者加加減減行數, 以前都可以save到個檔案只有數百kb, 但最近兩個月唔知點解做完相同動作, 個file就變左3mb... 即使我是拎返100幾kb 果個file 黎做然後save as, 佢都成2,3mb, 點解會咁?
我用緊2007, 但save d file 全部都save 返做excel97-2003workbook...

迴響
暱稱:
標題:
個人網頁:
電子郵件:
authimage

迴響

  

Bad Behavior 已經阻擋了 48 個過去 7 天試圖闖關的垃圾迴響與引用。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS