加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

从cUrl读取PHP中的POST数据

发布时间:2020-12-14 01:53:31 所属栏目:Linux 来源:网络整理
导读:我在 PHP中使用cUrl从一些外部服务请求. 有趣的是,服务器正在响应原始的“multipart / form-data”而不是二进制文件数据. 我的网站使用共享主机,因此PECL HTTP不是一个选项. 有没有办法用PHP解析这些数据? 示例代码: $response = curl_exec($cUrl);/* $res
我在 PHP中使用cUrl从一些外部服务请求.

有趣的是,服务器正在响应原始的“multipart / form-data”而不是二进制文件数据.

我的网站使用共享主机,因此PECL HTTP不是一个选项.

有没有办法用PHP解析这些数据?

示例代码:

$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)

*/

编辑:我尝试将响应传递给localhost HTTP请求,但响应数据可能超过PHP进程中允许的内存大小.扩展内存限制不是很实用,这个操作也大大降低了服务器性能.

如果没有原始问题的替代方法,您可以建议一种方法来处理非常大的POST请求,以及XML解析,就PHP中的流而言.

我知道这很难,请评论.我愿意讨论.

解决方法

如果您需要来自响应的zip文件,我想您可以只编写一个tmp文件来保存curl响应,并将其作为变通方法流式传输:
从来没有试过多部分卷发,但我想它应该工作.

$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

如果您不需要除响应的xml部分之外的任何内容,则可能需要禁用标头

curl_setopt($cUrl,CURLOPT_HEADER,FALSE);

并添加选项以仅接受xml作为响应

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

[编辑]

盲目猜测…
你可以用这些curlopt设置进行测试,看看修改这些设置是否有帮助

$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,$headers);
curl_setopt($cUrl,CURLOPT_POST,1);
curl_setopt($cUrl,CURLOPT_POSTFIELDS,$requestBody);
curl_setopt($cUrl,CURLOPT_RETURNTRANSFER,CURLOPT_FAILONERROR,0 );
curl_setopt($cUrl,CURLOPT_FOLLOWLOCATION,1 );
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);

[编辑II]

这只是一个尝试,如上所述,我不能让我的卷曲页面响应多部分表单数据.所以在这里和我一起温柔;)

$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;
}

当然,设置适当的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');

不要忘记不要因为内存问题而将curl响应保存到变量中,
希望你所需要的只是上面的$xml_response.

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

对于解析代码,您可以参考$xml_response以及在此方案中以tmp / tmpfile-2开头创建的临时文件.同样,我无法以任何方式测试上面的代码.所以这可能不起作用(但它应该是imho;))

[编辑III]

假设我们希望curl将所有传入数据直接写入另一个(传出)流,在本例中为套接字连接

我不确定它是否像这样容易:

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

否则我们将只需要一点技巧就可以使用我们已知的写入和头部函数

//first open the socket (before initiating curl)
$fs = fsockopen($host,$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,'socket_pipe');
// Set the same callback function for body
curl_setopt($cUrl,'socket_pipe');

// do not forget to 
fclose($fs); //when we're done

问题是,不编辑结果并简单地将其连接到$fs将使得apache正在监听某个端口,然后您将脚本分配给该端口.
或者你需要在fsockopen之后直接添加一个标题行

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读