Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

修正 Spreadsheet_Excel_Writer 的 unicode 問題
post by tommy @ 21 六月, 2008 15:10

在經過之前所提過的修正之後, 的確可以在 Excel 的欄位中正確的使用 unicode 了. 不過最近在 Study-Area 有人提到 Worksheet 的名稱與列印的 Header 與 Footer 都不能使用 unicode. 試了一下, 果然不能正確使用.

原本的解決方法, 當然就是這部份只用英文或數字, 來避開這個問題. 不過, 最近在 Google 上頭閒逛時, 發現有位日本人提到了一個解法, 在該網頁中說明這個修正取自另一位日本人的 Excel_Reviser 專案, 不過我下載該 patch 之後, 發現不能正常的在我的環境中使用 (UTF-8). 不過... 看起來在他們的日文環境中似乎是正常的.

由於在目前 perl 版本的 Spreadsheet-WriteExcel 是沒有這類的問題, 而 php 的這個物件, 當初也是由 perl 版本 port 過來的, 所以就抓了最新版的 Spreadsheet-WriteExcel 下來研究看看. 

後來發現這位日本人所做的 patch, 在 mb_convert_encoding 並未指定原本的編碼, 我改了一下, 指定我目前用的編碼之後, 果然可以在 worksheet 的名稱上頭使用中文, 不過, 似乎有些問題, 因為用 Excel 打開時都會有檔案有問題. 經過一小段時間的 trace 之後, 發現在 _calcSheetOffsets() 裡頭會計算這個名稱的長度, 我看一下 perl 版本中, 如果是 unicode 時, 這兒應該是轉成 UTF-16LE 的字串之後, 再看看這個字串佔了幾個 bytes, 而不是字串的長度. 直接取字串的長度, 如果是用非 ascii 碼的字串時, 長度會不夠. 所以產生的 excel 檔案會有些問題. 經過了這些修正之後, 目前看起來, 似乎解決了這個問題.

首先, 你必須加上前面提過, 在 pear bug 1572 中 Michal Fapso 所提出的修正, 這個修正如下:

diff -Nur Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Workbook.php Spreadsheet_Excel_Writer-0.9.1/Writer/Workbook.php
--- Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Workbook.php 2005-11-08 11:32:52.000000000 +0800
+++ Spreadsheet_Excel_Writer-0.9.1/Writer/Workbook.php 2008-06-21 14:43:03.619511020 +0800
@@ -1294,7 +1294,7 @@
$this->_append($header . $data);
}
 
- /**
+ /**
* 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
@@ -1311,9 +1311,10 @@
8228 : Maximum Excel97 block size
-4 : Length of block header
-8 : Length of additional SST header information
- = 8216
+ -8 : Arbitrary number to keep within _add_continue() limit
+ = 8208
*/

- $continue_limit = 8216;
+ $continue_limit = 8208;
$block_length = 0;
$written = 0;
$this->_block_sizes = array();
@@ -1321,6 +1322,9 @@
 
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.
@@ -1347,16 +1351,39 @@
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;
+ $block_length -= $continue_limit - $continue - $align;
 
// Store the max size for this block
- $this->_block_sizes[] = $continue_limit;
+ $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
@@ -1398,13 +1425,19 @@
This length is required to set the offsets in the BOUNDSHEET records since
they must be written before the SST records
*/
- $total_offset = array_sum($this->_block_sizes);
- // SST information
- $total_offset += 8;
- if (!empty($this->_block_sizes)) {
- $total_offset += (count($this->_block_sizes)) * 4; // add CONTINUE headers
- }
- return $total_offset;
+
+ $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;
}
 
/**
@@ -1421,9 +1454,31 @@
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
- $this->_block_sizes = array_reverse($this->_block_sizes);
- $length = array_pop($this->_block_sizes) + 8; // First block size plus SST information
+ $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);
@@ -1431,18 +1486,14 @@
$this->_append($header . $data);
 
 
- // Iterate through the strings to calculate the CONTINUE block sizes
- $continue_limit = 8216;
- $block_length = 0;
- $written = 0;
- $continue = 0;
 
 
/* TODO: not good for performance */

foreach (array_keys($this->_str_table) as $string) {
 
$string_length = strlen($string);
- $encoding = 0; // assume there are no Unicode strings
+ $headerinfo = unpack("vlength/Cencoding", $string);
+ $encoding = $headerinfo["encoding"];
$split_string = 0;
 
// Block length is the total length of the strings that will be
@@ -1473,6 +1524,30 @@
 
// 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
@@ -1483,7 +1558,7 @@
$string = substr($string, $space_remaining);
 
// Reduce the current block length by the amount written
- $block_length -= $continue_limit - $continue;
+ $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
@@ -1503,7 +1578,8 @@
// Write the CONTINUE block header
if (!empty($this->_block_sizes)) {
$record = 0x003C;
- $length = array_pop($this->_block_sizes);
+ $length = array_shift($tmp_block_sizes);
+
$header = pack('vv', $record, $length);
if ($continue) {
$header .= pack('C', $encoding);

這個 patch 可以由這兒抓取: http://www.teatime.com.tw/~tommy/mypatch/Spreadsheet_Excel_Writer-0.9.1-unicode-1.patch

經過上頭的 patch 處理之後, 可以正確的在 cell 裡頭使用 unicode 了. 接著, 再經過下面的修正:

diff -Nur Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Format.php Spreadsheet_Excel_Writer-0.9.1/Writer/Format.php
--- Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Format.php 2005-11-09 08:29:35.000000000 +0800
+++ Spreadsheet_Excel_Writer-0.9.1/Writer/Format.php 2008-06-21 14:46:35.197569488 +0800
@@ -243,16 +243,23 @@
var $_right_color;
 
/**
+ * input encoding for unicode
+ * @var string
+ */

+ var $_input_encoding;
+
+ /**
* Constructor
*
* @access private
* @param integer $index the XF index for the format.
* @param array $properties array with properties to be set on initialization.
*/

- function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0, $properties = array())
+ function Spreadsheet_Excel_Writer_Format($BIFF_version, $index = 0, $properties = array(), $input_encoding = '')
{
$this->_xf_index = $index;
$this->_BIFF_version = $BIFF_version;
+ $this->_input_encoding = strtoupper($input_encoding);
$this->font_index = 0;
$this->_font_name = 'Arial';
$this->_size = 10;
@@ -455,12 +462,22 @@
$bCharSet = $this->_font_charset; // Character set
$encoding = 0; // TODO: Unicode support
 
- $cch = strlen($this->_font_name); // Length of font name
$record = 0x31; // Record identifier
if ($this->_BIFF_version == 0x0500) {
+ $cch = strlen($this->_font_name); // Length of font name
$length = 0x0F + $cch; // Record length
} elseif ($this->_BIFF_version == 0x0600) {
- $length = 0x10 + $cch;
+ if ($this->_input_encoding != '') {
+ $encoding = 1;
+ if ($this->_input_encoding != 'UTF16-LE')
+ $this->_font_name = mb_convert_encoding($this->_font_name, "UTF-16LE");
+ $cch = mb_strlen($this->_font_name, "UTF-16LE");
+ $length = 0x10 + strlen($this->_font_name);
+ }
+ else {
+ $cch = strlen($this->_font_name); // Length of font name
+ $length = 0x10 + $cch; // Record length
+ }
}
$reserved = 0x00; // Reserved
$grbit = 0x00; // Font attributes
diff -Nur Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Workbook.php Spreadsheet_Excel_Writer-0.9.1/Writer/Workbook.php
--- Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Workbook.php 2008-06-21 14:43:03.619511000 +0800
+++ Spreadsheet_Excel_Writer-0.9.1/Writer/Workbook.php 2008-06-21 14:46:43.421493326 +0800
@@ -172,6 +172,12 @@
var $_string_sizeinfo_size;
 
/**
+ * input encoding for unicode sheetname
+ * @var string
+ */

+ var $_input_encoding;
+
+ /**
* Class constructor
*
* @param string filename for storing the workbook. "-" for writing to stdout.
@@ -266,14 +272,17 @@
* @access public
* @param integer $version The BIFF version
*/

- function setVersion($version)
+ function setVersion($version, $input_encoding = '')
{
if ($version == 8) { // only accept version 8
$version = 0x0600;
$this->_BIFF_version = $version;
+ $this->_codepage = 0x04B0;
// change BIFFwriter limit for CONTINUE records
$this->_limit = 8228;
+ $this->_input_encoding = strtoupper($input_encoding);
$this->_tmp_format->_BIFF_version = $version;
+ $this->_tmp_format->_input_encoding = $this->_input_encoding;
$this->_url_format->_BIFF_version = $version;
$this->_parser->_BIFF_version = $version;
 
@@ -287,6 +296,7 @@
// change version for all formats too
for ($i = 0; $i < $total_formats; $i++) {
$this->_formats[$i]->_BIFF_version = $version;
+ $this->_formats[$i]->_input_encoding = $this->_input_encoding;
}
}
}
@@ -361,7 +371,7 @@
*/
function &addFormat($properties = array())
{
- $format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version, $this->_xf_index, $properties);
+ $format = new Spreadsheet_Excel_Writer_Format($this->_BIFF_version, $this->_xf_index, $properties, $this->_input_encoding);
$this->_xf_index += 1;
$this->_formats[] = &$format;
return $format;
@@ -640,7 +650,11 @@
$total_worksheets = count($this->_worksheets);
// add the length of the BOUNDSHEET records
for ($i = 0; $i < $total_worksheets; $i++) {
- $offset += $boundsheet_length + strlen($this->_worksheets[$i]->name);
+ if ($this->_input_encoding != 'UTF-16LE' && $this->_input_encoding != '')
+ $name = mb_convert_encoding($this->_worksheets[$i]->name, "UTF-16LE", $this->_input_encoding);
+ else
+ $name = $this->_worksheets[$i]->name;
+ $offset += $boundsheet_length + strlen($name);
}
$offset += $EOF;
 
@@ -940,16 +954,26 @@
} else {
$length = 0x07 + strlen($sheetname); // Number of bytes to follow
}
-
$grbit = 0x0000; // Visibility and sheet type
- $cch = strlen($sheetname); // Length of sheet name
-
- $header = pack("vv", $record, $length);
if ($this->_BIFF_version == 0x0600) {
- $data = pack("Vvv", $offset, $grbit, $cch);
+ if ($this->_input_encoding != '') {
+ if ($this->_input_encoding != 'UTF16-LE')
+ $sheetname = mb_convert_encoding($sheetname, "UTF-16LE", $this->_input_encoding);
+ $cch = mb_strlen($sheetname, "UTF-16LE");
+ $encoding = 1;
+ $data = pack("VvCC", $offset, $grbit, $cch, $encoding);
+ } else {
+ $cch = strlen($sheetname);
+ $data = pack("Vvv", $offset, $grbit, $cch);
+ }
+ $length = 0x08 + strlen($sheetname); // Number of bytes to follow
} else {
+ $length = 0x07 + strlen($sheetname); // Number of bytes to follow
+ $cch = strlen($sheetname); // Length of sheet name
$data = pack("VvC", $offset, $grbit, $cch);
}
+
+ $header = pack("vv", $record, $length);
$this->_append($header.$data.$sheetname);
}
 
@@ -1020,16 +1044,22 @@
function _storeNumFormat($format, $ifmt)
{
$record = 0x041E; // Record identifier
-
+
if ($this->_BIFF_version == 0x0600) {
+ if ($this->_input_encoding != '') {
+ if ($this->_input_encoding != 'UTF16-LE')
+ $format = mb_convert_encoding($format, "UTF-16LE", $this->_input_encoding);
+ $cch = mb_strlen($format, "UTF-16LE");
+ }
+ else
+ $cch = strlen($format); // Length of format string
$length = 5 + strlen($format); // Number of bytes to follow
- $encoding = 0x0;
+ $encoding = 0x1;
} elseif ($this->_BIFF_version == 0x0500) {
$length = 3 + strlen($format); // Number of bytes to follow
+ $cch = strlen($format); // Length of format string
}
-
- $cch = strlen($format); // Length of format string
-
+
$header = pack("vv", $record, $length);
if ($this->_BIFF_version == 0x0600) {
$data = pack("vvC", $ifmt, $cch, $encoding);
@@ -1038,7 +1068,7 @@
}
$this->_append($header . $data . $format);
}
-
+
/**
* Write DATEMODE record to indicate the date system in use (1904 or 1900).
*
diff -Nur Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Worksheet.php Spreadsheet_Excel_Writer-0.9.1/Writer/Worksheet.php
--- Spreadsheet_Excel_Writer-0.9.1.orig/Writer/Worksheet.php 2006-09-27 02:17:38.000000000 +0800
+++ Spreadsheet_Excel_Writer-0.9.1/Writer/Worksheet.php 2008-06-21 14:46:44.177486354 +0800
@@ -1230,7 +1230,7 @@
*/

function _XF(&$format)
{
- if ($format) {
+ if (is_object($format)) {
return($format->getXfIndex());
} else {
return(0x0F);
@@ -1514,10 +1514,10 @@
*/
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");
+ if (!function_exists('mb_convert_encoding') || !function_exists('mb_strlen')) {
+ $this->raiseError("Using an input encoding requires PHP support for mb_convert_encoding() and mb_strlen()");
}
- $this->_input_encoding = $encoding;
+ $this->_input_encoding = strtoupper($encoding);
}
 
/**
@@ -1537,15 +1537,11 @@
*/

function writeStringBIFF8($row, $col, $str, $format = null)
{
- if ($this->_input_encoding == 'UTF-16LE')
- {
- $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
- $encoding = 0x1;
- }
- elseif ($this->_input_encoding != '')
+ if ($this->_input_encoding != '')
{
- $str = iconv($this->_input_encoding, 'UTF-16LE', $str);
- $strlen = function_exists('mb_strlen') ? mb_strlen($str, 'UTF-16LE') : (strlen($str) / 2);
+ if ($this->_input_encoding != 'UTF-16LE')
+ $str = mb_convert_encoding($str, 'UTF-16LE', $this->_input_encoding);
+ $strlen = mb_strlen($str, 'UTF-16LE');
$encoding = 0x1;
}
else
@@ -1789,6 +1785,40 @@
}
 
/**
+ * Write a formula to the specified row and column (zero indexed).
+ * For the packed binary string representation of the formula.
+ *
+ * Returns 0 : normal termination
+ * -2 : row or column out of range
+ *
+ * @access public
+ * @param integer $row Zero indexed row
+ * @param integer $col Zero indexed column
+ * @param binary $formula The formula binary string
+ * @param mixed $format The optional XF format
+ * @return integer
+ */

+ function writeFormulaBin($row, $col, $formula, $format = 0)
+ {
+ $record = 0x0006; // Record identifier
+ $xf = $this->_XF($format); // The cell format
+ $num = 0x00; // Current value of formula
+ $grbit = 0x03; // Option flags
+ $unknown = 0x0000; // Must be zero
+
+ // Check that row and col are valid and store max and min values
+ if ($this->_checkRowCol($row, $col) == false) return -2;
+
+ $formlen = strlen($formula); // Length of the binary string
+ $length = 0x16 + $formlen; // Length of the record data
+ $header = pack("vv", $record, $length);
+ $data = pack("vvvdvVv", $row, $col, $xf, $num,
+ $grbit, $unknown, $formlen);
+ $this->_append($header . $data . $formula);
+ return 0;
+ }
+
+ /**
* Write a hyperlink.
* This is comprised of two elements: the visible label and
* the invisible link. The visible label is the same as the link unless an
@@ -2606,8 +2636,13 @@
$str = $this->_header; // header string
$cch = strlen($str); // Length of header string
if ($this->_BIFF_version == 0x0600) {
- $encoding = 0x0; // TODO: Unicode support
- $length = 3 + $cch; // Bytes to follow
+ if ($this->_input_encoding != 'UTF-16LE')
+ $str = mb_convert_encoding($str, "UTF-16LE", $this->_input_encoding);
+ $cch = mb_strlen($str, "UTF-16LE");
+ $encoding = 1;
+ $length = 3 + $cch * 2; // Bytes to follow
+ //$encoding = 0x0; // TODO: Unicode support
+ //$length = 3 + $cch; // Bytes to follow
} else {
$length = 1 + $cch; // Bytes to follow
}
@@ -2634,8 +2669,11 @@
$str = $this->_footer; // Footer string
$cch = strlen($str); // Length of footer string
if ($this->_BIFF_version == 0x0600) {
- $encoding = 0x0; // TODO: Unicode support
- $length = 3 + $cch; // Bytes to follow
+ if ($this->_input_encoding != 'UTF-16LE')
+ $str = mb_convert_encoding($str, "UTF-16LE", $this->_input_encoding);
+ $cch = mb_strlen($str, "UTF-16LE");
+ $encoding = 1;
+ $length = 3 + $cch * 2; // Bytes to follow
} else {
$length = 1 + $cch;
}

這個 patch 可以由這兒抓取: http://www.teatime.com.tw/~tommy/mypatch/Spreadsheet_Excel_Writer-0.9.1-unicode-2.patch

經過這兩個的處理之後, 使用時只要在 setVersion 的第二個參數指定目前使用的編碼, 如下:

<?php
 
require_once('Spreadsheet/Excel/Writer.php');
 
$workbook = new Spreadsheet_Excel_Writer();
$workbook->setVersion(8, 'utf-8');
$worksheet =& $workbook->addWorksheet('test 測試 1243');
$worksheet->setInputEncoding('utf-8');
 
$x = 0;
$y = 0;
$worksheet->write($x, $y++, '群組');
$worksheet->write($x, $y++, '報表月份');
$worksheet->write($x, $y++, '應發獎金');
 
$worksheet->hideGridLines();
$worksheet->setHeader('Header 測試');
$worksheet->setFooter('Footer 測試');
 
$workbook->send('test.xls');
$workbook->close();
 
exit;

上頭的例子, 在我這兒是可以產生正確的 excel 檔案.

在 pear 的 bug 列表中, bug 1572 並不是 open 狀態, 也許是因為這個原因, 所以這個 patch 存在了好幾年, 這之間也有 release 過新的版本, 但是一直都未納入這個 patch. 不過... 我也懷疑這個 class 是不是還有人在維護, 畢竟經過快兩年了, 都沒有任何的異動. 不管如何, 我重新 open 了一個 bug 14203, 把這兩個 patch 都放進去, 希望維護者能在下一個版本把這個問題修正吧. 在這之前, 要使用的人就自己動手做吧.

Del.icio.us Furl HEMiDEMi Technorati MyShare
commons icon [1] Re:修正 Spreadsheet_Excel_Writer 的 unicode 問題 [ 回覆 ]

我之前有寫了一個程式, footer跟header是可以寫unicode沒問題的, 只要轉成UTF-16LE就好了.

$worksheet->setHeader(iconv('UTF-8','UTF-16LE',"&20&\"標楷體\"測試啦~~"),0.85,1);

$worksheet->setFooter(iconv('UTF-8','UTF-16LE',"&R&12&\"標楷體\"測試啦~~~"),0.55,1);

commons icon [2] Re:修正 Spreadsheet_Excel_Writer 的 unicode 問題 [ 回覆 ]

是轉 UTF16-LE 沒錯. 但是, 這部份不應該是使用者自己去轉才對.

commons icon [3] Re:修正 Spreadsheet_Excel_Writer 的 unicode 問題 [ 回覆 ]

改了之後可以正常輸出沒問題
不過我發現另一個問題是
原來未設定 setVersion = 8時,設定列印區域是有效的
但後來設定 setVersion = 8 後,
printArea 設定列印區域給定後,
輸出的檔案開啟時,會有錯誤訊息,
訊息是 "發現無法讀取的內容"

commons icon [4] Re:修正 Spreadsheet_Excel_Writer 的 unicode 問題 [ 回覆 ]

printArea 與上頭的 patch 應該都沒關係吧. 我試過 0.9.1 也會有錯誤.
請到官方網站去反應吧. (不過可能沒什麼用處)

commons icon [5] Re:修正 Spreadsheet_Excel_Writer 的 unicode 問題 [ 回覆 ]

現在發現在產生大檔案的時候, 會停留在 6.67 MB

for ($r=0; $r

commons icon [6] Re:修正 Spreadsheet_Excel_Writer 的 unicode 問題 [ 回覆 ]

for ($r=0; $r<50000; $r++) {
for ($c=0; $c<10; $c++) {
$worksheet->writeString($r, $c, $r.','.$c);
}
}

commons icon [7] Re:修正 Spreadsheet_Excel_Writer 的 unicode 問題 [ 回覆 ]

php 的 spreadsheet_execel_write 是由 perl 版本改過來的. 舊的版本有 7mb 的限制, 所以... php 的版本應該也有吧.
也許等有人再重新 port 一次才有解吧.

有需要的... 或許可以改慮別的方案, 如 phpexcel, http://www.phpexcel.net 吧.

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

迴響

  

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