在 Laravel 程序中上传文件时,请求验证可以很好验证上传的文件。你可以要求上传文件必须为 图片 , 也可以限制文件字节 大小 , 也可以根据 mime types 或者 文件扩展名 过滤文件。

如果我们希望用户上载 ZIP 文件,我们可以结合规则并像如下所示的内容使用:

return [
'file' => 'required|file|mimes:zip|size:3072'
];

  

但是与图片、文本或 pdf 文件不同,ZIP 是一个压缩文件,可以在其中保存多个不同的文件。 假设我们希望用户上传一个 ZIP 文件,但带有特定的必需文件和文件夹结构。 举一个真实的例子,如果您曾经使用过 Wordpress 并使用 ZIP 文件为其安装了主题,则 Wordpress 要求主题 ZIP 文件具有某些特定的文件,例如 style.css 或 post.php。 在 Laravel 中我们如何验证上传的 ZIP 文件以查看其是否包含所有必需文件?

PHP 的 libzip 扩展

这里会需要 php 的 libzip 扩展的支持,该扩展的启用以及具体用法请看文档 official documentation page.

如何操作 ZIP 文件

第一步,实例化 ZipArchive 类。

$zip = new \ZipArchive();

  

然后我们就可以通过 open() 方法来解压 ZIP 文档了。

$zip->open('/absolute/path/to/file.zip');

  

方法的官方文档 指出,如果成功打开 ZIP 文件,它将返回 “true”,否则返回整数错误代码。 我们可以像这样检查所有内容:

$zipStatus = $zip->open('/absolute/path/to/file.zip');
if (zipStatus !== true) {
threw new \Exception('Could not open ZIP file. Error code: ' . zipStatus);
} // 没问题,继续操作…

  

ZipArchive 类提供了多种方法来帮助我们读取 ZIP 文件的内容,其中一些方法是

  • count() - 返回 ZIP 文件中的文件数
  • getFromIndex() - 返回指定索引对应的文件
  • getNameIndex() - 返回指定索引的文件名
  • statIndex() - 返回指定索引对应文件的详细信息(文件名、大小等)

有了这些方法,如果我们想获得 ZIP 文件中的可用文件列表。 我们可以这样做:

$filesInside = [];
for ($i = 0; $i < $zip->count(); $i++) {
array_push($filesInside, $zip->getNameIndex($i));
} $zip->close();

  

由于一个 ZipArchive 实例可以同时处理一个 ZIP 文件,因此在处理完该文件后,我们需要使用 close()方法。 当您循环浏览多个 ZIP 文件或使用此类创建新的 ZIP 文件时,这一点尤其重要。

当你使用 ZipArchive 时有一点需要注意一下, “entity” 的概念,这里的 “entity” 并不单单是文件,他还包含所有文件夹以及子文件夹。这句话怎么理解呢?假设我们有个目录结构如下的文档:

- invoice.pdf
- profile_picture.jpg
- documents/
- homework.doc
- bills/
- january/
- payment.pdf

  

我们对当前文档执行 count() 操作可以得到当前文件数量,虽然我们只有 4 个文件,但 count() 方法返回的是 7 ,这是为什么呢?让我们打印一下 $filesInside 看它里面到底包含了什么吧。

$files = [
'invoice.pdf',
'profile_picture.jpg',
'documents/',
'documents/homework.doc',
'bills/',
'bills/january/',
'bills/january/payment.pdf'
];

  

可以看到,打印结果中并不仅仅有你的文件还有相应的文件夹。 这里你还可以通过 getNameIndex() 方法来获取完整的文件路径。

集成到 Laravel 程序中

现在,我们知道了如何使用 PHP 获取 ZIP 的文件列表,让我们将所有内容集成到 Laravel 中并验证上传的 ZIP 文件是否包含必需的文件。

假设我们需要用户上传一个 ZIP 文件,并且文件的 assets 目录中必须包含 thumbnail.jpg 和 style.css 文件。

- thumbnail.jpg
- assets/
- style.css

  

这是我们的控制器,该控制器处理带有名为 zip_file 的文件上传:

namespace App\Controllers;
use Illuminate\Http\Request; class UploadController
{
const REQUIRED_FILES = [
'thumbnail.jpg',
'assets/style.css',
]; public function upload(Request $request)
{
$zip = new \ZipArchive();
$file = $request->file('zip_file');
}
}

  

对我们从 Illuminate\Http\Request 中检索数据时,每个文件都返回一个 Illuminate\Http\UploadedFile 实例。我们可以在实例上使用 path() 方法返回上传的临时文件的绝对路径。

这是我们打开 ZIP 文件并使用 ZipArchive 类列出所有文件的方法。

public function upload(Request $request)
{
$zip = new \ZipArchive();
$file = $request->file('zip_file');
$zip->open($file->path()); $filesInside = [];
for ($i = 0; $i < $zip->count(); $i++) {
array_push($filesInside, $zip->getNameIndex($i));
}
}

  

现在我们可以使用诸如 array_intersect() 之类的方法将 REQUIRED_FILES 与 $filesInside 进行比对。如果交集元素数量不等于 REQUIRED_FILES 的元素数量,则意味着上传的 ZIP 文件中并不存在所有必需的文件,因此我们可以中止请求执行或返回验证错误。

$intersection = array_intersect(self::REQUIRED_FILES, $filesInside);

if (count($intersection) !== count(self::REQUIRED_FILES)) {
abort(422);
}

  

这是我们的控制器,一切就绪:

namespace App\Controllers;
use Illuminate\Http\Request; class UploadController
{
const REQUIRED_FILES = [
'thumbnail.jpg',
'assets/style.css',
]; public function upload(Request $request)
{
$zip = new \ZipArchive();
$file = $request->file('zip_file');
$zip->open($file->path()); $filesInside = [];
for ($i = 0; $i < $zip->count(); $i++) {
array_push($filesInside, $zip->getNameIndex($i));
} $intersection = array_intersect(self::REQUIRED_FILES, $filesInside); if (count($intersection) !== count(self:: REQUIRED_FILES)) {
abort(422);
} // ZIP contains all required files, continue
}
}

  

最佳实践

在 Laravel 应用程序中,最佳实践是将与验证相关的内容移出控制器。 常见选项有:

出于 ZIP 内容验证的需要,我创建了一个专用的 Laravel 软件包,该软件包几乎完成了本博客文章中所述的所有操作,并提供了更多选项和功能。 您可以在 GitHub 页面查看 orkhanahmadov/laravel-zip-validator 以获取更多信息以及如何使用它。

更多学习内容请访问:

腾讯T3-T4标准精品PHP架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新)​

如何 Laravel 中验证 zip 压缩包里的文件?的更多相关文章

  1. Java中往zip压缩包追加文件

    有个需求,从某个接口下载的一个zip压缩包,往里面添加一个说明文件.搜索了一下,没有找到往zip直接添加文件的方法,最终解决方法是先解压.再压缩. 具体过程如下: 1.一个zip文件的压缩和解压工具类 ...

  2. jeecg项目将workbook 的Excel流添加到zip压缩包里导出

    1.直接献出代码 Map<String,List<ConfidentialInformation>> typeMap = new HashMap<>(); try ...

  3. laravel中如何防止直接访问.env文件

    .env文件含有数据库账号密码等敏感数据,在laravel5.2中,在本地访问127.0.0.1/laravel/.env可直接访问到.env. 为避免.env被直接访问,可使用重定向,方法如下: 在 ...

  4. 怎么往mac中finder个人收藏里添加文件夹

    1.打开Finder,点击左上角finder偏好设置 2.选择边栏 3.如果侧栏中没有的文件夹,直接长按文件夹直接拖入.

  5. laravel中的storePublicly对上传的文件设置上传途径

    public function imgeUpload(Request $request) { //生成的文件名是md5随机的文件名字 //$path=$request->file('wangEd ...

  6. zip压缩包密码破解

    有一种破解方法叫做Known plaintext attack.市面上的密码破解软件几乎都带有这个功能.操作方法就是找到加密压缩包中的任意一个文件,用同样的压缩软件同样的压缩方式压缩成一个不加密的包, ...

  7. 【CTF 攻略】CTF比赛中关于zip的总结

    [CTF 攻略]CTF比赛中关于zip的总结   分享到: --> 本文首发于安全客,建议到原地址阅读,地址:http://bobao.360.cn/ctf/detail/203.html 前言 ...

  8. laravel中的验证及利用uploadify上传图片

    $rules = [ 'password'=>'required|between:6,20|confirmed', ]; $message = [ 'password.required'=> ...

  9. laravel 中使用tinker 验证驱动加载是否成功

    在验证laravel 中   InvalidArgumentException Driver [WeiBo] not supported. public function weibo() { retu ...

随机推荐

  1. Pytest系列(17)- pytest-xdist分布式测试的原理和流程

    pytest-xdist分布式测试的原理 前言 xdist的分布式类似于一主多从的结构,master机负责下发命令,控制slave机:slave机根据master机的命令执行特定测试任务 在xdist ...

  2. BMI的Python实现

    str1 = float(input('请输入您的身高(单位:米):')) # input默认转化为字符串型 用float转化为浮点型 str2 = float(input('请输入您的体重(单位:千 ...

  3. HashMap实现原理(JDK1.8)

    概述HashMap在底层数据结构上采用了数组+链表+红黑树,通过散列映射来存储键值对数据因为在查询上使用散列码(通过键生成一个数字作为数组下标,这个数字就是hash code)所以在查询上的访问速度比 ...

  4. flex实现三列布局

    css3新引入的flex在某些情况下布局非常实用 因为它是弹性盒子所以自适应效果会很棒 不过各项布局方案还是各有优劣 <!DOCTYPE html> <html lang=" ...

  5. AJ学IOS 之小知识之xcode6自动提示图片插件 KSImageNamed的安装

    AJ分享,必须精品 一:首先看效果 KSImageNamed是让XCode能预览项目中图片的插件 很牛逼,据说写这个插件的牛人在日本~ 主要针对imageNamed:方法 效果如图: 安装: 首先需要 ...

  6. Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十二)之Error Handling with Exceptions

    The ideal time to catch an error is at compile time, before you even try to run the program. However ...

  7. CSS两种盒子模型:cntent-box和border-box

    cntent-box 平时普通盒子模型,padding,border盒子会变大,向外扩展border-box 特殊盒子模型,padding,border盒子会变大,向内扩展

  8. 使用python pip安装工具组件包:出现 requests File “<stdin>",line 1 pip install xxx ^ SyntaxError:invalid syntax

    最近想要试试python ,软件安装完成了,但是,import 组件包时,出了问题,一直不得解:安装pycharm 工具感觉麻烦,不想安装那些,只想单纯使用python . 问题复现: 1.Windo ...

  9. js获取数组中最大值

    1.es6拓展运算符... Math.max(...arr) 2.es5 apply(与方法1原理相同) Math.max.apply(null,arr) 3.for循环 let max = arr[ ...

  10. Ansible playbook Vault 加密

    Ansible playbook Vault 加密详解与使用案例 主机规划 添加用户账号 说明: 1. 运维人员使用的登录账号: 2. 所有的业务都放在 /app/ 下「yun用户的家目录」,避免业务 ...