Я застрял в этой проблеме на несколько часов: я использую PHP и cURL для написания своего рода PHP-прокси. Почти все работает нормально, настройка файлов cookie, обработка перенаправлений и отправка форм с помощью POST.
По сути, я пытаюсь отразить удаленный веб-сайт с помощью моего локального прокси. Для этого я перенаправляю каждый запрос на http://localhost/resource
на http://localhost/proxy.php?url=http://remotesite.com/resource
, который будет извлекать ресурс на удаленном веб-сайте. Перенаправление обрабатывается страницей с ошибкой 404 в .htaccess, но я думаю, что использование 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 в этом случае находятся в массиве (attachments [691] [menu_order] = 0; attachments [691] [post_content] = foobar и т. Д.) ).
Я попробовал несколько изменений в соответствии с предложениями аналогичных постов, но не смог изменить поведение скрипта вообще. Все это потому, что, по-видимому, первый (локальный) POST отправляет данные на localhost, но 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 );
[...]