Die Unterstützung der PUT-Methode hat sich zwischen PHP 3 und PHP 4 geändert. In PHP 4 sollten Sie den Standard Input-Datenstrom benutzen, um die Inhalte eines HTTP PUT zu lesen.
Beispiel #1 Speichern von HTTP PUT Dateien mit PHP 4
<?php
/* PUT Daten kommen in den stdin Stream */
$putdata = fopen("php://stdin","r");
/* Eine Datei zum Schreiben öffnen */
$fp = fopen("myputfile.ext","w");
/* Jeweils 1kB Daten lesen und
in die Datei schreiben */
while ($data = fread($putdata,1024))
fwrite($fp,$data);
/* Die Streams schließen */
fclose($fp);
fclose($putdata);
?>
Hinweis:
Sämtliche untenstehende Dokumentation betrifft nur PHP 3.
PHP unterstützt die HTTP PUT-Methode, wie sie von Clients wie Netscape Composer oder W3C Amaya benutzt wird. PUT-Anfragen sind weitaus unkomplizierter als ein Dateiupload und sehen etwa so aus:
PUT /path/filename.html HTTP/1.1
Das würde normalerweise bedeuten, dass der entfernte Client den folgenden Inhalt als /path/filename.html im Webverzeichnisbaum speichert. Natürlich ist es keine gute Idee, dass PHP oder Apache jeden Benutzer beliebige Dateien überschreiben lassen. Um eine solche Anfrage bearbeiten zu können, muss der Webserver erst angewiesen werden, ein bestimmtes PHP-Skript für die Abarbeitung aufzurufen. Im Apache wird dies durch die Script - Direktive festgelegt. Sie kann fast überall in der Apache-Konfigurationsdatei platziert werden, gebräuchlich ist die Platzierung innerhalb einer <Directory>- oder <Virtualhost>- Sektion. Eine Zeile wie die folgende erledigt dies:
Script PUT /put.php
Diese Zeile legt fest, dass Apache alle PUT-Anfragen für URIs, die dem Kontext entsprechen, in dem diese Zeile steht, an das put.php Skript weiterleitet. Dies setzt natürlich voraus, dass PHP aktiv und für die .php-Dateierweiterung registriert ist.
Innerhalb der put.php-Datei könnte folgendes stehen:
<?php copy($PHP_UPLOADED_FILE_NAME,$DOCUMENT_ROOT.$REQUEST_URI); ?>
Dies kopiert die Datei an den vom Client angegebenen Ort. Möglicherweise sollen vor dem Kopieren der Datei noch Überprüfungen und/oder Benutzerauthentifizierung stattfinden. Wenn PHP eine PUT-Anfrage erhält, wird die Datei genau wie bei der POST-Methode in einem temporären Verzeichnis gespeichert. Nach dem Abarbeiten der Anfrage wird die temporäre Datei gelöscht. Also muss das PHP-Skript, das die PUT-Anfrage bearbeitet, die Datei irgendwohin kopieren. Der Name der temporären Datei findet sich in der Variablen $PHP_PUT_FILENAME; der Name der zu speichernden Datei steht in $REQUEST_URI (kann bei Nicht-Apache Webservern variieren). Dieser Zieldateiname wird vom Client festgelegt. Man kann den Client auch umgehen; beispielsweise könnten alle hochgeladenen Dateien in ein spezielles Upload-Directory kopiert werden.
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";
}
?>
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.
Here's my solution on my Note below
The .htacces-File
Options FollowSymLinks
RewriteEngine on
RewriteBase !!!The Path of your PUT-Upload-Folder, relative to the DocumentRoot!!!
RewriteRule ^index\.php$ - [L]
RewriteRule ^(.*)$ index.php?url=$1 [L]
index.php:
<?php
if ($_SERVER['REQUEST_METHOD'] == "PUT")
{ $f = fopen(basename($_SERVER['REQUEST_URI']), "w");
$s = fopen("php://input", "r");
while($kb = fread($s, 1024))
{ fwrite($f, $kb, 1024); }
fclose($f);
fclose($s);
Header("HTTP/1.1 201 Created"); }
elseif ($_SERVER['REQUEST_METHOD'] == "GET")
{ readfile(basename($_SERVER['REQUEST_URI'])); }
?>
Testes with Apache 2 and PHP 5, php as a module (win32)
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
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);
?>
Trying to capture a PUT stream into a single variable seems not to be allowed, probably because of the non presence of some kind of EOF. In this way save a PUT request into a database isn't easy.
The only way I find would be output to a cache file, then either insert filename into db or read again its content and place it in some kind of query.
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.
I can only make it work when I am using PHP as CGI, not as an Apache module.
I am using the version of PHP/Apahce that is shipped with Debian/testing.
You have to load the action_module, but not the put_module in Apache config.