使用PHP ZipArchive的Laravel - 添加文件两次

时间:2018-02-20 15:43:26

标签: php laravel ziparchive

我试图用Laravel创建一个KMZ文件。这只是一个根文件doc.kml的ZIP文件,以及存档中包含的所有引用文件。

这是我相对简单的代码:

        // Defined previously in the file:
        // $location -- a model containing a geographic location
        // $kml -- an XML document for the location
        // $kml is a valid KML file (tested and working)
        $kmz = new ZipArchive;
        $kmz->open("/tmp/{$location->name}.kmz", ZipArchive::CREATE);
        $kmz->addFromString("doc.kml", $kml);
        $icons = $location->markers->pluck("icon")->unique();
        // dd( $icons );
        foreach( $icons as $icon )
        {
            $icon = trim($icon, "/");
            $kmz->addFile(public_path($icon), $icon);
        }
        $kmz->close();
        return response()->download("/tmp/{$location->name}.kmz");

这会下载KMZ文件并按预期工作(我可以在Google地球中打开KMZ并查看文件,显示标记等)

但是每个图标都会添加两次。这是我在添加单个图标时看到的示例:/img/maps/pins/fa-home.png

enter image description here

如您所见,这是一个空白命名的文件夹。当我深入此文件夹时,它会显示以下内容:

enter image description here

图片fa-home.png存在于此奇怪空白目录中的/img/maps/pins/目录中。更糟糕的是,空白目录正在转储我的服务器的目录结构(一个小安全漏洞)

导致这种情况的原因是什么?

1 个答案:

答案 0 :(得分:1)

几天后我在这里找到了问题,这有点令人尴尬。

微妙 提示此行中的问题:

$kmz->open("/tmp/{$location->name}.kmz", ZipArchive::CREATE);

使用ZipArchive::CREATE时,如果文件已存在,则会将其打开以进行修改。这没有详细记录。充其量我们有以下几行:

  

ZipArchive :: CREATE(整数)

     

如果档案不存在,请创建档案。

来源:http://php.net/manual/en/zip.constants.php#ziparchive.constants.create

此处没有任何内容指定行为如果它存在。显然,行为是直接修改现有文件。

事实证明,在我之前编写的测试中,//home/ubuntu/workspace/public//img/maps/pins目录已添加到zip中,该测试已被更正并删除。但是,由于我不断更新现有文件而不是创建新文件,因此该文件永远不会从我的ZIP文件中删除。

作为快速解决方法,可以使用以下代码来代替此行:

$kmz->open("/tmp/{$location->name}.kmz", ZipArchive::CREATE | ZipArchive::OVERWRITE);

但是,如果两个人尝试访问同一个文件,那么第二个人可能会收到服务器错误(因为第一个用户具有ZIP文件的打开句柄,并且不能销毁它以进行覆盖)。我发现一个更好的解决方案是在文件名后附加一个唯一的字符串。我选择了以下内容:

$utime = utime();
$rand = rand();
$kmz->open("/tmp/{$location->name}-{$utime}-{$rand}.kmz", ZipArchive::CREATE | ZipArchive::OVERWRITE);

我对我的解决方案并不是100%满意,因为它不确定。虽然 非常,非常非常 不太可能,但是有两个人同时(相同的微秒)访问同一个文件和< / strong> rand()函数发生为每个函数返回相同的值。在接下来的10万年中,这种情况发生的可能性大概是1万亿,但如果有更好的解决方案,我有兴趣弄明白(使用锁定文件,散列请求的某些属性等)。