10

我的表单上有简单的 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 File control/s 将文件上传到服务器。$_FILES但是我面临的问题是,考虑到上述数组的( )内容,已经编写了进一步的代码逻辑和操作。

因此,我想将来自 Filepicker 的请求转换为与数组相同的格式,$_FILES这样就无需对已编写的代码逻辑和操作进行任何更改。

让我更清楚地解释一下这个场景,如果用户通过 Filepicker 从 Google Drive 中选择一个或多个图像文件并提交表单,请求将包含由 Filepicker 生成的那些图像的 URL 和文件名。

我想使用这些数据并形成上述数组($_FILES)的数组。

4

1 回答 1

6

假设您使用的是 PHP 5.2.1 或更高版本并且可以在 and 中使用 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()工作原理如下(在阅读本文之前,您应该阅读Rest 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失败。
中存在的错误值$_FILESUPLOAD_ERR_OK成功的,否则是任何其他值(来源,如果失败,我会在UPLOAD_ERR_NO_FILE这里使用)。
因此,为了分配一个有意义的错误值,我们使用三元运算符添加UPLOAD_ERR_OK到错误代码列表中 if copy()return TRUEUPLOAD_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'];

将刚刚解码的 JSON 数组中的值filename和分别添加到文件名和 mime 类型列表中。mimetype

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

返回一个数组,其image键指向我们创建的文件数组。

我们完成了。


演示?:(

我不打算为此建立一个完整的文件托管网站,因为编写此答案所需的时间是我的五倍。
因此,恐怕我无法为您提供完整的现场演示。

不幸的是,3v4lcodepad都没有启用 HTTPS 流包装器,所以我什至无法为您提供“自己看”的概念验证演示。

我能做的最好的可能是我的终端窗口的截图(点击放大):

在此处输入图像描述

于 2015-05-02T19:56:37.287 回答