cURL 在某些请求中不发送 POST 数据
我已经被这个问题困扰了几个小时:我正在使用 PHP 和 cURL 编写一种 PHP 代理。几乎一切都工作正常,设置 cookie、处理重定向以及使用 POST 提交表单。
基本上,我正在尝试使用本地代理镜像远程网站。为此,我将每个请求重定向到 http://localhost/resource
到 http://localhost/proxy.php?url=http://remotesite.com/resource
code> 将获取远程网站上的资源。重定向是由 .htaccess 上的 404 错误页面处理的,但我猜使用 mod_rewrite 不会改变事情。
我正在远程服务器上部署的复杂应用程序(最新版本的 WordPress)上测试我的代理。 WordPress 登录工作正常并使用 POST。但是,我发现一个页面无法更新表单,并且所有 POST 数据根本不会发送到服务器。
以下是我在环回接口上侦听wireshark时看到的情况:
POST /proxy/wp-admin/media.php?attachment_id=691&action=edit HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.23) Gecko/20110921 Ubuntu/10.04 (lucid) Firefox/3.6.23
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://localhost/proxy/wp-admin/media.php?attachment_id=691&action=edit
Cookie: [snip]
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 501
attachments%5B691%5D%5Bmenu_order%5D=0&attachments%5B691%5D%5Bpost_title%5D=fb&attachments%5B691%5D%5Bimage_alt%5D=&attachments%5B691%5D%5Bpost_excerpt%5D=&attachments%5B691%5D%5Bpost_content%5D=foobar&attachments%5B691%5D%5Burl%5D=http%3A%2F%2Flocalhost%2Fproxy%2Fwp-content%2Fuploads%2F2009%2F04%2Ffb.gif&save=Aggiorna+media&post_id=&attachment_id=691&action=editattachment&_wp_original_http_referer=&_wpnonce=02caf30462&_wp_http_referer=%2Fwp-admin%2Fmedia.php%3Fattachment_id%3D691%26action%3Dedit
HTTP/1.1 200 OK
Date: Wed, 19 Oct 2011 16:18:56 GMT
Server: Apache/2.2.14 (Ubuntu)
X-Powered-By: PHP/5.3.2-1ubuntu4.10
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 5441
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
[content]
同时,如果在连接到互联网的接口上侦听,我看到的是:
POST /wp-admin/media.php?attachment_id=691&action=edit HTTP/1.1
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.23) Gecko/20110921 Ubuntu/10.04 (lucid) Firefox/3.6.23
Host: www.remotesite.com
Accept: */*
Referer: http://www.remotesite.com/wp-admin/media.php?attachment_id=691&action=edit
Cookie: [snip]
X-Forwarded-For: 127.0.0.1
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Wed, 19 Oct 2011 16:25:13 GMT
Server: LiteSpeed
Connection: close
X-Powered-By: PHP/5.2.17
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Last-Modified: Wed, 19 Oct 2011 16:25:13 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=UTF-8
[content]
如您所见,我的代理没有将发布数据传输到远程服务器。 我预计问题与 POSTDATA 的编码有关,因为本例中的 POST 变量位于数组中(附件[691][menu_order]=0;附件[691][post_content]=foobar 等等... )。
我按照类似帖子的建议尝试了一些更改,但根本没有设法改变脚本的行为。所有这一切都是因为显然第一个(本地)POST 将数据发送到本地主机,但 cURL 无法获取 POST 数据(实际上,下面代码中的 file_get_contents("php://input") 读取了 0 个字节)。
我在这里粘贴我的部分代码希望有人可以帮助我:
$ch = curl_init( $url );
$headers = array();
if ( isset($_SERVER['CONTENT_TYPE']) ) {
// commenting this out or changing to multipart/form-data does not change anything
array_push($headers, "Content-Type: ".$_SERVER['CONTENT_TYPE'] );
}
if ( count($headers) > 0 ) {
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
}
$postdata = file_get_contents("php://input"); //this turns out to be empty - and so is $_POST
//REQUEST METHOD: since pages are redirected from a 404 error page, we have to handle
//a redirect, so the real method is specified in REDIRECT_REQUEST_METHOD
if ( isset($_SERVER['REDIRECT_REQUEST_METHOD']) && isset($postdata) ){
if ($_SERVER['REDIRECT_REQUEST_METHOD'] == 'POST'){
curl_setopt( $ch, CURLOPT_POST, true );
}
}
else{
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' ){
curl_setopt( $ch, CURLOPT_POST, true );
}
}
if ( isset($_SERVER['CONTENT_LENGTH'] ) && $_SERVER['CONTENT_LENGTH'] > 0 ) {
curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
}
//set cookies
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookietofwd');
curl_setopt($ch, CURLOPT_COOKIEFILE,'/tmp/cookietofwd');
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_HEADER, true );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
$out=curl_exec( $ch );
[...]
I've been stuck on this problem for several hours: I'm using PHP and cURL to write a sort of PHP proxy. Almost everything works fine, setting cookies, handling redirects, and submitting forms using POST.
Basically, I'm trying to mirror a remote website with my local proxy. To do so, I redirect every request to http://localhost/resource
to http://localhost/proxy.php?url=http://remotesite.com/resource
that will fetch the resource on the remote website. The redirect is handled by a 404 error page on .htaccess but I guess that using mod_rewrite would not change things.
I'm testing my proxy on a complex application (the latest version of WordPress) deployed on a remote server. The WordPress login works fine and uses POST. However, I found a page where updating a form does not work, and for which all the POST data is not sent at all to the server.
Here is what I see with wireshark listening on the loopback interface:
POST /proxy/wp-admin/media.php?attachment_id=691&action=edit HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.23) Gecko/20110921 Ubuntu/10.04 (lucid) Firefox/3.6.23
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://localhost/proxy/wp-admin/media.php?attachment_id=691&action=edit
Cookie: [snip]
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
Content-Length: 501
attachments%5B691%5D%5Bmenu_order%5D=0&attachments%5B691%5D%5Bpost_title%5D=fb&attachments%5B691%5D%5Bimage_alt%5D=&attachments%5B691%5D%5Bpost_excerpt%5D=&attachments%5B691%5D%5Bpost_content%5D=foobar&attachments%5B691%5D%5Burl%5D=http%3A%2F%2Flocalhost%2Fproxy%2Fwp-content%2Fuploads%2F2009%2F04%2Ffb.gif&save=Aggiorna+media&post_id=&attachment_id=691&action=editattachment&_wp_original_http_referer=&_wpnonce=02caf30462&_wp_http_referer=%2Fwp-admin%2Fmedia.php%3Fattachment_id%3D691%26action%3Dedit
HTTP/1.1 200 OK
Date: Wed, 19 Oct 2011 16:18:56 GMT
Server: Apache/2.2.14 (Ubuntu)
X-Powered-By: PHP/5.3.2-1ubuntu4.10
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 5441
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
[content]
While, what I see if listening on the interface connected to the internet is:
POST /wp-admin/media.php?attachment_id=691&action=edit HTTP/1.1
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.23) Gecko/20110921 Ubuntu/10.04 (lucid) Firefox/3.6.23
Host: www.remotesite.com
Accept: */*
Referer: http://www.remotesite.com/wp-admin/media.php?attachment_id=691&action=edit
Cookie: [snip]
X-Forwarded-For: 127.0.0.1
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Wed, 19 Oct 2011 16:25:13 GMT
Server: LiteSpeed
Connection: close
X-Powered-By: PHP/5.2.17
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Last-Modified: Wed, 19 Oct 2011 16:25:13 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Content-Type: text/html; charset=UTF-8
[content]
As you see my proxy is not transmitting the post data to the remote server.
I expect the problem to be related to the encoding of the POSTDATA, as POST variables in this case are in an array (attachments[691][menu_order]=0; attachments[691][post_content]=foobar and so on...).
I tried several changes as suggested by similar posts but haven't managed to change the behavior of the script at all. All this because apparently the first (local) POST sends the data to localhost, but cURL is unable to fetch the POST data (indeed, file_get_contents("php://input") in the code below reads 0 bytes).
I paste here part of my code hoping somebody can help me:
$ch = curl_init( $url );
$headers = array();
if ( isset($_SERVER['CONTENT_TYPE']) ) {
// commenting this out or changing to multipart/form-data does not change anything
array_push($headers, "Content-Type: ".$_SERVER['CONTENT_TYPE'] );
}
if ( count($headers) > 0 ) {
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
}
$postdata = file_get_contents("php://input"); //this turns out to be empty - and so is $_POST
//REQUEST METHOD: since pages are redirected from a 404 error page, we have to handle
//a redirect, so the real method is specified in REDIRECT_REQUEST_METHOD
if ( isset($_SERVER['REDIRECT_REQUEST_METHOD']) && isset($postdata) ){
if ($_SERVER['REDIRECT_REQUEST_METHOD'] == 'POST'){
curl_setopt( $ch, CURLOPT_POST, true );
}
}
else{
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST' ){
curl_setopt( $ch, CURLOPT_POST, true );
}
}
if ( isset($_SERVER['CONTENT_LENGTH'] ) && $_SERVER['CONTENT_LENGTH'] > 0 ) {
curl_setopt( $ch, CURLOPT_POSTFIELDS, $postdata );
}
//set cookies
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookietofwd');
curl_setopt($ch, CURLOPT_COOKIEFILE,'/tmp/cookietofwd');
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_HEADER, true );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
$out=curl_exec( $ch );
[...]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为什么不从 $_POST 获取 POST 数据? application/x-www-form-urlencoded 标头似乎是 AJAX 请求而不是常规 POST,我不确定 php://input 是如何处理它的。
你可以这样说:
你想要在 PHP 中使用这个有什么具体原因吗?为什么不直接使用 nginx 呢? (http://nginx.org/en/)
它可能会做得更好(而且更快)。
Why don't you get your POST data from $_POST? The application/x-www-form-urlencoded header appears to be an AJAX request instead of a regular POST, which I am not sure how it is handled by php://input.
You could so something like:
Is there a specific reason why you want this in PHP? Why don't you just use nginx? (http://nginx.org/en/)
It will probably do a better job (and faster).