思路:根据设置的每次导出的数据,分批写入到临时文件.txt中,进行压缩统一下载,最后删除临时.txt和压缩文件。(注意服务器文件夹是否有操作权限)
namespace app\common\my;
/**
* 文件导出(ZIP格式)
*/
class FileExport
{
private $fileName;
private static $initialize;
// 初始化
public static function init()
{
if (is_null(self::$initialize)) {
self::$initialize = new static;
}
return self::$initialize;
}
/**
* 设置临时及导出文件名
*/
public function setName(String $name = '')
{
$this->fileName = $name ?: date('Ymd') . '_' . md5(time());
return $this;
}
//控制器分批次写入数据到文件防止内存不够
public function writeData(Array $data, Array $field, int $is_head, string $txtFile){
// 判断数据是否为空
if (count($data) <= 0 || count($field) <= 0) die('数据长度错误');
// 验证数据值字段与标题长度
if (count($field) != count($data[0] ?? [])) die('数据值字段长度与标题字段长度不符');
$context = '';
if($is_head < 1){
$context = implode("\t", $field) . "\r\n";
}
foreach ($data as $key => $value) {
$context .= implode("\t", $value) . "\r\n";
}
// 写文件
$handle = fopen($txtFile, 'a');
fwrite($handle, $context);
fclose($handle);
}
//压缩文件
public function toZip(string $txtFile){
$zipFile = \Env::get('runtime_path') . $this->fileName . '.zip';
$zipArchive = new \ZipArchive();
if ($zipArchive->open($zipFile, \ZipArchive::CREATE)) {
$zipArchive->addFile($txtFile, basename($txtFile));
$zipArchive->close();
unlink($txtFile);
}
//下载文件
$fp=fopen($zipFile ,"r");
$file_size=filesize($zipFile);
$zipName = explode(DIRECTORY_SEPARATOR, $zipFile);
Header("Content-type: application/octet-stream");
Header("Accept-Ranges: bytes");
Header("Accept-Length:" . $file_size);
Header("Content-Disposition: attachment; filename=" . $zipName[count($zipName) - 1]);
$buffer=1024; $file_count=0;
while(!feof($fp) && $file_count<$file_size){
$file_con=fread($fp,$buffer);
$file_count+=$buffer;
echo $file_con;
}
fclose($fp);
//下载完成后删除压缩包
if($file_count >= $file_size)
{
unlink($zipFile);
}
}
/**
*
* 调用示例
*/
// public function testExport(){
// $sqlLimit = 5000;
// $count = \Db::name('user')->count('id');
// $field = ['姓名','手机号码','参与时间'];
// $txtFile = \Env::get('runtime_path') . DIRECTORY_SEPARATOR . '用户数据-'.date('Y-m-d',time()) . '.txt';
// for($i = 0;$i < ceil($count/$sqlLimit);$i++){
// $list = \Db::name('user')->field('username,mobile,createtime')->limit($i*$sqlLimit,$sqlLimit)->select();
// FileExport::init()->writeData($list,$field,$i,$txtFile);
// }
// FileExport::init()->setName('用户数据-'.date('Y-m-d',time()))->toZip($txtFile);
// }
}