[PHP-BUG] Req #68605 [NEW]: $_FILES should not only be filled when POST

[email protected] ("lewiscowles at me dot com")
Newsgroups php.standards
Message-ID <[email protected]>
From:             lewiscowles at me dot com
Operating system: ALL
PHP version:      Irrelevant
Package:          PHP Language Specification
Bug Type:         Feature/Change Request
Bug description:$_FILES should not only be filled when POST

Description:
------------
basically I am going to have to switch a major part of my app to Python
because I cannot PUT multiple files via CURL custom request. Made worse
by the fact PHP seems to have a bug that cuts off php:/input after the
first file (probably to do with C strings and EOF)

Test script:
---------------
// server receiving data (putEcho.php was used)
<?php $reqMeth = ( isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper(
$_SERVER['REQUEST_METHOD'] ) : 'GET' ); ?>
<?php
$_PUT = array();
if( $reqMeth == 'PUT' ) {
	$putF = fopen( "php://input", "r" );
	$tmp = fread( $putF, MAX_POST_SIZE*10 ); // limit maximum PUT size to
maximum POST size (seems reasonable)
	fclose($putF);
	$_PUT =  parse_raw_http_request( $tmp );
}
?>
put:
<?php var_dump( $_PUT ); ?>
file:
<?php var_dump( $_FILES ); ?>
<?php
//
// Functions
//
function parse_raw_http_request($input) {
	//var_dump($input);
	$a_data = array();
	// grab multipart boundary from content type header
	$matches = explode( str_ireplace( 'multipart/form-data; boundary=', '',
$_SERVER['CONTENT_TYPE'] ), $input ); //preg_match('/boundary=(.*)$/',
$_SERVER['CONTENT_TYPE'], $matches);
	// content type is probably regular form-encoded
	if (!count($matches)) {
		// we expect regular puts to containt a query string containing data
		parse_str(urldecode($input), $a_data);
		return $a_data;
	}
	$boundary = $matches[0];
	// split content by boundary and get rid of last -- element
	$a_blocks = explode($boundary,$input);//preg_split("/-+$boundary/",
$input);
	//array_pop($a_blocks);
	// loop data blocks
	foreach ($a_blocks as $id => $block) {
		if (empty($block)) { continue; }
		//var_dump( $block );
		// you'll have to var_dump $block to understand this and maybe replace
\n or \r with a visibile char
		// parse uploaded files
		if (mb_strpos($block, 'application/octet-stream') !== FALSE) {
			//var_dump( $block );
			// match "name", then everything after "stream" (optional) except for
prepending newlines
			preg_match("/name=\"([^\"]*)\".*filename=\"([^\"]*)\".*stream[\n|\r]+([^\n\r].*)?$/ms",
$block, $matches);
			$a_data['files'][$matches[1]]['filename'] = basename( $matches[2] );
//for some reason CURL can send files with an absolute path
			$a_data['files'][$matches[1]]['data'] = $matches[3];
		} else { // parse all other fields
			// match "name" and optional value in between newline sequences
			preg_match('/name=\"([^\"]*)\"[\n|\r]+([^\n\r].*)?\r$/su', $block,
$matches);
			$a_data[$matches[1]] = $matches[2];
		}
	}
	return $a_data;
}

// client to send data (name does not matter)
<?php

$data = array(
	'text'=>'bob
    bob
	漢字</textarea>
	ghghg
表外字?
表外字?表外字?',
	'file1' =>	new CURLFile( __DIR__.'/need a second monicle.jpg' ),
	'kanji'=>'漢字表外字?表外字?表外字?',
	'file2' => new CURLFile(
__DIR__.'/10620539_301923573265336_9157682394656180014_n.jpg' )
);
?>
<pre><?php var_dump( json_decode( CURL_REQ(
'http://censored/putEcho.php', 'PUT', $data/*$_POST*/ ), true ) );
?></pre>
<?php
//
// CURL lightweight helper Function...
//
function CURL_REQ( $url, $method, &$data ) {
	$ch = curl_init( $url );
	curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
	curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, $method );
	curl_setopt( $ch, CURLOPT_POSTFIELDS, $data );
	$response = curl_exec( $ch );
	return $response;
}

Expected result:
----------------
I expected (although I think I understand why) to be able to manually
parse the results of my request, even if PHP did not support populating
the $_FILES array...

Basically within 15minutes I was able to get this to work with Python,
but a large part of my system is PHP. I am always telling people PHP is
a great language and developers are part of the problem, but it seems to
me that the decision to not populate $_FILES is a bit mad

for desired outcome, I like how python FLASK is able to give me 
request.args ($_GET)
request.form ($_PUT or $_POST)
request.files ($_FILES)

and wondered if it was something that could be easily patched into PHP.

In any case I have the C code and will try custom compiling, then
patching, but my weekend is now dead, so it may be some time before I
come up with something and after 20mins python working, it might just be
easier for me to convert HTTP methods to python =(

Actual result:
--------------
well in the example given everything after the first file is missing
from php://input stream, so not even the second var gets through... I
can mitigate this by moving the posted form field values easily, but I
never get more than one file, and I am unsure if it is complete (seems
to end if 255 and 0 if I run ord on the last two bytes)

-- 
Edit bug report at https://bugs.php.net/bug.php?id=68605&edit=1
-- 
Try a snapshot (PHP 5.4):   https://bugs.php.net/fix.php?id=68605&r=trysnapshot54
Try a snapshot (PHP 5.5):   https://bugs.php.net/fix.php?id=68605&r=trysnapshot55
Try a snapshot (trunk):     https://bugs.php.net/fix.php?id=68605&r=trysnapshottrunk
Fixed in SVN:               https://bugs.php.net/fix.php?id=68605&r=fixed
Fixed in release:           https://bugs.php.net/fix.php?id=68605&r=alreadyfixed
Need backtrace:             https://bugs.php.net/fix.php?id=68605&r=needtrace
Need Reproduce Script:      https://bugs.php.net/fix.php?id=68605&r=needscript
Try newer version:          https://bugs.php.net/fix.php?id=68605&r=oldversion
Not developer issue:        https://bugs.php.net/fix.php?id=68605&r=support
Expected behavior:          https://bugs.php.net/fix.php?id=68605&r=notwrong
Not enough info:            https://bugs.php.net/fix.php?id=68605&r=notenoughinfo
Submitted twice:            https://bugs.php.net/fix.php?id=68605&r=submittedtwice
register_globals:           https://bugs.php.net/fix.php?id=68605&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=68605&r=php4
Daylight Savings:           https://bugs.php.net/fix.php?id=68605&r=dst
IIS Stability:              https://bugs.php.net/fix.php?id=68605&r=isapi
Install GNU Sed:            https://bugs.php.net/fix.php?id=68605&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=68605&r=float
No Zend Extensions:         https://bugs.php.net/fix.php?id=68605&r=nozend
MySQL Configuration Error:  https://bugs.php.net/fix.php?id=68605&r=mysqlcfg
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.