Home > Article > Backend Development > PHP simulates post request to send files_PHP tutorial
Due to the needs of the project, the local server needs to receive the data and then forward the data to another server, so a simulated post request is used to send the data. Of course, the data also includes file streams.
curl is one of the more commonly used methods in PHP. The general code is as follows:
$params1 = test; $params2 = @.$absolute_path;//如果是文件 则参数为@+绝对路径 $post_data = array( 'params1' => $params1, 'params2' => $params2, ); function postData($url, $data){ $ch = curl_init(); $timeout = 300; curl_setopt($ch, CURLOPT_URL, $url); //请求地址 //curl_setopt($ch, CURLOPT_REFERER, $ip);//构造来路 curl_setopt($ch, CURLOPT_POST, true); //post请求 curl_setopt($ch, CURLOPT_BINARYTRANSFER,true);//二进制流 curl_setopt($ch, CURLOPT_POSTFIELDS, $data); //数据 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //当CURLOPT_RETURNTRANSFER设置为1时 $head 有请求的返回值 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); //设置请求超时时间 $handles = curl_exec($ch); curl_close($ch); return $handles; }The other party is a java server. I only know the interface, but I don't know how the other party handles file reception. The above method is successful in the win7 wamp environment, but putting the code on the centOS Nginx server fails. The returned message is that the file reception failed. After packet capture analysis, it was found that the format of the packets delivered by win7 wamp and the http packets delivered by centos nginx were different. Under normal circumstances, curl sets the content_type to multipart/form-data by default. On my machine, this is the case under win7 wamp, but under centos nginx, it is application/x-www-form-urlencoded. Of course, this may also be a server configuration problem, but I don't know where the problem is. Then I checked the PHP version. It was also PHP5.3.X, but there were slight differences. It does not rule out that it is a problem with the PHP version. Then add the code:
$header = array( 'Content-Type: multipart/form-data', ); curl_setopt( $ch, CURLOPT_HTTPHEADER, $header);Set the header, but it is still invalid under centos. It's really a scam that I can't change the content-type.
Later, with the help of the technical director, I read a link on the PHP official website http://php.net/manual/en/class.curlfile.php, and followed the official website’s practices to post requests under win wamp and centos nginx. All worked. After reading the code carefully, I found that the method is to completely write the body part of the http request instead of using the part generated by curl itself. I have to admire it. The code is released below:
function postData($url, $data = array(), $data1 = array()){ $header = array( 'Content-Type: multipart/form-data', ); $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $url); curl_setopt( $ch, CURLOPT_HTTPHEADER, $header); curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT,10); curl_setopt ($ch, CURLOPT_BINARYTRANSFER,true); //curl_setopt ($ch, CURLOPT_POSTFIELDS, $data); curl_custom_postfields($ch, $data, $data1); $dxycontent = curl_exec($ch); curl_close($ch); return $dxycontent; } /** * For safe multipart POST request for PHP5.3 ~ PHP 5.4. * * @param resource $ch cURL resource * @param array $assoc name => value * @param array $files name => path * @return bool */ function curl_custom_postfields($ch, array $assoc = array(), array $files = array()) { // invalid characters for name and filename static $disallow = array(, , , ); // build normal parameters foreach ($assoc as $k => $v) { $k = str_replace($disallow, _, $k); $body[] = implode( , array( Content-Disposition: form-data; name={$k}, , filter_var($v), )); } // build file parameters foreach ($files as $k => $v) { switch (true) { case false === $v = realpath(filter_var($v)): case !is_file($v): case !is_readable($v): continue; // or return false, throw new InvalidArgumentException } $data = file_get_contents($v); $v = call_user_func(end, explode(DIRECTORY_SEPARATOR, $v)); $k = str_replace($disallow, _, $k); $v = str_replace($disallow, _, $v); $body[] = implode( , array( Content-Disposition: form-data; name={$k}; filename={$v}, Content-Type: application/octet-stream, , $data, )); } // generate safe boundary do { $boundary = --------------------- . md5(mt_rand() . microtime()); } while (preg_grep(/{$boundary}/, $body)); // add boundary for each parameters array_walk($body, function (&$part) use ($boundary) { $part = --{$boundary} {$part}; }); // add final boundary $body[] = --{$boundary}--; $body[] = ; // set options return @curl_setopt_array($ch, array( CURLOPT_POST => true, CURLOPT_POSTFIELDS => implode( , $body), CURLOPT_HTTPHEADER => array( Expect: 100-continue, Content-Type: multipart/form-data; boundary={$boundary}, // change Content-Type ), )); }Parameter passing has no effect. If it is a file, @ precedes the absolute path. The only difference is to use different arrays to separate file data and ordinary data, and process them differently when simulating the body part of http. The file was finally uploaded successfully.