注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

@fc_lamp

关注Web应用解决方案MySql/PHP/Python一盏名为"飞川"的灯~

 
 
 

日志

 
 

php mysql 如何批量下载数据到csv、excel(PHP 输出excel单元格内自动换行) ZipArchive 多级目录  

2013-05-30 17:14:51|  分类: Web技术-应用研究 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一 一般做法
   我们经常要从数据库导出数据到csv、excel等文件中,对于csv文件我们通常都是一行一行的拼接字符串。实际上,HTML表格标签与excel 表格
是相通,所以我们只需要组装好HTML 表格就可以导出成csv、excel等文件了。
我们这里创建一个方法: down_xls()

/**
*
* 导出成Excel文件
* @param array $list array(array('id'=>0,'title'=>''))
* @param array $key_list array('id' => '订单编号','title'=>'项目')
* @param string $file_name
*/
function down_xls($data, $keynames, $name = 'dataxls.xls')
{
$xls [] = "<html><meta http-equiv=content-type content=\"text/html; charset=UTF-8\"><body><table border='1'>";
$xls [] = "<tr><td>" . implode ( "</td><td>", array_values ( $keynames ) ) . '</td></tr>';
foreach ( $data as $o )
{
$line = array ();
foreach ( $keynames as $k => $v )
{
$line [] = $o [$k];
}
$xls [] = '<tr><td>' . implode ( "</td><td>", $line ) . '</td></tr>';
}
$xls [] = '</table></body></html>';
$xls = join ( "\r\n", $xls );
$name = mb_convert_encoding ( $name, 'GBK', 'UTF-8' );
header ( 'Content-Disposition: attachment; filename="' . $name . '"' );
die ( mb_convert_encoding ( $xls, 'UTF-8', 'UTF-8' ) );
}

实际上这里还涉及一个问题是:
PHP 输出excel单元格内自动换行问题,由于我们这里是以HTML的方式输出的Excel文件,所以可以直接在内容里加上:

<br style='mso-data-placement:same-cell;'/>

这个标签即可,实现自动换行(注意:如果你是非HTML方式输出的excel文件,则不能使用此方法)。

使用时:

//实际使用中,可从数据库查询出数,并产生这样的二维数组
$list= array(array('id'=>1,'title'=>'sss'));
$key_list=array('id' => '订单编号','title'=>'项目');
down_xls($list, $key_list);
//mb_convert_encoding 如果出现乱码请使用此函数转一下。


二 数据过大时
  上面的方法一般能解决大多数需求。但是如果数据量上万了,要一次性导出万多条数据,找用此方法还是点不妥。因此,我查了相关资料,也只找到使用zip的方法来批理下载大数据量。
 我的做法是使用:分多次请求WEB服务器每次产一定量的数据文件,最后在打包在一起下载(注意:下面全是模拟代码
 1  我们先修改一下:down_xls()或者是创建一个方法:create_down_xls()

/**
*
* 创建Excel文件
* @param array $list array(array('id'=>0,'title'=>''))
* @param array $key_list array('id' => '订单编号','title'=>'项目')
* @param string $file_path 生成的文件路径
*/
function create_down_xls($list, $key_list, $file_path)
{
$xls [] = "<html><meta http-equiv=content-type content=\"text/html; charset=UTF-8\"><body><table border='1'>";
//字段行
$xls [] = "<tr><td>" . implode ( "</td><td>", array_values ( $key_list ) ) . '</td></tr>';

//数据行
foreach ( $list as $o )
{
$line = array ();
foreach ( $key_list as $k => $v )
{
$line [] = $o [$k];
}
$xls [] = '<tr><td>' . implode ( "</td><td>", $line ) . '</td></tr>';
}
$xls [] = '</table></body></html>';
$xls = join ( "\r\n", $xls );

file_put_contents ( $file_path, $xls );
}


 2  分页式的从数据库中获取出数据 list.php

$offset = (isset ( $_GET ['offset'] ) and is_numeric ( $_GET ['offset'] )) ? abs(intval($_GET ['offset']) ) : 0;

$pagesize = 6000;

$list = array();

$sql = "select id,title from test limit $offset,$pagesize";
$sql_result = mysql_query($sql);
while($res = mysql_fetch_assoc($sql_result))
{
$list[] = $res;
}

if(empty($list))
{
//没有数据了,跳转到下载页,并休息2s.

$url = 'export.php';
echo <<<HTML

<script language="javascript">
setTimeout("redirect('$url');",2*1000);
</script>

HTML;
exit();
}



//还有数据就产生excel文件

$key_list=array('id' => '订单编号','title'=>'项目');

$file_path = '/zip_path/'.date('YmdHis').'.xls';

create_down_xls($list, $key_list, $file_path)


//重新请求服务器,并休息2S

$offset += $size;
$url = 'list.php?offset='.$offset;
echo <<<HTML

<script language="javascript">
setTimeout("redirect('$url');",2*1000);
</script>

HTML;
exit ();




3   下载页面 export.php

$zip_path = '/zip_path/';
//使用zip工具
$zip = new ZipArchive ();
$zip_file = $zip_path . date ( 'YmdHis' ) . 'zip.zip';
if ($zip->open ( $zip_file, ZIPARCHIVE::CREATE ) !== True)
{
die('zip false!');
}
$tpl = scandir ( $zip_path );
foreach ( $tpl as $v )
{
$ext = end ( explode ( '.', $v ) );
$f = $zip_path . $v;
if (in_array ( $ext, array ('txt', 'xls' ) ) and file_exists ( $f ))
{
//添加文件到zip包 $v可以直接写多级目录,如:/ttt/www/xxx/tt/t.txt
$zip->addFile ( $f, $v );
}
}
$zip->close ();
if (! file_exists ( $zip_file ))
{
die('zip false!');
}
header ( "Content-Description: File Transfer" );
header ( 'Content-disposition: attachment; filename=' . basename ( $zip_file ) ); //文件名
header ( "Content-Type: application/zip" ); //zip格式的
header ( "Content-Transfer-Encoding: binary" ); //告诉浏览器,这是二进制文件
readfile ( $zip_file );
die ();

到这一歩,就可以实行zip打包下载了。似乎没有什么问题。


三  进一歩
   也许细心的朋友看到了,我的产后下载文件并没有及时删除,这样会到后面越来越多。对,这是一个问题。
  所以我选择了在每次请求时,就清空'/zip_path/' 目录(存放创建excel文件的目录)。

$zip_path = '/zip_path/';

$offset = (isset ( $_GET ['offset'] ) and is_numeric ( $_GET ['offset'] )) ? abs(intval($_GET ['offset']) ) : 0;

if ($offset <= 0)
{
//删除之前生成的下载文件
$fs = scandir ( $zip_path );
foreach ( $fs as $f )
{
unlink ( $zip_path . $f );
}
}
$pagesize = 6000;
$list = array();
$sql = "select id,title from test limit $offset,$pagesize";
$sql_result = mysql_query($sql);
while($res = mysql_fetch_assoc($sql_result))
{
$list[] = $res;
}
if(empty($list))
{
//没有数据了,跳转到下载页,并休息2s.
$url = 'export.php';
echo <<<HTML

<script language="javascript">
setTimeout("redirect('$url');",2*1000);
</script>

HTML;
exit();
}


//还有数据就产生excel文件
$key_list=array('id' => '订单编号','title'=>'项目');
$file_path = $zip_path.date('YmdHis').'.xls';
create_down_xls($list, $key_list, $file_path)

//重新请求服务器,并休息2S
$offset += $size;
$url = 'list.php?offset='.$offset;
echo <<<HTML

<script language="javascript">
setTimeout("redirect('$url');",2*1000);
</script>

HTML;
exit ();


但是这里又出来一个问题,如果有几个人同时请求得话,那么某个人正在请求产生文件就有可能被其他人请求时删除。我想不出什么好方法,只好在数据库记录下,有没有人在执行导出操作。如果有得话,就等待。直到那个人导出完成,才能进行操作。
  评论这张
 
阅读(777)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017