导出功能在管理后台算是比较常见的了。在实现导出表格类信息的功能时,可以选择两种实现方式:
导出为excel
导出为csv文件格式
用csv方式导出,则可以像导出txt一样,以文本流的方式进行流式处理,不但能导出海量信息,而且流式处理占用内存极低,服务器对浏览器的响应也是非常迅速的。理论上是不限量的。具体能导出多少条,是由服务器的响应时间、PHP的运行时间和内存等限制决定。但是如果用excel来打开csv,超过65536行的数据都会看不见,这是excel程序的问题。本次导出数据量很大。所以选择csv。
总体实现思路为:
先把需要导出的数据存到数组里,然后写入到文件。话不多说,还是直接上代码吧。
function export(){
$data=array(
array(
'nId' => '90',
'nick' => 'piapia',
),
array(
'nId' => '91',
'nick' => 'monkey',
)
);
$head = array(
'nId' => 'id',
'nick' => '昵称',
);
$name = "filetoexport" . date('YmdHis', time());
$this->writeCsvToBrowser($name, $head, $data);
}
function writeCsvToBrowser($filename,$headLine,$data,$lostData=array()) {
$out = implode(',', $headLine);
$out = iconv('UTF-8', 'GBK//IGNORE',$out);
foreach ($data as $v) {
$line = array();
foreach (array_keys($headLine) as $objAttr) {
if (is_object($v) && isset($v->$objAttr)) {
$cellValue = $v->$objAttr;
}elseif(is_array($v) && isset($v[$objAttr])) {
$cellValue = $v[$objAttr];
}else {
$cellValue = $lostData[$objAttr];
}
$line[] = $cellValue;
}
$line = array_map('csvFormate',$line);
$out .= "\n";
$lineStr= implode(',', $line);
//iconv转换编码对字符串有长度限制,如果太长就会被截断。
$lineStr= @iconv('UTF-8', 'GBK//IGNORE', $lineStr);
$out .= $lineStr;
}
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Length: " . strlen($out));
header("Content-type: text/x-csv");
header("Content-Disposition:filename=$filename.csv");
echo $out;
}
function csvFormate($str) {
if (''===$str) {
return '';
}
$find = FALSE;
foreach (array(',','"',"\n","\t") as $v){
if (FALSE===strpos($str, $v)) {
$find = true;
break;
}
}
if (!$find) {
return $str;
}
$str = str_replace('"', '""', $str);
return sprintf('"%s"',$str);
}
在实现这个功能时,有一些问题需要大家注意一下。
1.精度丢失问题:
问题描述:导出后,发现有一个字段总是跟取得不一样,Id为1918553121332457在导出后变成1918553121332450,也就是说最后一位 总是变成了0。
原因:Excel数值显示精度为15位造成精度丢失。
解决思路:强制转化成字符串
$strId."\t"
或者
$strId."\n"
需要注意的是,这样加是没有用的:
$strId." "
2.PHP运行时间的限制,导致程序被强制中断。
在不能随便改变php.ini文件里PHP运行的时间限制下,可以这样设置来增加运行时间:
set_time_limit(60*5);
3.默认内存设置太小,导致文件写入失败:
可以尝试这样解决
ini_set('memory_limit','1024M');
4.奇淫技巧
如果不想文件在读取或者写入的时候,因为用户的误操作被中断。可以通过如下参数实现:
ignore_user_abort(true);
以上是我自己在多次管理后台开发实现导出功能时曾经遇到过的问题,主页菌在此列出来希望可以和大家一起探讨一下。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。