Similar question asked here a few years ago but with no answer: Get path of temp file created via fopen('php://temp')
Я использую Google Cloud Storage для параллельной загрузки нескольких больших файлов, а затем загружаю их в другой сервис. По сути, перенос с A на C через мой сервер B.
Под капотом Google StorageObject -> downloadAsStream() использует Guzzle для получения файла через fopen('php://temp','r+').
Я столкнулся с проблемой нехватки места на диске, потому что библиотека Google Cloud Storage не очищает временные файлы, если во время передачи возникает исключение. (Это ожидаемое поведение согласно документы). Каждая повторная попытка скрипта создает дамп еще одного огромного файла в моем каталоге 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 в дескрипторе потока, чтобы получить эту информацию из потока.
@lufc Ahhh хорошо ... Обновлен ответ с информацией об этом.
В нижней части моего вопроса вы можете увидеть вывод stream_get_meta_data и почему это не сработало :)
Ах, прости... Я слишком устал после долгой поездки. Это то, что "должно" дать вам. Не уверен, почему это не так. Вы МОЖЕТЕ перебрать решение и получить список файлов в временной папке, принадлежащей пользователю, владеющему вашим php-процессом, и сравнить его позже, чтобы найти добавленные файлы. Но это не так элегантно, как получение пути к конкретному файлу. :П
Кроме того, в Guzzle у вас есть возможность установить имя сохраняемого файла. Разве у вас нет доступа к этому и вы можете использовать это, чтобы вы знали имя с тех пор, как вы его установили?
Поддержка Google Cloud Platform здесь!
На данный момент с помощью библиотеки php Cloud Storage невозможно получить имя временного файла, созданного при использовании метода downloadAsStream(). Поэтому я создал запрос функции от вашего имени, вы можете подписаться на него здесь.
В качестве обходного пути вы можете удалить файл вручную, вы можете получить имя временного файла, используя следующую команду:
$filename = shell_exec('ls -lt | awk 'NR==2' | cut -d: -f2 | cut -d " " -f2');
После этого $filename будет содержать имя последнего измененного файла, который будет неудачным и который вы хотите удалить. Теперь с именем файла вы можете приступить к его удалению.
Обратите внимание, что перед выполнением функции вам нужно будет находиться в папке php://temp.
Спасибо @bhito. Пожалуйста, обновите ответ, если он будет добавлен в библиотеку.
Буду следить за этим и сообщу вам об этом, как только получу обновление! Удалось ли вам найти обходной путь? @lufc
Да, смотрите мое обновление выше. Это нормально, но явно не так эффективно, как могло бы быть.
Что-то вроде следующего должно помочь:
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). Мои извинения, это не четко задокументировано, но надеюсь, что это поможет!
Ничего себе, я думаю, вы правы - похоже, это зарыто в buildDownloadObjectParams() здесь: github.com/googleapis/google-cloud-php/blob/master/Storage/src/… и в getRequestOptions() здесь: github.com/googleapis/google-cloud-php/blob/master/Core/src/…
(Я попробую это, как только следующий большой файл будет сгенерирован и готов к загрузке, а затем сообщу / приму ответ)
@lufc это помогло?
да! Спасибо. На самом деле я использую tempnam(), чтобы установить имя с my-big-ol-file в качестве префикса, а затем использую его. Таким образом, при передаче большого количества файлов я могу отслеживать каталог tmp, чтобы увидеть, что загружается и т. д.
Спасибо, да, он входит в
sys_get_temp_dir()(в моем случае /tmp), но это имя файла, которое я ищу. Например./tmp/php89089809. И да, файлы очень большие, слишком большие для памяти, поэтому помещаются на диск.