刚接到这样的需求,其实我是拒绝的。我甚至很有耐心地和pm商量,扔个csv不就好了么?

pm:对方需要一个csv打包成.tar.gz的包,他们是linux server,这是硬性要求。

然后我开始折腾之旅,里面小坑无数。

其实这里大致有两条思路:

1.把生成好的csv利用System(),exec()函数去使用系统命令tar成包,比较蛋疼的是公司配的是windows,我只能在自己虚拟机ubuntu里面测试。

2.利用现成的工具类或者函数什么的, 去直接生成一个tar.gz,然后扔csv进去。

我特么先选第二条路。首先别人是要.tar.gz,我先去查了一下php的内置函数,貌似只有gzwrite,gzopen等文件操作函数,只能把文件弄成安全二进制的.gz文件。我发现如果继续走下去就走到第1条路上了,只能利用系统命令去实现。

我尝试性地在ubuntu下exec('tar -cxf do.tar.gz do.csv'),然而只有run script方式可以执行生成成功,而通过浏览器并没有生成。没得到tar.gz,何谈后面利用一连串header去输出下载文件呢?

所以第一条路是彻底死了,我继续在第二条路上行走。

由于网络不好,没能连上vpn。我只能一直百度,而不能利用到google优质的资源。我搜索了相关php导出tar.gz的资料,国内一大堆抄袭的,基本结论是:少数人遇到这个需求,且遇到了下载出来的文件破损不能打开,无解。

你没看错,是:无解。国内没有一个人解决了这个问题(至少在能搜索出来的page上来看)。我先试着曲线救国,先还是用gzwrite系列函数去创建一个.gz文件,代码如下:

<?php$gz = gzopen('/tmp/do.gz', 'w9'); // 打开或创建一个.gz文件,linux下记得写权限问题
gzwrite($gz, '33c,24ec,32q3');// 写入内容到.gz文件
gzclose($gz); // 关闭文件句柄,释放资源
header("Content-Type: application/x-gzip");
$lastPackName = '/tmp/do.gz';
//header("Content-type:application/octet-stream");
header("Accept-Ranges:bytes");
header("Accept-Length: ".filesize($lastPackName));
Header("Content-Disposition:attachment; filename=records.gz");
@readfile($lastPackName);
//下载文件之后,要删除该压缩包
 @unlink($lastPackName);

相关函数的用法,可以自行查阅php.net上的相关函数。然后我发现单独写一个demo文件,是能下载下来能正常解压的文件,而如果写到公司项目中对应的Controller的function里面,则下载的包是破损的,这是我遇到的第一个坑。

然后我又在想,是否是环境问题。我把下载好的文件包,扔到我虚拟机(ubuntu)里面,也是解压出来有问题。而在服务器上生成的原始文件.gz是完好无缺的。所以我遇到了和这位同学一样的问题:http://bbs.csdn.net/topics/390226194

最后他的提问被说是header头设置的问题,我又仔细排查了一下header设置没有问题。

后面我知道pear有个Archive_Tar类可以直接打包tar文件,我分析了一下,需要安装pear相应的包,成本较大,放弃了这样的做法。

昨天整个下午就在不断下载解压失败和查看国内千篇一律无解的技术资料上消耗完了。晚上回到家,我不甘心,连上vpn,怒用google,很快查到了这篇文章:

http://stackoverflow.com/questions/7004989/creating-zip-or-tar-gz-archive-without-exec

歪果仁果然会折腾,早就遇到类似打包的要求,并且没有使用exec.可以使用php自带的PharData类去创建tar文件,然后通过compress函数打包成tar.gz.关于PharData类和相关函数可以去php.net上查阅。

于是我使用如下代码打包:

<?php$csvFile = '/tmp/do.csv';
$fp = fopen($csvFile , 'w+');
fwrite($fp, '232,c233,23dc');
fclose($fp);
$tarFile = '/tmp/archive.tar';
$a = new PharData($tarFile);// ADD FILES TO archive.tar FILE
$a->addFile($csvFile, 'do.csv');
$a->compress(Phar::GZ);
unlink($tarFile);
unlink($csvFile);
header("Content-Type: application/x-gzip");
$lastPackName = $tarFile . '.gz';
//header("Content-type:application/octet-stream");
header("Accept-Ranges:bytes");
header("Accept-Length: ".filesize($lastPackName));
Header("Content-Disposition:attachment; filename=records.tar.gz");
@readfile($lastPackName);
//下载文件之后,要删除该压缩包
@unlink($lastPackName);

我果真so easy地创建了一个包含xx.csv的tar.gz文件,但是下载解压失败依然存在。当然,如果写一个小脚本直接用浏览器访问是对的,下载的文件也是解压正常。

时间不知不觉就到了今天上午,和部门leader一起排查,先排除了ngnix转发输出的问题(在测试服务器上测试某段代码),也排除了生成文件部分的问题。代码就那么十几行,最后只剩下header输出到最后readfile这部分。

readfile是把文件读到缓冲区里面,而下载下来有问题,多半是buffer区在readfile之前有东西了。于是我bing了一下"php header gz broken"关键字,查到这篇讨论:

http://stackoverflow.com/questions/22046020/php-downloading-tar-gz-file-increases-file-size-and-changes-md5

虽然并不是完全和我想要的内容一样,不过给了我一点提示。我发现他在readfile之前执行了ob_clean(),清除缓冲区。这个函数保证了后面的输出都是干净的,新的。最终我的代码如下:

$csvFile = '/tmp/downPrivilege.csv';$fp = fopen($csvFile, 'w+') or die('cant not create file');fwrite($fp, '23233,cw3,232');fclose($fp);$tarFile = '/tmp/downPrivilege.tar';$a = new PharData($tarFile);// ADD FILES TO archive.tar FILE$a->addFile($csvFile, 'downPrivilege.csv');$a->compress(Phar::GZ);header("Content-Type: application/x-gzip");$lastPackName = $tarFile . '.gz';header("Accept-Ranges:bytes");header("Accept-Length: " . filesize($lastPackName));Header("Content-Disposition:attachment; filename=downPrivilege.tar.gz");header("Expires: 0");header("Cache-Control: must-revalidate, post-check=0, pre-check=0");header("Cache-Control: private");header("Pragma: public");ob_clean(); // 清除缓冲区内容@readfile($lastPackName);unlink($tarFile);unlink($csvFile);unlink($lastPackName);

下载之后终于正确能解压出东西了。

总结:

1.不要想着别人能帮助你 ,特别是比较不常见的东西,只能自己专研。我以前觉得有团队可以一起探讨,但是实际工作中很少人愿意花时间真的和你讨论。

2.查资料真心不要百度,常见的问题都可能是错误解答,而且千篇一律。还是bing+google吧。

3.排查问题要自信,过滤掉的环节就不要反复折腾。

4.歪果仁往往已经遇到了那些非主流的情况,可以直接借鉴。

希望有做类似需求的朋友可以看到这篇文章,因为国内没有一个人能正面回答这个问题。

转载于:https://www.cnblogs.com/freephp/p/4935593.html

人生在于折腾:php实现下载导出xx.tar.gz相关推荐

  1. docker 导出本地所有镜像,带仓库和tag值导出到tar.gz文件

    shell脚本导出本地机器上所有docker镜像,导出成一个文件. 1.根据docker image list 结果 2.将所有镜像的REPOSITORY和TAG值,用awk取出,并合并到一行. 3. ...

  2. android+5.0+root,人生在于折腾:Android 5.0再次闪电Root 附Root方法

    一般来说,Android开发版系统都是给开发人员研究用的,但也有不少喜欢折腾的玩家会在第一时间尝鲜,而他们也都有一个必备的要求:Root. Nexus 5/7 2013 Android 5.0最新预览 ...

  3. linux系统安装.tar.gz文件,Linux中下载、解压、安装.tar.gz文件

    一.将解压包发送到linux服务器上: 1.在windos上下载好.tar.gz文件后,通过winscp等SFTP客户端传送给linux 2.在linux中通过wget命令直接下载 #wget [选项 ...

  4. curl快速下载GitHub Repo指定commit的tar.gz

    前言 有些时候需要下载GitHub仓库的tar.gz来做一些其他操作: 这时候可能最常见的就是去GitHub上找release或者tag里面有提供tar.gz的资源: 然后点击下载-- 但是有些场景可 ...

  5. github下载tar.gz文件

    好坑啊,想去github上下载FastDFS的tar.gz包,结果只能下载zip文件,去百度,百度了半小时尽是没用的东西,唯一找到一个说用wget 下载地址,结果下载的是以.git结尾的文件,好气!! ...

  6. OSChina 周二乱弹 ——生命,在于折腾!

    2019独角兽企业重金招聘Python工程师标准>>> @涉水轻舟 : 我觉得<情人>这首歌是许巍在睡到半夜时突然醒来,然后哼两句,然后弹着吉他弹着弹着然后又睡着了- 情 ...

  7. 幸福人生在于正确选择

    一个人在其漫长的一生中所走的每一步,都已为明天埋下了伏笔.我们所做的每一件事,都如同我们撒下的一粒种子,在时光的滋润下,那些种子慢慢生根.发芽.抽枝.开花,最终结出属于自己的果实.所以,幸福的人生在于 ...

  8. vue使用html2canvas jspdf实现pdf下载导出功能

    vue使用html2canvas jspdf实现pdf下载导出功能 功能步骤介绍: 1.安装 全局.局部引用 2.封装 html2canvas结合 JsPDF 下载导出方法 3.组件页面调用

  9. Angular导出功能(excel导出功能、文件数据流导出功能、图片的下载导出功能)

    Angular导出功能(excel导出功能.文件数据流导出功能.图片的下载导出功能) 场景1:(直接返回网络地址进行导出的excel) 后台返回的是 : "http://192.168.0. ...

最新文章

  1. android 8.0 3D锁屏,Android 8.0 锁屏滑动无法解锁
  2. 【135天】尚学堂高淇Java300集视频精华笔记(74-76)
  3. fastreport 打印两个list_Smaller And Smarter Python数据结构:合并两个有序链表
  4. android如何删除项目,AndroidStudio中怎样删除项目
  5. 趣头条,或许是下一个小巨头
  6. JavaCC报错:ERROR: Second call to constructor of static parser
  7. Ceylon 1.0.0
  8. springMVC浏览器接受json报406错误的解决方法
  9. luoguP3723 HNOI2017 礼物
  10. 排序算法积累(3)-----快速排序
  11. 360与Bing合作上线英文搜索
  12. atitit.高性能遍历 文本文件行 attilax总结
  13. 计算机更新bios,小编教你如何升级bios
  14. python调用access数据库_Python访问Access数据库
  15. 《具体数学》部分习题解答3
  16. 中国天气预报API城市编号
  17. 南京工程学院计算机博士,南京工程学院高层次人才引进工作实施办法(修订)...
  18. C++的重载(overload)与重写(override)
  19. SPI 读取不同长度 寄存器_几种常用的总线设计:UART/SPI/I2C
  20. iOS 开关-UISwitch

热门文章

  1. 取证技术---数据存储【硬盘结构】
  2. 哪类公司能开增值税票,哪类公司只能开普票?
  3. IE8 主页不能修改的Case Study
  4. TransactionScope的使用
  5. 15---文件上传与下载
  6. linux服务器进入系统黑屏6,进入Linux黑屏一般用什么方法解决
  7. 第一章 DirectX 计算机图形学(下)
  8. 9行Python代码去除图片中的数字水印
  9. Unity性能优化之性能检测工具汇总
  10. 小程序自定义导航栏高度