Поддержка метода PUT

PHP поддерживает HTTP-метод PUT, через который отдельные клиенты отправляют файлы на сервер для хранения. PUT-запросы проще, чем загрузка файлов POST-запросами, а выглядят PUT-запросы примерно так:

PUT /path/filename.html HTTP/1.1

Обычно такой вызов означает, что удалённый клиент хотел бы сохранить файл /path/filename.html в дереве каталогов веб-сервера. Не сомневаемся, что настраивать веб-сервер Apache или PHP так, чтобы они разрешали каждому автоматически перезаписывать файлы веб-сервера, — плохая идея. Поэтому, чтобы обработать такой запрос, потребуется сначала сообщить веб-серверу, чтобы запрос обрабатывал конкретный PHP-скрипт. На веб-сервере Apache это делается через директиву Script. Обычно директиву записывают в произвольном месте конфигурационного файла веб-сервера Apache внутри блока <Directory> или, возможно, внутри блока <VirtualHost>. Строка наподобие этой укажет веб-серверу конкретный PHP-файл для обработки запроса:

Script PUT /put.php

Строка говорит веб-серверу Apache перенаправлять каждый PUT-запрос к URI-идентификаторам, которые соответствуют контексту, в котором записали строку, в файл put.php. Предполагается, что файлы с расширением .php обрабатываются как PHP-скрипты, и что сам PHP активен. Ресурсом назначения для PUT-запросов к этому скрипту должен быть сам скрипт, а не имя, которое требуется дать загружаемому файлу.

Затем внутри файла 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 notes

up
37
micronix at gmx dot net
14 years ago
Hello PHP World After many Hours of worryness :=)

I have found the Solution for Resume or Pause Uploads
In this Code Snippet it is the Server Side not Client on any Desktop Programm you must use byte ranges to calculate the uploaded bytes and missing of total bytes.

Here the PHP Code

<?php
$CHUNK
= 8192;

try {
if (!(
$putData = fopen("php://input", "r")))
throw new
Exception("Can't get PUT data.");

// now the params can be used like any other variable
// see below after input has finished

$tot_write = 0;
$tmpFileName = "/var/dev/tmp/PUT_FILE";
// Create a temp file
if (!is_file($tmpFileName)) {
fclose(fopen($tmpFileName, "x")); //create the file and close it
// Open the file for writing
if (!($fp = fopen($tmpFileName, "w")))
throw new
Exception("Can't write to tmp file");

// Read the data a chunk at a time and write to the file
while ($data = fread($putData, $CHUNK)) {
$chunk_read = strlen($data);
if ((
$block_write = fwrite($fp, $data)) != $chunk_read)
throw new
Exception("Can't write more to tmp file");

$tot_write += $block_write;
}

if (!
fclose($fp))
throw new
Exception("Can't close tmp file");

unset(
$putData);
} else {
// Open the file for writing
if (!($fp = fopen($tmpFileName, "a")))
throw new
Exception("Can't write to tmp file");

// Read the data a chunk at a time and write to the file
while ($data = fread($putData, $CHUNK)) {
$chunk_read = strlen($data);
if ((
$block_write = fwrite($fp, $data)) != $chunk_read)
throw new
Exception("Can't write more to tmp file");

$tot_write += $block_write;
}

if (!
fclose($fp))
throw new
Exception("Can't close tmp file");

unset(
$putData);
}

// Check file length and MD5
if ($tot_write != $file_size)
throw new
Exception("Wrong file size");

$md5_arr = explode(' ', exec("md5sum $tmpFileName"));
$md5 = $md5sum_arr[0];
if (
$md5 != $md5sum)
throw new
Exception("Wrong md5");
} catch (
Exception $e) {
echo
'', $e->getMessage(), "\n";
}
?>
up
5
arnaud at caramia dot Fr
1 year ago
We resolved our problem with https://pecl.php.net/package/apfd.

It parses multipart/form-data body (files and payload) with PUT and PATCH http requests, witch was only possible before with POST http request.
up
2
Oscar Fernandez Sierra
3 years ago
This is what worked for me. There are many examples in the web that don't work. I found in https://lornajane.net/posts/2009/putting-data-fields-with-php-curl.

IMPORTANT: You should not use the code

curl_setopt($ch, CURLOPT_PUT, true);

even if it seems to be the right option (it would be the right option for a POST request, with CURLOPT_POST, but it does not work for a PUT request).

Notice that the constant CURLOPT_CUSTOMREQUEST is used instead of CURLOPT_PUT, and that the value used is "PUT" instead of true.

<?php

$url
= "....."; // put your URL here

$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;
}
up
1
polygon dot co dot in at gmail dot com
1 year ago
I was confused with file uploads using the PUT method.
My concern was why can't we upload multiple files using the PUT method with streams
PUT data comes in on the stdin stream
$putdata = fopen("php://input", "r");
Note the $putdata is a file pointer to the file content that is being uploaded.
The data is received on the server on the fly (which means available as it is received)

Secondly, when we are using parse_str(file_get_contents("php://input")).
This means the data is completely received on the server end and is then made available to the script.

When using fopen() one cant parse the data. This can be used when uploading a large file.
The file may range from 100's of MBs to Gigs where streams plays a major role.

Streams make the file data available to script in chunks instead of first saving in the temp folder.
Hence, when using $putdata = fopen("php://input", "r"); one can't pass the payload as well.
If someone wants to pass the payload the only option is in the URL query string.
up
6
San
10 years ago
Instead of using fread fwrite to save uploaded content to a file.
stream_copy_to_stream is much cleaner.
up
1
willy at kochkonsult dot no
3 years ago
All the example code I found for using PUT with PHP always used a default hard-coded file extension for the incoming stream.

The filename from the incoming file PUT request can't be found anywhere from the incoming request (at least I couldn't find it) but mimetype can be found in the $_SERVER global variable.

I used this code to get the correct file extension:

$mimeType = $_SERVER['HTTP_CONTENT_TYPE'];

if ($mimeType!='application/pdf')
{
header('HTTP/1.1 405 Only PDF files allowed');
echo("Only PDF files are allowed for upload - this file is ".$mimeType);
die();
}
else $fileExtension = 'pdf';

If you have an Apache Tika server available, that would be the best option to analyze the file content to get the mimetype, but that might not be in scope for everyone :-)
To Top