我试图用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
如您所见,这是一个空白命名的文件夹。当我深入此文件夹时,它会显示以下内容:
图片fa-home.png
存在于此奇怪空白目录中的/img/maps/pins/
目录和中。更糟糕的是,空白目录正在转储我的服务器的目录结构(一个小安全漏洞)
导致这种情况的原因是什么?
答案 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万亿,但如果有更好的解决方案,我有兴趣弄明白(使用锁定文件,散列请求的某些属性等)。