PHP Curl и проблема заголовков - PullRequest
2 голосов
/ 22 декабря 2010

Я уже задавал вопрос по этому вопросу раньше, но снова столкнулся с проблемами и просто не могу решить их. У меня есть внутренний прокси-сервер и контент-сервер. Код на прокси-сервере таков. (Некоторые комментарии могут быть неправильными, но я оставляю здесь, чтобы передать то, что я понимаю):

<?php
session_start();
$data_server_url = "http://my_data_server_url/";
$i_var_prefix="i_var_";

$process_headers_separately=0;
//$process_headers_separately=1;
// WARNING! Has problems with GZIPPED DATA!
// AVOID/REMOVE OPTION ALLTOGETHER
// (Set to 1 if you want to catch received headers
// and send explicit headers to clients)
//-----------------------------------------

// Other important request dependent 'SERVER' variables.
if(isset($_SERVER['HTTPS']))
{ $_POST["${i_var_prefix}_HTTPS"]=$_SERVER['HTTPS']; };

if(isset($_SERVER['REMOTE_ADDR']))
{ $_POST["${i_var_prefix}_REMOTE_ADDR"]=$_SERVER['REMOTE_ADDR']; };

$request_uri="";
if(isset($_SERVER['REQUEST_URI'])) { $request_uri = $_SERVER['REQUEST_URI']; };
$curl_url="${data_server_url}${request_uri}";

$field_array= array(
      'Accept' => 'HTTP_ACCEPT',
      'Accept-Charset' => 'HTTP_ACCEPT_CHARSET',
      'Accept-Encoding' => 'HTTP_ACCEPT_ENCODING',
      'Accept-Language' => 'HTTP_ACCEPT_LANGUAGE',
      'Connection' => 'HTTP_CONNECTION',
      'Host' => 'HTTP_HOST',
      'Referer' => 'HTTP_REFERER',
      'User-Agent' => 'HTTP_USER_AGENT'
      );

$curl_request_headers=array();

foreach ($field_array as $key => $value) {
   if(isset($_SERVER["$value"])) {
      $server_value=$_SERVER["$value"];
      $curl_request_headers[]="$key: $server_value";
   }
};
//------
session_write_close();

//Open connection
$curl_handle = curl_init();
curl_setopt($curl_handle,CURLOPT_COOKIE,session_name()."=".session_id().";");
//Set the url, number of POST vars, POST data
curl_setopt($curl_handle, CURLOPT_URL, $curl_url);
curl_setopt($curl_handle, CURLOPT_POST, count($_POST));
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $_POST);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_AUTOREFERER, TRUE);
curl_setopt($curl_handle, CURLOPT_HEADER, $process_headers_separately);
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $curl_request_headers);
curl_setopt($curl_handle, CURLOPT_ENCODING, "identity");


//Execute post
$result = curl_exec($curl_handle);

//Close connection
curl_close($curl_handle);

if ($process_headers_separately) {
   list($headers,$content)=explode("\r\n\r\n",$result,2);
   foreach (explode("\r\n",$headers) as $hdr) {
      header($hdr);
   }
   echo $content;
} else {
   echo $result;
}    
?>

Проблема 1: При текущем коде, даже если тип содержимого, возвращаемый сервером данных, является text / plain, тип содержимого, видимый клиентом, является text / html. Например, см. http://sarcastic -quotes.com / robots.txt Этот запрос идет в файл выше. Я проверил, что сервер данных фактически возвращает Content-Type как text / plain. Но через прокси клиент видит тип содержимого в заголовках ответа как text / html.

Задача 2: Обратите внимание на использование переменной process_headers_separately. Если я установлю его на 1, браузер попытается загрузить файл gzip вместо отображения содержимого (независимо от того, какой тип содержимого возвращает сервер данных). Таким образом, в этом потоке кода есть логическая ошибка.

Я просто хочу, чтобы приведенный выше код работал как внутренний прокси, который беспрепятственно действует как мост между моим сервером данных и клиентом. Любые мысли были бы оценены, я действительно запутался с тем, как правильно обрабатывать заголовки выше.

С уважением, JP


Я нашел причину проблемы, когда process_headers_separately = 1 (браузер загружает файл вместо отображения). Но это ТАК странно, и я не могу решить это. Проблема: если я раскомментирую строки if(isset($_SERVER['REMOTE_ADDR'])) { $_POST["${i_var_prefix}_REMOTE_ADDR"]=$_SERVER['REMOTE_ADDR']; }; тогда все начинает работать нормально! Странный!

Должна быть какая-то сумасшедшая проблема с пробелами, как предложил Нил.

В любом случае, пытаясь это исправить - я потратил 3 дня (2 раньше и 1 сейчас) из-за этой сумасшедшей ошибки :(. Спасибо Нейлу и Р.Ф. за помощь в этом.

Ответы [ 2 ]

2 голосов
/ 22 декабря 2010

Вы можете использовать следующие строки кода:

//Execute post
$result = curl_exec($curl_handle);
$result_info = curl_getinfo($curl_handle);

А затем:

} else {
    if (isset($result_info['content_type'])) {
        header("Content-Type: {$result_info['content_type']}");
    }
    echo $result;
}

По сути, ваш прокси-сервер возвращает данные.Итак, вот где вы должны будете установить Content-Type.По умолчанию это будет HTML.Но если вы проверите, имеет ли ответ CURL определенный Content-Type, и вам удастся его установить, это сработает!:)

Дайте нам знать, если это работает для вас.


Я понимаю, что вы пытаетесь сделать сейчас.Итак, вот как получить заголовки в ответе вашего прокси:

Если вы установите опцию CURLOPT_HEADER в 1, вы получите заголовки в своем выводе, что позволит вам сделать это:* Я предлагаю использовать функцию http_parse_headers из-за причин, упомянутых в постере первого ответа.Я не уверен, решит ли это вашу проблему с сжатием.Дайте нам знать.

2 голосов
/ 22 декабря 2010

Это все выглядит довольно кошерно. Единственное несоответствие, которое я вижу, состоит в том, что НЕКОТОРЫЕ серверы разделяют только заголовки с \n, а не \r\n. Но это, вероятно, не проблема.

Можете ли вы попробовать записать var_export(explode("\r\n",$headers),true) в файл и посмотреть, что получится?

Перейдите к вопросу о gzip, убедитесь, что после закрытия ?> нет пробельных символов, или, что еще безопаснее, измените echo $result на die($result) Очевидно, что если вы не передадите заголовки ответа CURL, Apache создаст свой собственный, поэтому вам понадобится флаг CURLOPT_HEADER.

CURL распаковывает ответ для вас? Если это так, вам может потребоваться вмешаться с заголовками ответов Content-Encoding и Content-Length.

п.

...