Как преобразовать запрос загрузки файла /s, сделанный с помощью Filepicker, в аналогичный запрос, сделанный с помощью простого элемента управления файлами HTML в PHP?

У меня есть простой элемент управления файлами HTML в моей форме. Он динамичен по своей природе, означает, что пользователь может загружать один или несколько файлов. Его HTML выглядит следующим образом:

<input type="file" id="image_book" class="image_book upload" name="image[]" accept="image/*" value=""/>

Если я загружу два изображения, используя вышеуказанное управление файлами HTML, и отправьте форму, которую я получаю в массиве $_FILES (вывод print_r($_FILES);):

Array
(
    [image] => Array
        (
            [name] => Array
                (
                    [0] => Aurbd-b3582991-large.jpg
                    [1] => BL_Miller_GD_Square_KV_300dpi_A2.jpg
                )

            [type] => Array
                (
                    [0] => image/jpeg
                    [1] => image/jpeg
                )

            [tmp_name] => Array
                (
                    [0] => /tmp/phpSt8CJJ
                    [1] => /tmp/phpibFjR2
                )

            [error] => Array
                (
                    [0] => 0
                    [1] => 0
                )

            [size] => Array
                (
                    [0] => 519179
                    [1] => 86901
                )

        )

)

Теперь, согласно новому требованию, я должен использовать Filepicker вместо простого элемента управления файлами HTML для загрузки файлов на сервер. Но проблема, с которой я сталкиваюсь, заключается в том, что дальнейшая логика кода и манипуляция уже были написаны с учетом содержимого указанного выше массива ($_FILES).

Итак, я хочу преобразовать запрос, поступающий через Filepicker, в тот же формат, что и в массиве $_FILES, чтобы не было необходимости вносить какие-либо изменения в уже написанную логику кода и манипуляции.

Позвольте мне объяснить вам сценарий более четко, если пользователь выбирает один или несколько файлов изображений с Google Диска через Filepicker и отправляет форму, запрос будет содержать URL-адреса тех образов, которые генерируются Filepicker и имена файлов.

Я хочу использовать эти данные и сформировать массив как из предыдущего массива ($_FILES).

Ответ 1

Предполагая, что вы используете PHP 5.2.1 или новее и можете использовать оболочку потока HTTPS в copy() и file_get_contents(), эта функция должна быть все, что вам нужно:

function getFilepickerFiles($tokens)
{
    $files = array('name' => array(),
                   'type' => array(),
                   'tmp_name' => array(),
                   'error' => array(),
                   'size' => array());
    $tmpdir = sys_get_temp_dir();
    foreach($tokens as $token)
    {
        $files['tmp_name'][] = $tmp = $tmpdir.'/php'.$token;
        $files['error'][] = copy('https://www.filepicker.io/api/file/'.$token, $tmp) ? UPLOAD_ERR_OK : UPLOAD_ERR_NO_FILE;
        $files['size'][] = filesize($tmp);
        $meta = json_decode(file_get_contents('https://www.filepicker.io/api/file/'.$token.'/metadata?filename=true&mimetype=true'), TRUE);
        $files['name'][] = $meta['filename'];
        $files['type'][] = $meta['mimetype'];
    }
    return array('image' => $files);
}

Эта функция принимает в качестве аргумента массив токенов (например, hFHUCB3iTxyMzseuWOgG).
Вы можете назвать это как

getFilepickerFiles(array('hFHUCB3iTxyMzseuWOgG'));

Я не знаю точно, что Filepicker передает на ваш сервер, но если это полный URL-адрес файла, например

https://www.filepicker.io/api/file/hFHUCB3iTxyMzseuWOgG

то вы можете извлечь токены следующим образом:

$tokens = array();
foreach($urls as $url)
{
    $matches = array();
    preg_match('# ^https://www\\.filepicker\\.io/api/file/([^/]*)/?', $url, $matches);
    $tokens[] = $matches[1];
}
// Pass $tokens to getFilepickerFiles()

Вы также можете поместить это право в getFilepickerFiles(), чтобы вместо этого взять массив URL-адресов файлов:

function getFilepickerFiles($urls)
{
    $files = array('name' => array(),
                   'type' => array(),
                   'tmp_name' => array(),
                   'error' => array(),
                   'size' => array());
    $tmpdir = sys_get_temp_dir();
    foreach($urls as $url)
    {
        $matches = array();
        preg_match('# ^https://www\\.filepicker\\.io/api/file/([^/]*)/?', $url, $matches);
        $token = $matches[1];
        $files['tmp_name'][] = $tmp = $tmpdir.'/php'.$token;
        $files['error'][] = copy('https://www.filepicker.io/api/file/'.$token, $tmp) ? UPLOAD_ERR_OK : UPLOAD_ERR_NO_FILE;
        $files['size'][] = filesize($tmp);
        $meta = json_decode(file_get_contents('https://www.filepicker.io/api/file/'.$token.'/metadata?filename=true&mimetype=true'), TRUE);
        $files['name'][] = $meta['filename'];
        $files['type'][] = $meta['mimetype'];
    }
    return array('image' => $files);
}

Объяснение

Мне кажется, что приведенный выше код довольно прост, но вот как работает getFilepickerFiles() (вы должны прочитать документацию по остаточному API до прочитав это):

$files = array('name' => array(),
               'type' => array(),
               'tmp_name' => array(),
               'error' => array(),
               'size' => array());

Инициализировать $files массиву вроде $_FILES, не содержащему файлов.

$tmpdir = sys_get_temp_dir();

Получить каталог, в котором хранятся временные файлы, потому что мы будем загружать туда файлы (для этой функции требуется PHP 5.2.1 или новее).

foreach($urls as $url)

Что foreach должно быть ясным.

$files['tmp_name'][] = $tmp = $tmpdir.'/php'.$token;

Создайте наш временный путь к файлу, следуя шаблону $_FILES (т.е. путь к папке временных файлов, строка "php" и некоторые случайные символы).
Это имя мы присваиваем $tmp (для более легкого использования позднее), и мы добавляем его в список путей к файлам.

$files['error'][] = (int)(!copy('https://www.filepicker.io/api/file/'.$token, $tmp));

Попытайтесь загрузить файл в $tmp с помощью copy() с URL-адресом в качестве источника.
Значение, возвращаемое copy(), равно TRUE при успешном завершении и FALSE при ошибке.
Значения ошибок, присутствующие в $_FILES, являются UPLOAD_ERR_OK при успехе и в любом другом значении в противном случае (source, я собираюсь с UPLOAD_ERR_NO_FILE здесь в случае отказа).
Поэтому, чтобы назначить значимое значение ошибки, мы используем тернарный оператор, чтобы добавить UPLOAD_ERR_OK в список кодов ошибок, если copy() возвращает TRUE и UPLOAD_ERR_NO_FILE в противном случае.

$files['size'][] = filesize($tmp);

Запросить размер файла и добавить его в список размеров файлов.

$meta = json_decode(file_get_contents('https://www.filepicker.io/api/file/'.$token.'/metadata?filename=true&mimetype=true'), TRUE);

Получить метаданные файлов, используя URL-адрес в качестве аргумента для file_get_contents(), который должен вернуть массив JSON, который мы декодируем в ассоциативный массив, используя json_decode(/*...*/, TRUE).
Поскольку мы добавили &filename=true&mimetype=true в конец URL-адреса, мы получим только значения filename и mimetype - нам не нужно все остальное.
Декодированный массив, который мы присваиваем $meta;

$files['name'][] = $meta['filename'];
$files['type'][] = $meta['mimetype'];

Добавьте значения filename и mimetype из только что декодированного массива JSON в списки имен файлов и типов mime соответственно.

return array('image' => $files);

Возвращает массив с ключом image, указывающим на массив файлов, которые мы создали.

И все готово.


Demo? (

Я не собираюсь создавать для этого весь веб-сайт для хостинга файлов, потому что для написания этого ответа потребуется в пять раз больше времени.
Поэтому я боюсь, что не смогу предоставить вам полноценную демо-версию.

К сожалению, ни 3v4l, ни codepad активизирована оболочка потока HTTPS, поэтому я даже не могу предоставить вам доказательство демонстрации концепции "для себя".

Лучшее, что я могу сделать, это, вероятно, скриншот моего окна терминала (нажмите, чтобы увеличить):

введите описание изображения здесь