您的位置:首页 > 编程语言 > PHP开发

php 导出数据到excel(缓冲区应用)

2016-04-21 15:15 549 查看
昨天写了个php 结合缓冲区读取excel数据并批量导入mysql,缓冲区可有可无,没有多大的影响,接下来介绍一下php导出数据到excel,这次采用缓冲区的方式,大家知道,php中,所有的输出都会用到缓冲区,缓冲区的左右就是协调告诉的cpu与相对缓慢的I/O操作。

echo 'hello123';
sleep(10);
echo '再一次输出hello123';
按照正常的逻辑,程序的运行应该是先输出hello123.之后10秒之后再输出‘再一次输出hello123’;

why?为什么会出现这种问题呢,答案网上一堆,我就简单点说,原因是,php把输出都缓冲了,并且一直到程序执行完才全部输出出来,这样的结果,我可以调处n多的不足:

一,很多时候需要在输出时设置header头,比如我们写程序测试时,输出出来的东西应该是对我们友好可读的,这个时候就需要设置utf8等header头,平时我们都把header头写在程序的开头,这是因为header之前不允许出现echo 等操作,不过这个可以通过php缓冲区避免,比如在第一次echo
之间 开启ob_start(),这样就会正常显示了(但是坚决不推崇这种方法,这是严重浪费系统资源的行为);

二,现在输出的数据真的特别的少,但是如果数据足够多呢,多到echo 所有的数据需要执行1w秒呢,难道要分文件下载吗?

其实真的不用这样,php给了解决这个的办法,而且很友好,下面是本篇文章的重点

cms系统中有很多将需求就是要把mysql数据导出到excel中,实现下载操作,原理很简单,数据库查数据,设置header头,让浏览器知道这是一个下载附件的操作,从而实现下载。

但是,有个问题,数据量小的时候,什么情况都无所谓,比如上面所说的,在没有超出memory_limit时,php程序正常运行,下载也很流畅,但是如果索要请求的数据很多呢,超过限制了呢,这样的情况再手动设置ini_set('memory_limit',"XXXXM")吗,万一数据多到你都不知道呢,要知道,你可分配的内存是有限的,为了这样的程序去随便的设置这些也是一种华丽的浪费。下面一个小程序,大家可以下载下来测试:

set_time_limit(10);
ob_end_clean();//在循环输出前,要关闭输出缓冲区
echo str_pad('',1024);//浏览器在接受输出一定长度内容之前不会显示缓冲输出,这个长度值 IE是256,火狐是1024
for($i=10;$i>0;$i--){
$a=str_repeat('hello',$i).'<br />';
echo $a;
flush(); //刷新输出缓冲
sleep(1);
}
通过运行程序,可以看到,在浏览器中输出的数据是渐渐的输出的,那么,大家应该明白了,既然如此,是不是可以将这个嵌套到导出excel的程序中呢,答案是肯定的,而且这样做的话,相当于把数据拆分成n多的小块,每一块都不超出内存,而且每取出来一块就能实时导出来数据,这样的体验,无疑是最好的,下面贴出一个测试版的:

$ceshi=array();
for($j=1;$j<100;++$j){
for($i=1;$i<100;++$i){
$ceshi[]=array($j,$i);
}
}
header("Content-Type: application/force-download");
header("Content-type:application/vnd.ms-excel");
header("Content-Disposition:attachment; filename=".date("YmdHis").".xls");
echo '<HTML xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">'."\n";
echo '<head><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=utf-8"></head>'."\n";
echo "<body>";
echo "<table width='100%' border='1'>";
echo "<tr align='center'><td>\$j</td><td>\$i</td></tr>";
foreach($ceshi as $rs)
{
echo "<tr align='left'><td>".$rs[0]."</td><td>".$rs[1]."</td></tr>";
sleep(1);//模拟数据多造成的后果
}
echo '</table></body></html>';
上面的程序是可执行的测试程序,通过sleep(1)模拟数据过多造成的页面等待状态,而如果注释掉那一行,就会是我们经常遇到的业务环境了,可以想象,1w条数据模拟的后果是最少等待1w秒才会出现下载提示;

$ceshi=array();
for($j=1;$j<100;++$j){
for($i=1;$i<100;++$i){
$ceshi[]=array($j,$i);
}
}
header("Content-Type: application/force-download");
header("Content-type:application/vnd.ms-excel");
header("Content-Disposition:attachment; filename=".date("YmdHis").".xls");
echo '<HTML xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">'."\n";
echo '<head><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=utf-8"></head>'."\n";
echo "<body>";
echo "<table width='100%' border='1'>";
echo "<tr align='center'><td>\$j</td><td>\$i</td></tr>";

ob_end_flush();
foreach($ceshi as $rs)
{
echo "<tr align='left'><td>".$rs[0]."</td><td>".$rs[1]."</td></tr>";
flush();
sleep(1);
}
echo '</table></body></html>';
通过开启缓冲区,没取到一次数据就直接输出到浏览器端,这样就会直接显示出下载框,当用户点击之后,就会实现下载,虽然模拟的结果也是差不多1w秒才会完成,不过这种情况是不会出现滴,因为还没到1w秒,就会超出php限定的120秒

,不过不用纠结这个,这只是一个测试的极端结果。



 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  html mysql php excel 浏览器