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.
PHP ofrece soporte para el método PUT de HTTP utilizado por algunos clientes para almacenar ficheros en un servidor. Las peticiones PUT son mucho más simples que una subida de ficheros mediante peticiones POST. Se ven algo como esto:
PUT /ruta/nombrefichero.html HTTP/1.1
Esto normalmente significaría que el cliente remoto quiere guardar
el contenido que le sigue como: /ruta/nombrefichero.html en el árbol web.
Obviamente, no es una buena idea que Apache o PHP permitan a todo el mundo
sobrescribir automáticamente cualquier fichero del árbol web. Por tanto, para manejar
tales peticiones se debe primero indicar al servidor web que
cierto script de PHP maneje la petición. En Apache, esto se
hace con la directiva Script. Esta se puede
colocar casi en cualquier parte del fichero de configuración de Apache. Un
lugar común es dentro de un bloque <Directory>
o tal vez dentro
de un bloque <VirtualHost>
. Una línea como ésta resolvería el problema:
Script PUT /put.php
Esto le indica a Apache que envíe todas las peticiones PUT para los URI que coincidan con el contexto en el cual se pone esta línea en el script put.php. Se asume, por supuesto, que se tiene habilitado PHP para la extensión .php y que PHP está activo. El recurso de destino para todas las peiticiones PUT a este script tiene que ser el propio script, no el nombre de fichero que debería tener el fichero subido.
Entonces, con PHP se haría algo como lo siguiente en el fichero put.php. Se copiaría el contenido del fichero subido al fichero mificheroput.ext en el servidor. Podría ser conveniente realizar algunas comprobaciones y/o autenticar al usuario antes de realizar esta copia del fichero.
Ejemplo #1 Guardar ficheros PUT de HTTP
<?php
/* Los datos de PUT vienen en el flujo de entrada estándar */
$datosPUT = fopen("php://input", "r");
/* Abrir un fichero para escritura */
$fp = fopen("mificheroput.ext", "w");
/* Leer 1 KB de datos cada vez
y escribir en el fichero */
while ($datos = fread($datosPUT, 1024))
fwrite($fp, $datos);
/* Cerrar los flujos */
fclose($fp);
fclose($datosPUT);
?>
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.
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";
}
?>
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;
}
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.
Instead of using fread fwrite to save uploaded content to a file.
stream_copy_to_stream is much cleaner.
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 :-)
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.
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);
?>