PHP Conference Japan 2024

PUT 方法支持

PHP 提供了对 HTTP PUT 方法的支持,一些客户端使用该方法将文件存储到服务器上。PUT 请求比使用 POST 请求上传文件简单得多,它们看起来像这样

PUT /path/filename.html HTTP/1.1

这通常意味着远程客户端希望将后面的内容保存为:/path/filename.html 在您的 Web 树中。显然,让 Apache 或 PHP 自动允许每个人覆盖 Web 树中的任何文件不是一个好主意。因此,要处理此类请求,您必须首先告诉您的 Web 服务器您希望某个 PHP 脚本处理该请求。在 Apache 中,您可以使用 Script 指令执行此操作。它几乎可以放置在 Apache 配置文件的任何位置。一个常见的位置是在 <Directory> 块内,或者可能是在 <VirtualHost> 块内。以下行可以解决问题

Script PUT /put.php

这告诉 Apache 将所有与您放置此行的上下文匹配的 URI 的 PUT 请求发送到 put.php 脚本。当然,这假设您已为 .php 扩展启用了 PHP,并且 PHP 处于活动状态。所有对此脚本的 PUT 请求的目标资源必须是脚本本身,而不是上传的文件应具有的文件名。

使用 PHP,您可以在您的 put.php 中执行以下操作。这会将上传文件的内容复制到服务器上的 myputfile.ext 文件。在执行此文件复制之前,您可能希望执行一些检查和/或对用户进行身份验证。

示例 #1 保存 HTTP PUT 文件

<?php
/* PUT 数据通过 stdin 流传入 */
$putdata = fopen("php://input", "r");

/* 打开一个文件以供写入 */
$fp = fopen("myputfile.ext", "w");

/* 一次读取 1 KB 的数据
并写入文件 */
while ($data = fread($putdata, 1024))
fwrite($fp, $data);

/* 关闭流 */
fclose($fp);
fclose($putdata);
?>

添加注释

用户贡献的注释 6 条注释

micronix at gmx dot net
14 年前
你好 PHP 世界 经过几个小时的担心 :=)

我找到了恢复或暂停上传的解决方案
在此代码片段中,它是服务器端,而不是任何桌面程序上的客户端,您必须使用字节范围来计算已上传的字节和总字节数的缺失部分。

以下是 PHP 代码

<?php
$CHUNK
= 8192;

try {
if (!(
$putData = fopen("php://input", "r")))
throw new
Exception("无法获取PUT数据。");

// 现在参数可以像其他变量一样使用
// 在输入完成后查看以下内容

$tot_write = 0;
$tmpFileName = "/var/dev/tmp/PUT_FILE";
// 创建临时文件
if (!is_file($tmpFileName)) {
fclose(fopen($tmpFileName, "x")); // 创建文件并关闭它
// 以写入模式打开文件
if (!($fp = fopen($tmpFileName, "w")))
throw new
Exception("无法写入临时文件。");

// 一次读取一部分数据并写入文件
while ($data = fread($putData, $CHUNK)) {
$chunk_read = strlen($data);
if ((
$block_write = fwrite($fp, $data)) != $chunk_read)
throw new
Exception("无法继续写入临时文件。");

$tot_write += $block_write;
}

if (!
fclose($fp))
throw new
Exception("无法关闭临时文件。");

unset(
$putData);
} else {
// 以写入模式打开文件
if (!($fp = fopen($tmpFileName, "a")))
throw new
Exception("无法写入临时文件。");

// 一次读取一部分数据并写入文件
while ($data = fread($putData, $CHUNK)) {
$chunk_read = strlen($data);
if ((
$block_write = fwrite($fp, $data)) != $chunk_read)
throw new
Exception("无法继续写入临时文件。");

$tot_write += $block_write;
}

if (!
fclose($fp))
throw new
Exception("无法关闭临时文件。");

unset(
$putData);
}

// 检查文件长度和MD5
if ($tot_write != $file_size)
throw new
Exception("文件大小错误。");

$md5_arr = explode(' ', exec("md5sum $tmpFileName"));
$md5 = $md5sum_arr[0];
if (
$md5 != $md5sum)
throw new
Exception("MD5错误。");
} catch (
Exception $e) {
echo
'', $e->getMessage(), "\n";
}
?>
arnaud at caramia dot Fr
1 年前
我们使用 https://pecl.php.net/package/apfd.解决了我们的问题。

它使用 PUT 和 PATCH HTTP 请求解析 multipart/form-data 主体(文件和有效负载),这在之前只能使用 POST HTTP 请求实现。
Oscar Fernandez Sierra
2 年前
这是对我有用的方法。网上有很多示例不起作用。我在 https://lornajane.net/posts/2009/putting-data-fields-with-php-curl.找到了。

重要提示:您不应该使用以下代码

curl_setopt($ch, CURLOPT_PUT, true);

即使它看起来像是正确的选项(对于 POST 请求来说,使用 CURLOPT_POST 是正确的选项,但对于 PUT 请求却不起作用)。

请注意,此处使用常量 CURLOPT_CUSTOMREQUEST 而不是 CURLOPT_PUT,并且使用“PUT”而不是 true 作为值。

<?php

$url
= "....."; // 在此处填写您的 URL

$data = array("a" => $a);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));

$response = curl_exec($ch);
if ( !
$response) {
return
false;
}
polygon dot co dot in at gmail dot com
1 年前
我对使用 PUT 方法上传文件感到困惑。
我的疑问是为什么我们不能使用流通过 PUT 方法上传多个文件。
PUT 数据通过 stdin 流传入。
$putdata = fopen("php://input", "r");
请注意,$putdata 是指向正在上传的文件内容的文件指针。
数据在服务器端动态接收(这意味着在接收时可用)。

其次,当我们使用 parse_str(file_get_contents("php://input")) 时。
这意味着数据已完全接收在服务器端,然后提供给脚本。

当使用 fopen() 时,无法解析数据。这可以用于上传大型文件。
文件大小可能从数百 MB 到 GB 不等,流在此发挥着重要作用。

流使文件数据以块的形式提供给脚本,而不是先保存到临时文件夹中。
因此,当使用 $putdata = fopen("php://input", "r"); 时,无法同时传递有效负载。
如果有人想要传递有效负载,唯一的选择是通过 URL 查询字符串。
San
10 年前
不使用 fread fwrite 将上传的内容保存到文件中。
stream_copy_to_stream 更简洁。
willy at kochkonsult dot no
3 年前
我找到的所有关于使用 PHP 进行 PUT 操作的示例代码都对传入流使用了默认的硬编码文件扩展名。

来自传入文件 PUT 请求的文件名在传入请求中找不到(至少我找不到),但 MIME 类型可以在 $_SERVER 全局变量中找到。

我使用以下代码获取正确的文件扩展名

$mimeType = $_SERVER['HTTP_CONTENT_TYPE'];

if ($mimeType!='application/pdf')
{
header('HTTP/1.1 405 只允许 PDF 文件');
echo("仅允许上传 PDF 文件 - 此文件为 ".$mimeType);
die();
}
else $fileExtension = 'pdf';

如果您有可用的 Apache Tika 服务器,那将是分析文件内容以获取 MIME 类型的最佳选择,但这可能不适合所有人 :-)
To Top