[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: [Решено]: Мусор при чтении страниц через fsockopen
vmunt
Здравствуйте всем!

Читаю содержимое странички через fsockopen()/fgets()/fread():
<?php
$host = 'www.php.net';
$uri = '/manual/ru/function.fsockopen.php';
$request =
"GET ".$uri." HTTP/1.1\r\n".
"Host: ".$host."\r\n".
"Connection: close\r\n".
"\r\n";

$socket = fsockopen($host, 80, $errno, $error);
if ($socket) {
fwrite($socket, $request); // Отправляем запрос
// Считываем возврат. Любой вариант считывания выдаёт одинаковый результат с одинаковыми проблемами

$response=''; while (!feof($socket)) $response .= fgets($socket);
// $response=''; while (!feof($socket)) $response .= fread($socket, 8192);
// $response = stream_get_contents($socket);

fclose($socket);
echo $response; // Результат на экран
file_put_contents('./logs/'.$host.'.response.luna.html', $response); // Результат в файл
}
?>
В выводе мусор вида:
Строки 13-16:
Content-Type: text/html;charset=utf-8

1517
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
Строки 135-138:
<div id="layout_2">
fd8

<div id="leftbar">
Строки 197-203:
    <option value="en/function.fsockopen.php">English</option>

4f
<option value="pt_BR/function.fsockopen.php">Brazilian Portuguese</option>

fb6
<option value="zh/function.fsockopen.php">Chinese (Simplified)</option>
Строки 194-196 (мусор вставлен в разрыв тега):
     <s
1a5
pan class
="term"><i><tt class="parameter">errno</tt></i></span>
Строки 306-309 (мусор вставлен в середину абзаца):
       indication th
fc1
at the error occurred before the
ну и так далее. В конце обязательно присутствует
0

Результат стабилен. Проверено при запуске с хостингов WinXP / Win2008 x64 и на FreeBSD 8.2 amd64. PHP версий 5.2 (5.2.12 и 5.2.17) и 5.3.8. Пробовал штук пять других больших страниц. Мусор в других местах, но тоже присутствует. Тестовые странички в одну строку считывает без мусора.

Никто не пробовал бороться с этой проблемой (уж больно не хочется использовать cURL, в моей задаче не так элегантно всё будет получаться)? PHP.ini (большинство настроек по умолчанию) ниже:
"PHP.ini"
[PHP]
engine = On
short_open_tag = Off
asp_tags = Off
precision = 14
y2k_compliance = On
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 17
allow_call_time_pass_reference = Off
safe_mode = Off
safe_mode_gid = Off
safe_mode_include_dir =
safe_mode_exec_dir =
safe_mode_allowed_env_vars = PHP_
safe_mode_protected_env_vars = LD_LIBRARY_PATH
disable_functions =
disable_classes =
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL
display_errors = On
display_startup_errors = Off
log_errors =On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = Off
error_log = D:/WWW/logs/php.errors.log
variables_order = "GPCS"
request_order = "GP"
register_globals = Off
register_long_arrays = Off
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 32M
magic_quotes_gpc = Off
magic_quotes_runtime = Off
magic_quotes_sybase = Off
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
upload_tmp_dir="D:\WWW\temp"
session.save_path="D:\WWW\temp"
error_log="D:\WWW\logs\php.errors.log"
extension_dir="C:\Program Files (x86)\PHP\ext"
[Date]
date.timezone = 'Asia/Yekaterinburg';
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Syslog]
define_syslog_variables = Off
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[SQL]
sql.safe_mode = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQL]
mysql.allow_local_infile = On
mysql.allow_persistent = On
mysql.cache_size = 2000
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = 60
mysql.trace_mode = Off
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
[PostgresSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Sybase-CT]
sybct.allow_persistent = On
sybct.max_persistent = -1
sybct.max_links = -1
sybct.min_server_severity = 10
sybct.min_client_severity = 10
[bcmath]
bcmath.scale = 0
[Session]
session.save_handler = files
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.bug_compat_42 = Off
session.bug_compat_warn = Off
session.referer_check =
session.entropy_length = 0
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry"
[MSSQL]
mssql.allow_persistent = On
mssql.max_persistent = -1
mssql.max_links = -1
mssql.min_error_severity = 10
mssql.min_message_severity = 10
mssql.compatability_mode = Off
mssql.secure_connection = Off
[mbstring]
mbstring.language = Russian
mbstring.internal_encoding = UTF-8
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[ldap]
ldap.max_links = -1
[PHP_BZ2]
extension=php_bz2.dll
[PHP_CURL]
extension=php_curl.dll
[PHP_GD2]
extension=php_gd2.dll
[PHP_GETTEXT]
extension=php_gettext.dll
[PHP_GMP]
extension=php_gmp.dll
[PHP_IMAP]
extension=php_imap.dll
[PHP_MBSTRING]
extension=php_mbstring.dll
[PHP_MYSQL]
extension=php_mysql.dll
[PHP_MYSQLI]
extension=php_mysqli.dll
[PHP_MSSQL]
extension=php_sqlsrv_53_ts_vc9.dll
[PHP_PDO_MSSQL]
extension=php_pdo_sqlsrv_53_ts_vc9.dll
[PHP_OPENSSL]
extension=php_openssl.dll
[PHP_PDO_MYSQL]
extension=php_pdo_mysql.dll
[PHP_PDO_ODBC]
extension=php_pdo_odbc.dll
[PHP_PDO_SQLITE]
extension=php_pdo_sqlite.dll
[PHP_PGSQL]
extension=php_pgsql.dll
[PHP_SOAP]
extension=php_soap.dll
[PHP_SOCKETS]
extension=php_sockets.dll
[PHP_SQLITE3]
extension=php_sqlite3.dll
[PHP_TIDY]
extension=php_tidy.dll
[PHP_XMLRPC]
extension=php_xmlrpc.dll
[PHP_EXIF]
extension=php_exif.dll

Заранее всем спасибо!

P.S.: При ответе (если не трудно) отпишитесь, у Вас проблема повторилась или нет?

Решение проблемы
При отправке в заголовке запроса HTTP/1.1 некоторые серверы возвращают ответ в режиме Transfer-Encoding: chunked (кодирование ответа: цепочкой, подробнее тут (глава 4.4). При этом веб-сервер передаёт заголовки, и потом сразу (без дополнительной пустой строки "\r\n") начинает передавать блоки данных вида "\r\n".шестнадцатиричная длина следующего блока."\r\n".данные следующего блока. Последний блок данных всегда имеет вид "\r\n0\r\n".

Таким образом при использовании низкоуровневой функции fsockopen() нужно будет определять наличие режима цепочной передачи данных и потом пересобрать принятый HTTP-ответ без промежуточных значений длины переданных кусков.



Спустя 14 минут, 23 секунды (29.02.2012 - 10:01) Игорь_Vasinsky написал(а):
а если через file_get_contents() попробывать? или курлом?

Спустя 1 час, 28 минут, 3 секунды (29.02.2012 - 11:29) walerus написал(а):
function get($url)
{
$hostData = parse_url($url);
if (!isset($hostData["port"])) $hostData["port"] = 80;
if (!isset($hostData["path"])) $hostData["path"] = "/";
if($ch = fsockopen($hostData["host"], $hostData["port"], $errno, $errstr, 10))
{
fputs($ch, "GET ".$hostData["path"]." HTTP/1.0\r\nHost: ".$hostData["host"]."\r\n\r\n");
$result = "";
while (!feof($ch))
$result .= fgets($ch, 1024);
fclose($ch);
$result = explode("\r\n\r\n", $result, 2);
$headers = array();
$tmp = explode("\r\n", $result[0]);
foreach($tmp as $line)
{
$tmp = explode(":", $line, 2);
if (array_key_exists("1", $tmp))
$headers[strtolower($tmp[0])] = $tmp[1];
}
return array("data" => trim($result[1]), "headers" => $headers);
}
}



$url = 'http://www.php.net/manual/ru/function.fsockopen.php';

print_r( get( $url ) );

попробуй функцию.

Спустя 52 минуты, 59 секунд (29.02.2012 - 12:22) vmunt написал(а):
Спасибо за ответы, уважаемые!

Понимания стало чуть больше.

Если в заголовке запроса GET стоит HTTP/1.1, то HTTP-ответ получается косячный. Если поставить HTTP/1.0, то HTTP-ответ принимается правильно. Причём в ответе от сайта в обоих случаях стоит HTTP/1.1. То есть получается, что каким-то образом содержимое заголовка запроса, отправляемого через fsockopen()/fwrite(), меняет алгоритм работы PHP при приёме сообщения? Или всё-таки сервер отправляет мне ответ по протоколу 1.0, хотя в заголовке пишет 1.1? Озадачился...

Так что на текущий момент вопрос можно уже переформулировать так: можно ли заставить fsockopen() / fread() работать правильно при указании в запросе протокола HTTP/1.1 (браузеры все отправляют сайтам 1.1, поэтому отправлять 1.0 совсем неправильным будет). Фоном ещё и сам порою интернет на эту тему...

P.S.: file_get_contents() и cURL работают правильно. Это я уже проверил. Но file_get_contents() не умеет передавать мне куки, а при использовании cURL код получается более громоздкий и некрасивый (разобрать лёгкий текстовый запрос на его составные части, настроить curl кучей функций, запустить отправку curl-ом, потом ответ собрать снова из кучи curl-овских полей и в результате вернуть элегантный однострочный ответ (одна строковая переменная, мне удобна именно она). Жуть!)

Добавлено: Мой код никто не пробовал? Может, у кого он и при HTTP/1.1 работает? Тогда по идее можно будет просто порыть отличия в конфигах/версиях PHP/.htaccess-а...

Добавлено 2: Тут это уже обсуждалось. Видимо, эти вставыши -- шестнадцатиричная длина предыдущего переданного куска. Как заставить PHP выкусывать их (функции fgets/fread/stream_get_contents не знают, какого размера куски веб-сервер передавал в буфер PHP), пока непонятно...

Добавлено 3: Разобрался. Сейчас поправлю заголовок темы алгоритмом, что да как...

Спустя 1 час, 21 минута, 23 секунды (29.02.2012 - 13:44) killer8080 написал(а):
Цитата (vmunt @ 29.02.2012 - 11:22)
То есть получается, что каким-то образом содержимое заголовка запроса, отправляемого через fsockopen()/fwrite(), меняет алгоритм работы PHP при приёме сообщения?

PHP тут не причем, ответ вы получаете от вебсервера.
Цитата (vmunt @ 29.02.2012 - 11:22)
Или всё-таки сервер отправляет мне ответ по протоколу 1.0, хотя в заголовке пишет 1.1?

именно так
Цитата (vmunt @ 29.02.2012 - 11:22)
Это я уже проверил. Но file_get_contents() не умеет передавать мне куки

не правда, умеет.
Цитата (vmunt @ 29.02.2012 - 11:22)
можно ли заставить fsockopen() / fread() работать правильно при указании в запросе протокола HTTP/1.1

он и так работает правильно, что запросили, то и получили. Не хотите возится с чанками, делайте запросы в версии 1.0



Спустя 20 минут, 51 секунда killer8080 написал(а):
$url = 'http://www.php.net/manual/ru/function.fsockopen.php';
$opts['http']['header'] = "Cookie: cookiename=cookievalue; second=second_cookie_value\r\n";
$context = stream_context_create($opts);
echo '<pre>'.htmlspecialchars(file_get_contents($url, false, $context)).'</pre>';

Спустя 7 часов, 23 минуты, 53 секунды (29.02.2012 - 21:08) vmunt написал(а):
Не в плане прений, а токмо ради уточнения позиции:
Цитата (killer8080 @ 29.02.2012 - 15:44)
Цитата (vmunt @ 29.02.2012 - 11:22)
Это я уже проверил. Но file_get_contents() не умеет передавать мне куки
не правда, умеет.
Вы, видимо, чуток невнимательно прочитали, уважаемый. Я писал не об отправке кукисов на сервер (что, собственно, Ваш пример и демонстрирует), а о приёме их от сервера. Ибо не вижу смысла передавать куки на сервер без возможности перед этим их от этого сервера принять...
Цитата (killer8080 @ 29.02.2012 - 15:44)
Цитата (vmunt @ 29.02.2012 - 11:22)
можно ли заставить fsockopen() / fread() работать правильно при указании в запросе протокола HTTP/1.1
он и так работает правильно, что запросили, то и получили. Не хотите возится с чанками, делайте запросы в версии 1.0
1) я вообще-то нигде не писал, что я не хочу возиться с разбором этого способа кодирования. Поэтому обвинение меня в каких-то явно не моих желаниях или нежеланиях несколько неожиданно и немножко дискредитирует пишущего. Не находите? К тому же я открытым текстом указал ранее, что не считаю отправку запроса в версии 1.0 правильным решением. Грустно...
2) И ещё более того: я к моменту написания Вашего сообщения уже набросал определение этого режима и алгоритм устранения отметок длины из HTTP-ответа. Завтра в рабочее время допишу, отлажу, и, думаю, будет всё работать просто шоколадно.

Спасибо всем отвечавшим за наводку на проблему. Постараюсь также в свою очередь в меру сил и возможностей помогать чем могу...

Спустя 48 минут, 5 секунд (29.02.2012 - 21:56) killer8080 написал(а):
Цитата (vmunt @ 29.02.2012 - 20:08)
Вы, видимо, чуток невнимательно прочитали, уважаемый. Я писал не об отправке кукисов на сервер (что, собственно, Ваш пример и демонстрирует), а о приёме их от сервера. Ибо не вижу смысла передавать куки на сервер без возможности перед этим их от этого сервера принять...

Пардон, значит неправильно понял ваш вопрос. А с чего вы взяли что с помощью file_get_contents() нельзя принять заголовки сервера?

$url = 'http://www.php.net/manual/ru/function.fsockopen.php';
$content = file_get_contents($url);
echo '<pre>'.print_r($http_response_header, 1).'</pre>';
echo '<pre>'.htmlspecialchars($content).'</pre>';


Цитата (vmunt @ 29.02.2012 - 20:08)
Поэтому обвинение меня в каких-то явно не моих желаниях или нежеланиях несколько неожиданно и немножко дискредитирует пишущего. Не находите?

Ну уж извините если задел ваше самолюбие, я хотел помочь :)
Цитата (vmunt @ 29.02.2012 - 20:08)
К тому же я открытым текстом указал ранее, что не считаю отправку запроса в версии 1.0 правильным решением.

Вы собираетесь посылать несколько запросов через одно соединение? Если нет, то зачем вам нужен протокол версии 1.1, если его преимущества все равно не будете использовать?

P.S. кстати через контекст можно заставить file_get_contents отправлять запрос в HTTP/1.1, правда разбирать фрагменты автоматом, php может только с версии 5.3.0

Спустя 1 час, 30 минут, 25 секунд (29.02.2012 - 23:26) walerus написал(а):
Офф Топ:
Как по мне, так Curl мне более приятен чем сокеты, хотя и не пользовался ими плотно...

Спустя 1 день, 23 часа, 58 минут, 9 секунд (2.03.2012 - 23:24) vmunt написал(а):
Цитата (killer8080;Дата 29.02.2012 - 23:56)
А с чего вы взяли что с помощью file_get_contents() нельзя принять заголовки сервера?
$url = 'http://www.php.net/manual/ru/function.fsockopen.php';
$content = file_get_contents($url);
echo '<pre>'.print_r($http_response_header, 1).'</pre>';
echo '<pre>'.htmlspecialchars($content).'</pre>';
Оба на! Спасибо! Век живи — век учись!

Цитата (killer8080;Дата 29.02.2012 - 23:56)
Ну уж извините если задел ваше самолюбие, я хотел помочь :)
Кхм... При чём тут моё самолюбие?! Я тоже хотел помочь. Ну да ладно, проехали...

Цитата (killer8080;Дата 29.02.2012 - 23:56)
Вы собираетесь посылать несколько запросов через одно соединение? Если нет, то зачем вам нужен протокол версии 1.1, если его преимущества все равно не будете использовать?
Ну, тут на самом деле всё просто. Некоторые сайты (как бы это помягче-то?) не очень благожелательно относятся к тому, что какие-то автоматические программные средства путешествуют по страничками на этих сайтах. А отправлять запрос в формате HTTP/1.0, в то время как все (даже очень древние браузеры) отправляют запросы с поддержкой HTTP/1.1 — это просто сразу заранее поднять две руки вверх и кричать: «Я тупой программный робот, который даже не умеет принимать ответы по протоколу HTTP/1.1»...

А по поводу нескольких запросов через одно соединение: тут Вы в точку! Очень хочу попробовать эту возможность. Ибо сайт, по которому сейчас стоит задание, поддерживает Connection: Keep-alive...

Ну и если кому вдруг понадобится, запрос через fsockopen() (сопутствующие части кода не убирал, просто закомментировал. Вдруг кому-нибудь идеи пригодятся? Альтернативные варианты кода тоже закомментированы, но любая веточка работает. Проверено)
Функция request()
// -----------------------------------------------------------
// Функция отправляет сформированный запрос указанному хосту
// В config['request_headers'] заносятся разобранные заголовки
// В $host принимается собственно хост и порт при желании
// -----------------------------------------------------------

function request($host, $request)
{
global $config;

$url_parts = parse_url($host);
if (!isset($url_parts['host']))
{
$url_parts['host'] = $url_parts['path'];
unset($url_parts['path']);
}
if (!isset($url_parts['port']))
$url_parts['port'] = 80;

if (($socket = fsockopen($url_parts['host'], $url_parts['port'], $errNumber, $errString, (isset($config['request_timeout'])?$config['request_timeout']:30))) == false)
return str2www('ОШИБКА: Не могу достучаться к '.$url_parts['host'].', ошибка: '.$errNumber.' ('.$errString.')'); // !!! Заменить на $message
fwrite($socket, $request);
// $response=''; while (!feof($socket)) $response .= fgets($socket);
// $response=''; while (!feof($socket)) $response .= fread($socket, 8192);

$response = stream_get_contents($socket);
fclose($socket);

// Проверяем, если у нас HTTP-передача Transfer-Encoding: chunked, то вырезаем длины фрагментов из полученного потока
$head_text= substr($response,0,strpos($response,"\r\n\r\n")+2); // Копируем только строчки заголовков с финальными окончаниями строк
$head_arr = parse_headers_area($head_text);
$config['request_headers'] = $head_arr; // Вдруг когда ещё понадобится?
if (isset($head_arr['transfer-encoding']) && (strtolower($head_arr['transfer-encoding'])=='chunked'))
{ // Имеем цепочную передачу. Убираем куски \r\nXXX\r\n
$buffer='';
$pos=strlen($head_text);
while (($size = hexdec(substr($response,$pos+2,($pnext=strpos($response, "\r\n", $pos+2)+2)-$pos-4))) != 0)
{
$buffer.=substr($response, $pnext, $size);
$pos = $pnext+$size;
}
$response = $head_text."\r\n".$buffer;
}
// Тут пока непонятно, при цепочной передаче данных gzip-ом упаковываются отдельные цепочки, или цепочка может быть только одна?
if (isset($head_arr['content-encoding']) && (strtolower($head_arr['content-encoding'])=='gzip'))
{
$buffer = substr($response, strlen($head_text)+2);
// $response = $head_text."\r\n".gzdecode($buffer);
$response = $head_text."\r\n".gzinflate(substr($buffer,10));
}
return $response;
} // request()
P.S.: У меня в редакторе табуляции настроены на 2 пробела, поэтому если на этом сайте большой отступ в табуляциях будет раздражать, только скажите, в будущих фрагментах кода буду заменять на двойные-тройные пробелы. Нет проблем
Дополнительная функция parse_headers_area()
// -----------------------------------------------------------------------------
// Функция преобразует переданную строку заголовков в ассоциативный массив
// Первый элемент всегда 0 и равен или методу запроса, или коду возврата
// При $uc==true ключи массива преобразуются в верхний регистр, иначе - в нижний
// -----------------------------------------------------------------------------

function parse_headers_area($http, $uc=false)
{
global $config;

if (($pos = strpos($http, "\r\n\r\n")) != 0)
$http = substr($http, 0, $pos+2);

$head_rows = explode("\r\n", $http); // Разрезали на строчки
$row = 0;
$headers = array();
foreach ($head_rows as $head)
{
if ($row++ == 0)
$headers[0] = $head; // Первый параметр - статус. 200 OK, 304 Moved Permanently, ну и так далее
else
{
if (strlen($head) > 0)
{
$key = trim(substr($head, 0, strpos($head, ':')));
$val = trim(substr($head, strpos($head, ':')+1));
$key = ($uc?strtoupper($key):strtolower($key));
if (isset($headers[$key])) // Один заголовок с таким же именем уже был. Возможно, это ещё одни Cookies
{
echo2log('Повторное вхождение заголовка "'.$head.'". Предыдущее значение="'.$headers[$key].'"', LOG_MSG_INFO); // !!! Заменить на $message[]
$headers[$key] .= '; '.$val; // Добавляем новое значение к предыдущему (обычно cookie, которые разделяются запятыми)
}
else
{
if (isset($config['known_headers']))
{
if (!in_array(strtolower($key), $config['known_headers']))
echo2log('Непривычный заголовок: '.$head, LOG_MSG_INFO);
else if (isset($config['known_header_values'][strtolower($key)]) && !in_array(strtolower($val), $config['known_header_values'][strtolower($key)]))
echo2log('В заголовке "'.$key.'" встретилась неизвестная опция "'.$val.'"', LOG_MSG_INFO);
}
$headers[$key] = $val;
}
}
// if (strlen($head) > 0)
} // Вторая и последующие строки заголовков
} // foreach ($head_row)
return $headers;
} // parse_headers_area()

Тестовый примерчик
$url = 'http://tune.yandex.ru/region/?retpath='.urlencode('http://market.yandex.ru/');
$url_parts = parse_url($url);
$request =
"GET ".$url_parts['path']." HTTP/1.1\r\n".
"Host: ".$url_parts['host']."\r\n".
"User-Agent: ".$user_agent."\r\n".
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n".
"Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3\r\n".
"Accept-Encoding: gzip, deflate\r\n".
"Connection: Close\r\n".
"Referer: http://market.yandex.ru/\r\n".
"\r\n";
$page = request($url_parts['host'], $request);
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.