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

Поддержка метода PUT была изменена при переходе от PHP 3 к PHP 4. В PHP 4 вы должны использовать стандартный поток ввода для чтения файла, передаваемого методом HTTP PUT.

Пример #1 Сохранение загруженного при помощи HTTP PUT файла в PHP 4

<?php
/* Данные PUT находятся в потоке stdin */
$putdata fopen("php://stdin""r");

/* Открываем файл для записи */
$fp fopen("myputfile.ext""w");

/* Читаем данные блоками размером в 1 KB и
   записываем их в файл */
while ($data fread($putdata1024))
  
fwrite($fp$data);

/* Закрываем потоки */
fclose($fp);
fclose($putdata);
?>

Замечание: Вся документация, приведенная ниже, касается исключительно PHP 3.

PHP поддерживает загрузку файлов методом HTTP PUT, который используется в клиентах Netscape Composer и W3C Amaya. Запрос PUT выглядит проще, чем в случае обыкновенной загрузки файла на сервер:

PUT /path/filename.html HTTP/1.1
     

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

Script PUT /put.php
     

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

Внутри вашего файла put.php file вы можете поместить что-нибудь похожее на это:

<?php copy($PHP_UPLOADED_FILE_NAME$DOCUMENT_ROOT $REQUEST_URI); ?>

Приведенный код скопирует файл в место, запрошенное клиентом. Возможно, вы захотите выполнить какую-либо проверку и/или аутентифицировать пользователя, прежде чем выполнять копирование. Трюк состоит в том, что когда PHP видит PUT-запрос, он сохраняет полученный файл во временной папке, как и при загрузке методом POST. По окончании обработки запроса временный файл удаляется. Поэтому ваш PHP-скрипт, обрабатывающий PUT-запрос, должен скопировать куда-либо полученный файл. Имя временного файла хранится в переменной $PHP_PUT_FILENAME, а предполагаемое имя файла можно найти в переменной $REQUEST_URI (может быть другим на веб-серверах, отличных от Apache). Запрашиваемое имя файла указывается удаленным клиентом. Вы не обязаны следовать его указаниям. Например, вы можете скопировать все загруженные файлы в отдельный каталог.

Коментарии

I have spent a lot of time trying to make PUT work with Apache 2.0.40. I have not yet been able to find any way of making the Script directive invoke php via mod_php, the only way has been to have a file called example.cgi and invoke it via CGI, with the file starting
#!/usr/bin/php
so the PHP interpreter is invoked through the CGI mechanism and not as a module.

If there IS a way of making it work 'right' I'd love to know! After six hours of messing around, I've settled for CGI. The error messages in the apache error log are significantly misleading and the whole thing has been an exercise in frustration.

Attempts to use AddHandler and all 'normal' ways of trying to persuade Apache to do this have been fruitless. It does seem as if PUT can only be handled by CGI invocation.
2003-11-03 16:41:55
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
Автор:
A Case Study:  To set up publishing with Netscape 7.2 Composer to Apache/PHP, no need to use CGI (which I tried unsuccessfully for too long) or to alter Apache's httpd.conf.  I needed only to click Publish As, fill in put2disk.php as the filename (where its contents are the below), and fill in that file's dir as the "Publishing address".
XAMPP 1.4.14: Apache/2.0.54 (Win32) mod_ssl/2.0.54 OpenSSL/0.9.7g PHP/5.0.4.

<? // filename: put2disk.php.

//file_put_contents ("get_def.out", print_r (get_defined_vars(), TRUE)); // debugging

// Two slurp methods: (a) didn't work, (b) did.
//$stdin_rsc = fopen("php://input", "r");
//$putdata='';
//while ($putdata .= fread($stdin_rsc, 1024)); // a. Hangs the "Publishing..." dialog.
//while (!feof($stdin_rsc)) $putdata.=fread($stdin_rsc, 8192); // b. Worked, but file_get_contents is faster.
//fclose($stdin_rsc);

// All that's nec:
$putdata=file_get_contents('php://input'); // Not php://stdin! (When the ability to see error messages isn't available, the doc (this manual page) needs to be more accurate.)

file_put_contents("stdin.out",$putdata);
?>
2005-08-15 05:16:38
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
NOTE: The <Script>-Directive can not be placed in .htaccess files.

So if you're having shared webspace and no access to the apache-configuration file you will have little chance to make something like this work.

But you can solve the problem, using mod_rewrite (for Apache) - for further information see the documentation at http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
2005-09-20 16:22:43
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
PUT raw data comes in php://input, and you have to use fopen() and fread() to get the content. file_get_contents() is useless. 

The HTTP PUT request MUST contain a Content-Length header to specify the length (in bytes) of the body, or the server will not be able to know when the input stream is over. This is the common problem for many to find the php://input empty if no such header available. 

This should make PUT work properly on win32 using PHP5.1.1 and apache2.
2005-12-14 06:01:31
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
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";
        }
?>
2010-09-10 22:43:53
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
Автор:
Instead of using fread fwrite to save uploaded content to a file.
stream_copy_to_stream is much cleaner.
2014-03-19 23:33:59
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
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 :-)
2021-11-25 15:35:09
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
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($chCURLOPT_RETURNTRANSFERtrue);
       
curl_setopt($chCURLOPT_CUSTOMREQUEST"PUT");
       
curl_setopt($chCURLOPT_POSTFIELDShttp_build_query($data));

       
$response curl_exec($ch);
        if ( ! 
$response) {
            return 
false;
        }
2021-12-14 11:27:37
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
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.
2023-04-23 12:11:59
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html
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.
2023-06-08 09:27:23
http://php5.kiev.ua/manual/ru/features.file-upload.put-method.html

    Поддержать сайт на родительском проекте КГБ