如何将通过 Filepicker 发出的 file/s 上传请求转换为使用简单的 HTML File control/s in PHP 发出的类似请求?
How to convert the file/s upload request made through Filepicker into the similar request made by using simple HTML File control/s in PHP?
我的表格上有简单的 HTML 文件 control/s。它本质上是动态的,意味着用户可以上传一个或多个文件。它的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 文件 control/s 将文件上传到服务器。但我面临的问题是,考虑到上述数组的($_FILES
)内容,已经编写了进一步的代码逻辑和操作。
所以,我想将来自 Filepicker 的请求转换为与数组相同的格式 $_FILES
,这样就不需要对已经编写的代码逻辑和操作进行任何更改。
让我更清楚地解释一下这个场景,如果用户通过 Filepicker 从 Google 驱动器中选择一个或多个图像文件并提交表单,请求将包含由 Filepicker 生成的这些图像的 URL 和文件名。
我想使用此数据并形成与上述数组相同的数组($_FILES
)。
假设您正在使用 PHP 5.2.1 或更高版本并且可以在 copy()
和 file_get_contents()
中使用 HTTPS 流包装器,这个功能应该是您所需要的:
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()
中,使其采用文件数组 URLs:
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 documentation):
$files = array('name' => array(),
'type' => array(),
'tmp_name' => array(),
'error' => array(),
'size' => array());
将 $files
初始化为不包含任何文件的类似于 $_FILES
的数组。
$tmpdir = sys_get_temp_dir();
获取存放临时文件的目录,因为我们要将文件下载到那里(此功能需要PHP5.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));
尝试使用 copy()
以 URL 作为源将文件下载到 $tmp
。
copy()
编辑的值 return 成功时为 TRUE
,失败时为 FALSE
。
$_FILES
中出现的错误值在成功时为 UPLOAD_ERR_OK
,否则为任何其他值(source,如果失败,我将在此处使用 UPLOAD_ERR_NO_FILE
)。
因此,为了分配一个有意义的错误值,我们使用三元运算符将 UPLOAD_ERR_OK
添加到错误代码列表中 if copy()
returns 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()
的参数获取文件元数据,这应该 return 我们使用 [=47 将其解码为关联数组的 JSON 数组=].
由于我们将 &filename=true&mimetype=true
附加到 URL 的末尾,我们将只会获得值 filename
和 mimetype
- 我们不需要所有其他值。
我们分配给 $meta
;
的解码数组
$files['name'][] = $meta['filename'];
$files['type'][] = $meta['mimetype'];
将刚刚解码的 JSON 数组中的值 filename
和 mimetype
分别添加到文件名和 mime 类型列表中。
return array('image' => $files);
Return 一个数组,其中 image
键指向我们创建的文件数组。
我们完成了。
演示? :(
我不会为此建立一个完整的文件托管网站,因为这将花费我写这个答案所需时间的五倍。
所以恐怕我无法为您提供完整的现场演示。
不幸的是,3v4l nor codepad 都没有启用 HTTPS 流包装器,所以我什至无法为您提供 "see-for-yourself" 概念验证演示。
我能做的最好的可能是我的终端截图window(点击放大):
我的表格上有简单的 HTML 文件 control/s。它本质上是动态的,意味着用户可以上传一个或多个文件。它的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 文件 control/s 将文件上传到服务器。但我面临的问题是,考虑到上述数组的($_FILES
)内容,已经编写了进一步的代码逻辑和操作。
所以,我想将来自 Filepicker 的请求转换为与数组相同的格式 $_FILES
,这样就不需要对已经编写的代码逻辑和操作进行任何更改。
让我更清楚地解释一下这个场景,如果用户通过 Filepicker 从 Google 驱动器中选择一个或多个图像文件并提交表单,请求将包含由 Filepicker 生成的这些图像的 URL 和文件名。
我想使用此数据并形成与上述数组相同的数组($_FILES
)。
假设您正在使用 PHP 5.2.1 或更高版本并且可以在 copy()
和 file_get_contents()
中使用 HTTPS 流包装器,这个功能应该是您所需要的:
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()
中,使其采用文件数组 URLs:
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 documentation):
$files = array('name' => array(),
'type' => array(),
'tmp_name' => array(),
'error' => array(),
'size' => array());
将 $files
初始化为不包含任何文件的类似于 $_FILES
的数组。
$tmpdir = sys_get_temp_dir();
获取存放临时文件的目录,因为我们要将文件下载到那里(此功能需要PHP5.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));
尝试使用 copy()
以 URL 作为源将文件下载到 $tmp
。
copy()
编辑的值 return 成功时为 TRUE
,失败时为 FALSE
。
$_FILES
中出现的错误值在成功时为 UPLOAD_ERR_OK
,否则为任何其他值(source,如果失败,我将在此处使用 UPLOAD_ERR_NO_FILE
)。
因此,为了分配一个有意义的错误值,我们使用三元运算符将 UPLOAD_ERR_OK
添加到错误代码列表中 if copy()
returns 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()
的参数获取文件元数据,这应该 return 我们使用 [=47 将其解码为关联数组的 JSON 数组=].
由于我们将 &filename=true&mimetype=true
附加到 URL 的末尾,我们将只会获得值 filename
和 mimetype
- 我们不需要所有其他值。
我们分配给 $meta
;
$files['name'][] = $meta['filename'];
$files['type'][] = $meta['mimetype'];
将刚刚解码的 JSON 数组中的值 filename
和 mimetype
分别添加到文件名和 mime 类型列表中。
return array('image' => $files);
Return 一个数组,其中 image
键指向我们创建的文件数组。
我们完成了。
演示? :(
我不会为此建立一个完整的文件托管网站,因为这将花费我写这个答案所需时间的五倍。
所以恐怕我无法为您提供完整的现场演示。
不幸的是,3v4l nor codepad 都没有启用 HTTPS 流包装器,所以我什至无法为您提供 "see-for-yourself" 概念验证演示。
我能做的最好的可能是我的终端截图window(点击放大):