Google Cloud Storage 获取临时文件名(使用 fopen('php://temp'))

Google Cloud Storage get temp filename (using fopen('php://temp'))

Similar question asked here a few years ago but with no answer: Get path of temp file created via fopen('php://temp')

我正在使用 Google 云存储并行下载大量大文件,然后将它们上传到其他服务。本质上是通过我的服务器 B 从 A 转移到 C。

在幕后,Google 的 StorageObject -> downloadAsStream() 使用 Guzzle 通过 fopen('php://temp','r+') 获取文件。

我 运行 遇到磁盘 space 问题,因为如果在传输过程中抛出异常,Google 的云存储库不会清理临时文件。 (这是 docs 的预期行为)。每次重试脚本都会在我的 tmp 目录中转储另一个未清理的大文件。

如果 Guzzle 使用 tmpfile() 我可以使用 stream_get_meta_data()['uri'] 来获取文件路径,但是因为它使用 php://temp,这个选项似乎被屏蔽了:

[
 "wrapper_type" => "PHP",
 "stream_type" => "TEMP",
 "mode" => "w+b",
 "unread_bytes" => 0,
 "seekable" => true,
 "uri" => "php://temp", // <<<<<<<< grr.
]

那么: 有没有人知道如何获取由 fopen('php://temp') 创建的临时文件名,以便我可以执行手动清理?

更新:

看来这是不可能的。希望 GCS 将更新他们的库以更改生成临时文件的方式。在那之前,我使用以下清理代码:

public function cleanTempDir(int $timeout = 7200) {

    foreach (glob(sys_get_temp_dir()."/php*") as $f) { 

        if (is_writable($f) && filemtime($f) < (time() - $timeout))
            unlink($f);

    }

}

更新 2

有可能,请参阅下面已接受的答案。

很可能是系统配置的临时目录,您可以通过sys_get_temp_dir获得。

请注意,这只会在需要时保存到文件,并且可以驻留在内存中。 https://www.php.net/manual/en/wrappers.php.php

编辑: 好的,文件已创建。然后您可以在流句柄上使用 stream_get_meta_data 从流中获取该信息。

Google云平台支持!

目前,使用 php 云存储库无法获取在使用方法 downloadAsStream() 时创建的临时文件名。因此,我代表您创建了一个功能请求,您可以关注它 here

作为解决方法,您可以手动删除该文件,您可以使用以下命令获取临时文件名:

$filename = shell_exec('ls -lt | awk 'NR==2' | cut -d: -f2 | cut -d " " -f2');

之后,$filename 将包含最后修改的文件名,这将是失败的并且您希望删除的文件。使用文件名,您现在可以继续删除它。

请注意,在执行函数之前,您必须位于 php://temp 文件夹中。

像下面这样的东西应该可以解决问题:

use Google\Cloud\Storage\StorageClient;

$client = new StorageClient;

$tempStream = tmpfile();
$tempFile = stream_get_meta_data($tempStream)['uri'];

try {
    $stream = $client->bucket('my-bucket')
        ->object('my-big-ol-file')
        ->downloadAsStream([
            'restOptions' => [
                'sink' => $tempStream
            ]
        ]);
} catch (\Exception $ex) {
    unlink($tempFile);
}

restOptions 选项允许您通过命令代理到底层 HTTP 1.1 传输(Guzzle,默认情况下)。很抱歉,这没有明确记录,但希望它有所帮助!