说明
实现效果:使用php压缩目标目录成zip文件,并下载
环境框架:laravel 5.1 php 5.6
示例
逻辑处理片段代码:
use ZipArchive;//此处需要引入ZipArchive类
/**
* 文件夹打包下载
* @param Request $request
*/
public function Down(Request $request) {
//判断zip扩展类是否加载
if ( ! extension_loaded('zip')) {
return Redirect::back();
}
set_time_limit(0);
$iId = $request->get('id');
//获取需要压缩的文件路径
$aResArr = Compress::getTargetDirectory($iId);
if ($aResArr === false || $aResArr['sDir'] == '') {
return Redirect::back();
}
//生成压缩包
$oZip = new ZipArchive();
//压缩包命名
$sZipName = md5(uniqid() . time()) . '.zip';
//将一级目录名作为下载压缩包名
$sFileName = $aResArr['sFileName'] ? $aResArr['sFileName'] . '.zip' : $sZipName;
$sRes = $oZip->open($sZipName, ZipArchive::OVERWRITE | ZipArchive::CREATE);
if($sRes === true) {
//压缩目标目录
Compress::compressTargetDirectory($aResArr['sDir'], $oZip);
$oZip->close();
}
//下载压缩包
header('Content-Type:application/zip');
if (preg_match("/MSIE/", $_SERVER["HTTP_USER_AGENT"])) {
header('Content-Disposition: attachment; filename="' . rawurlencode($sFileName) . '"');
} else if (preg_match("/Firefox/", $_SERVER["HTTP_USER_AGENT"])) {
header('Content-Disposition: attachment; filename*="utf8\'\'' . $sFileName . '"');
} else {
header('Content-Disposition: attachment; filename="' . $sFileName . '"');
}
header('Content-Length:' . filesize($sZipName));
session_write_close();
readfile($sZipName);
ob_flush();
flush();
//删除生成的目标目录
Compress::removeTargetDirectory($aResArr['sDir']);
//删除生成的压缩包
unlink($sZipName);
}
操作类代码(compress.php):
<?php
/**
* 文件压缩类
*/
namespace App\Services;
use App\File;
use Illuminate\Support\Facades\DB;
class Compress
{
/**
* 获取文件信息
* @param $iId
* @return bool
*/
public static function getFileInfo($iId)
{
if ( ! $iId) {
return false;
}
return File::select('id', 'name', 'isdir', 'loc')
->where('id', $iId)
->first();
}
/**
* 获取指定文件夹下所有信息
* @param $iId
* @return bool
*/
public static function getFileInfoById($iId)
{
if ( ! $iId) {
return false;
}
$aConditions = [':path' => '%/' . $iId . '/' . '%'];
$sSql = 'SELECT * FROM `File` WHERE `path` LIKE :path';
return DB::select($sSql, $aConditions);
}
/**
* 创建目标目录或文件
* @param $sName 目标目录或名称
* @param $sPath 目标目录路径
* @param int $iStatus 目录类型 0 文件 1 文件夹名称
* @param string $sPrev 上级目录路径
* @return bool|string
*/
public static function createDirectory($sName, $sPath, $iStatus = 0, $sPrev = '')
{
if ( ! defined('COM_DIR') ) {
define('COM_DIR', storage_path('upload/compress'));
}
if ( ! defined('UP_DIR') ) {
define('UP_DIR', storage_path('upload/files'));
}
if ( ! defined('DS')) {
define('DS', DIRECTORY_SEPARATOR);
}
$newDir = $sPrev ?: COM_DIR . DS . md5(uniqid());
if ($iStatus == 0) {//文件
$sExt = self::getExtByPath(trim($sPath));
$sFileName = $sName ? basename($sName, '.' . self::getExtByPath(trim($sName))) . '.' . $sExt : basename($sPath);
$newPath = $newDir . DS . $sFileName;
//判断文件是否存在
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
$newPath = iconv('utf-8', 'gbk//IGNORE', $newPath);
}
//文件不存在
if ( ! file_exists($sPath)) {
return false;
}
//文件夹不存在,创建文件夹
if ( ! file_exists($newDir)) {
mkdir($newDir, 0777, true);
}
//copy原有文件到新目录
if ( ! copy($sPath, $newPath)) {
return false;
}
} else {//文件夹
if ( ! $sName) {
return false;
}
$newPath = $newDir . DS . $sName;
//判断文件是否存在
if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
$newPath = iconv('utf-8', 'gbk//IGNORE', $newPath);
}
//文件夹不存在,创建文件夹
if ( ! file_exists($newPath)) {
mkdir($newPath, 0777, true);
}
}
return $newPath;
}
/**
* 获取目标目录路径
* @param $iId 目标id
* @param string $sPrev 上级目录路径
* @return array|bool
*/
public static function getDirectory($iId, $sPrev = '')
{
$sDir = '';
$sFileName = '';
//获取目标文件信息
$aFile = self::getFileInfo($iId);
if (count($aFile) < 1) {
return false;
}
//创建目标目录路径
$sPath = self::createDirectory($aFile->name, $aFile->loc, $aFile->isdir ? 1 : 0, $sPrev);
//目标目录路径,与文件名获取
if ($sPrev == '') {
$sDir = $sPath ?: '';
$sFileName = $aFile->isdir ? $aFile->name : basename($aFile->name, '.' . self::getExtByPath(trim($aFile->name)));
}
//循环文件夹,生成子目录
if ($aFile->isdir == 1) {//文件夹
$aList = self::getFileInfoById($aFile->uid, $aFile->id);
if (count($aList) > 0) {
foreach ($aList as $v) {
self::getDirectory($v->id, $sPath);
}
}
}
return [
'sDir' => $sDir,
'sFileName' => $sFileName
];
}
/**
* 压缩目标目录
* @param $sDir 目标目录路径
* @param $aZip ZipArchive类对象
* @param string $sPrev 上级目录路径
* @return null
*/
public static function compressDirectory($sDir, $aZip, $sPrev = '')
{
$sBasename = basename($sDir);//文件(夹)名
$sBasePath = $sPrev ? $sPrev . '/' . $sBasename : $sBasename;//目标根目录
if(is_dir($sDir)) {
$oHandler = opendir($sDir);
$aZip->addEmptyDir($sBasePath);
while ($oFile = readdir($oHandler)) {
$sRealPath = $sDir . '/' . $oFile;
if (is_dir($sRealPath)) {
if ($oFile !== '.' && $oFile !== '..') {
$aZip->addEmptyDir($sBasePath . '/' . $oFile);
self::compressDirectory($sRealPath, $aZip, $sBasePath);
}
} else {
$aZip->addFile($sRealPath, $sBasePath . '/' . $oFile);
}
}
closedir($oHandler);
} else {
$aZip->addFile($sDir, $sBasePath);
}
return null;
}
/**
* 删除生成的目标目录
* @param $sDir
*/
public static function removeDirectory($sDir)
{
//获取包含目标目录的上级目录路径
$sDir = str_replace('\\' . basename($sDir), '', $sDir);
//判断当前目录类型
if (is_dir($sDir)) {
$oHandler = opendir($sDir);
while ($oFile = readdir($oHandler)) {
$sRealPath = $sDir . '/' . $oFile;
if (is_dir($sRealPath)) {
if ($oFile !== '.' && $oFile !== '..') {
self::removeDirectory($sRealPath);
}
} else {//删除文件
unlink($sRealPath);
}
}
closedir($oHandler);
rmdir($sDir);
} else {
unlink($sDir);
}
}
/**
* 获取文件后缀
* @param $sPath
*/
public static function getExtByPath($sPath){
$sUrl = parse_url($sPath); // 解析url 返回其组成部分
return pathinfo($sUrl['path'], PATHINFO_EXTENSION); //返回文件扩展名信息
}
}