Reading POST data in PHP from cUrl

I am using cUrl in PHP to query from some external service.

Interestingly, the server responds with raw "multipart / form-data" instead of binary files.

My site uses shared hosting, so PECL HTTP is not an option.

Is there a way to parse this data using PHP?

Code example:

$response = curl_exec($cUrl); /* $response is raw "multipart/form-data" string --MIMEBoundaryurn_uuid_DDF2A2C71485B8C94C135176149950475371 Content-Type: application/xop+xml; charset=utf-8; type="text/xml" Content-Transfer-Encoding: binary (xml data goes here) --MIMEBoundaryurn_uuid_DDF2A2C71485B8C94C135176149950475371 Content-Type: application/zip Content-Transfer-Encoding: binary (binary file data goes here) */ 

EDIT: I tried passing the response to the localhost HTTP request, but the response data is likely to exceed the allowed memory size in the PHP process. Exceeding the memory limit is not very practical, this action also significantly reduces server performance.

If there is no alternative to the original question, you can suggest a way to handle very large POST requests along with XML analysis in terms of threads in PHP.

I know that it will be difficult, comment. I am open to discussion.

+6
source share
5 answers

if you need a zip file from the answer, I think you could just write a tmp file to save the twist, and pass it as a workaround: I have never tried this with multi-pole curls, but I think it should work.

 $fh = fopen('/tmp/foo', 'w'); $cUrl = curl_init('http://example.com/foo'); curl_setopt($cUrl, CURLOPT_FILE, $fh); // redirect output to filehandle curl_exec($cUrl); curl_close($cUrl); fclose($fh); // close filehandle or the file will be corrupted 

if you do NOT need anything other than the part of the xml response you can disable the headers

 curl_setopt($cUrl, CURLOPT_HEADER, FALSE); 

and add parameter to accept only xml as response

 curl_setopt($cUrl, CURLOPT_HTTPHEADER, array('Accept: application/xml')); //That a workaround since there is no available curl option to do so but http allows that 

[EDIT]

A shot in the dark ... you can test with these curlopt settings to see if this improves their performance

 $headers = array ( 'Content-Type: multipart/form-data; boundary=' . $boundary, 'Content-Length: ' . strlen($requestBody), 'X-EBAY-API-COMPATIBILITY-LEVEL: ' . $compatLevel, // API version 'X-EBAY-API-DEV-NAME: ' . $devID, 'X-EBAY-API-APP-NAME: ' . $appID, 'X-EBAY-API-CERT-NAME: ' . $certID, 'X-EBAY-API-CALL-NAME: ' . $verb, 'X-EBAY-API-SITEID: ' . $siteID, ); $cUrl = curl_init(); curl_setopt($cUrl, CURLOPT_URL, $serverUrl); curl_setopt($cUrl, CURLOPT_TIMEOUT, 30 ); curl_setopt($cUrl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($cUrl, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($cUrl, CURLOPT_HTTPHEADER, $headers); curl_setopt($cUrl, CURLOPT_POST, 1); curl_setopt($cUrl, CURLOPT_POSTFIELDS, $requestBody); curl_setopt($cUrl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($cUrl, CURLOPT_FAILONERROR, 0 ); curl_setopt($cUrl, CURLOPT_FOLLOWLOCATION, 1 ); curl_setopt($cUrl, CURLOPT_HEADER, 0 ); curl_setopt($cUrl, CURLOPT_USERAGENT, 'ebatns;xmlstyle;1.0' ); curl_setopt($cUrl, CURLOPT_HTTP_VERSION, 1 ); // HTTP version must be 1.0 $response = curl_exec($cUrl); if ( !$response ) { print "curl error " . curl_errno($cUrl ) . PHP_EOL; } curl_close($cUrl); 

[EDIT II]

This is just an attempt, as already mentioned, I cannot get my curled pages to respond using data with multiple forms. So be careful with me here;)

 $content_type = ""; //use last know content-type as a trigger $tmp_cnt_file = "tmp/tmpfile"; $xml_response = ""; // this will hold the "usable" curl response $hidx = 0; //header index.. counting the number of different headers received function read_header($cUrl, $string)// this will be called once for every line of each header received { global $content_type, $hidx; $length = strlen($string); if (preg_match('/Content-Type:(.*)/', $string, $match)) { $content_type = $match[1]; $hidx++; } /* should set $content_type to 'application/xop+xml; charset=utf-8; type="text/xml"' for the first and to 'application/zip' for the second response body echo "Header: $string<br />\n"; */ return $length; } function read_body($cUrl, $string) { global $content_header, $xml_response, $tmp_cnt_file, $hidx; $length = strlen($string); if(stripos ( $content_type , "xml") !== false) $xml_response .= $string; elseif(stripos ($content_type, "zip") !== false) { $handle = fopen($tmp_cnt_file."-".$hidx.".zip", "a"); fwrite($handle, $string); fclose($handle); } /* elseif {...} else{...} depending on your needs echo "Received $length bytes<br />\n"; */ return $length; } 

and of course set the correct curlopts

 // Set callback function for header curl_setopt($cUrl, CURLOPT_HEADERFUNCTION, 'read_header'); // Set callback function for body curl_setopt($cUrl, CURLOPT_WRITEFUNCTION, 'read_body'); 

don't forget to NOT save the curl response to the variable due to memory problems, hope all you need is $ xml_response anyway.

 //$response = curl_exec($cUrl); curl_exec($cUrl); 

And to parse the code, you can reference $xml_response and the temporary files you created, starting with tmp/tmpfile-2 in this scenario. Again, I could not verify the code above. So this may not work (but it should imho;))

[EDIT III]

Suppose we want a curl to write all incoming data directly to another (outgoing) stream, in this case a socket connection

I'm not sure how simple it is:

 $fs = fsockopen($host, $port, $errno, $errstr); $cUrl = curl_init('http://example.com/foo'); curl_setopt($cUrl, CURLOPT_FILE, $fs); // redirect output to sockethandle curl_exec($cUrl); curl_close($cUrl); fclose($fs); // close handle 

else we will have to use our well-known recording and title functions with just a little trick

 //first open the socket (before initiating curl) $fs = fsockopen($host, $port, $errno, $errstr); // now for the new callback function function socket_pipe($cUrl, $string) { global $fs; $length = strlen($string); fputs($fs, $string); // add NOTHING to the received line just send it to $fs; that was easy wasn't it? return $length; } // and of course for the CURLOPT part // Set callback function for header curl_setopt($cUrl, CURLOPT_HEADERFUNCTION, 'socket_pipe'); // Set the same callback function for body curl_setopt($cUrl, CURLOPT_WRITEFUNCTION, 'socket_pipe'); // do not forget to fclose($fs); //when we're done 

The fact is that not editing the result and just connecting it to $fs will require that apache listen on a specific port, which is then assigned to you by a script. Or you need to add ONE header line directly after fsockopen

 fputs($fp, "POST $path HTTP/1.0\n"); //where path is your script of course 
+4
source

Sorry, I canโ€™t help much, because you donโ€™t have much code, but I remember that I had a similar problem when I played with curl_setopt parameters.

Have you used CURLOPT_BINARYTRANSFER ?

From the documentation php โ†’ CURLOPT_BINARYTRANSFER โ†’ TRUE to return raw output when using CURLOPT_RETURNTRANSFER.

0
source

just set CURLOPT_RETURNTRANSFER CURLOPT_POST

  $c = curl_init($url); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 1); curl_setopt($c, CURLOPT_TIMEOUT, 1); curl_setopt($c, CURLOPT_POST, 1); curl_setopt($c, CURLOPT_POSTFIELDS, array()); $rst_str = curl_exec($c); curl_close($c); 
0
source

You can reassemble your binary data by doing something like this, I hope this helps.

 $file_array = explode("\n\r", $file, 2); $header_array = explode("\n", $file_array[0]); foreach($header_array as $header_value) { $header_pieces = explode(':', $header_value); if(count($header_pieces) == 2) { $headers[$header_pieces[0]] = trim($header_pieces[1]); } } header('Content-type: ' . $headers['Content-Type']); header('Content-Disposition: ' . $headers['Content-Disposition']); echo substr($file_array[1], 1); 
0
source

If you do not need binary data, have you tried below?

 curl_setopt($c, CURLOPT_NOBODY, true); 
0
source

All Articles