Google Cloud Storage получает имя временного файла (используя 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 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

Это возможно, см. принятый ответ ниже.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
711
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Скорее всего, это будет настроенный системой временный каталог, который вы можете получить с помощью sys_get_temp_dir.

Обратите внимание, что это будет сохраняться в файл только при необходимости и может находиться в памяти. https://www.php.net/manual/en/wrappers.php.php

Редактировать: Хорошо, файл создан. Тогда вы, вероятно, можете использовать stream_get_meta_data в дескрипторе потока, чтобы получить эту информацию из потока.

Спасибо, да, он входит в sys_get_temp_dir() (в моем случае /tmp), но это имя файла, которое я ищу. Например. /tmp/php89089809. И да, файлы очень большие, слишком большие для памяти, поэтому помещаются на диск.

lufc 12.07.2019 21:13

@lufc Ahhh хорошо ... Обновлен ответ с информацией об этом.

inquam 12.07.2019 21:19

В нижней части моего вопроса вы можете увидеть вывод stream_get_meta_data и почему это не сработало :)

lufc 12.07.2019 21:19

Ах, прости... Я слишком устал после долгой поездки. Это то, что "должно" дать вам. Не уверен, почему это не так. Вы МОЖЕТЕ перебрать решение и получить список файлов в временной папке, принадлежащей пользователю, владеющему вашим php-процессом, и сравнить его позже, чтобы найти добавленные файлы. Но это не так элегантно, как получение пути к конкретному файлу. :П

inquam 12.07.2019 21:22

Кроме того, в Guzzle у вас есть возможность установить имя сохраняемого файла. Разве у вас нет доступа к этому и вы можете использовать это, чтобы вы знали имя с тех пор, как вы его установили?

inquam 12.07.2019 21:25

Поддержка 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 22.07.2019 21:02

Буду следить за этим и сообщу вам об этом, как только получу обновление! Удалось ли вам найти обходной путь? @lufc

bhito 23.07.2019 09:11

Да, смотрите мое обновление выше. Это нормально, но явно не так эффективно, как могло бы быть.

lufc 23.07.2019 13:30
Ответ принят как подходящий

Что-то вроде следующего должно помочь:

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/s‌​rc/… и в getRequestOptions() здесь: github.com/googleapis/google-cloud-php/blob/master/Core/src/‌​…

lufc 24.07.2019 03:02

(Я попробую это, как только следующий большой файл будет сгенерирован и готов к загрузке, а затем сообщу / приму ответ)

lufc 25.07.2019 18:32

@lufc это помогло?

david s 07.08.2019 22:37

да! Спасибо. На самом деле я использую tempnam(), чтобы установить имя с my-big-ol-file в качестве префикса, а затем использую его. Таким образом, при передаче большого количества файлов я могу отслеживать каталог tmp, чтобы увидеть, что загружается и т. д.

lufc 08.08.2019 02:10

Другие вопросы по теме