Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Подгрузка нескольких потоков, Скачиваю сайты 
V
    Опции темы
Levsha
Дата 13.6.2007, 19:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Я осуществляю загрузку сразу нескольких страниц других сайтов стандартным методом "fopen-fgets-fclose".  Страниц примерно 15.
Как понимаю, при загрузке страницы чужого сервера, тратится время на:
  • запрос серверу
  • ожидание ответа сервера
  • подбор сервером нужных данных для страницы
  • выдача сервером результата
Но загрузка страниц происходит последовательно, следовательно я трачу лишнее время на второй и третий пункт, т.е. пока чужой сервер думает, я мог бы загружать другие файлы. 
Следовательно даже не зависимо от ширины или скорости канала моего сервера, скорость загрузки сраниц будет доооолгой.

Вопрос, возможно ли организовать загрузку сразу нескольких страниц одновременно?

Примерно, я планирую что бы это выглядело так: 
Код

$url = array("orange.com", "banana.com", "apple.com");
$text = MyDownload ($url);

где $text соответсвенно будет массивом


--------------------
PM   Вверх
sTa1kEr
Дата 13.6.2007, 22:21 (ссылка) |    (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Для создания нескольких потоков существует 2 способа:
1. Для каждого нового потока запускать отдельный интерпретатор PHP. Это наиболее простой, но и наиболее корявый способ. Так же каждый новый псевдопоток будет съедать около 15мб памяти.
Методика этого способа следующая: создаем отдельный скрипт вся работа которого заключается в том, что бы загрузить нужный сайт, URL сайта будет передаватся первым параметром. Затем просто запускаем этот скрипт для каждого URL-а.
Для того что бы не ожидать окончание работы каждого такого скрипта, можно запустить его в фоновом режиме (для этого в конце команды нужно добавить &):
Код

exec("/usr/binphp loadpage.php $url &");

Но такой способ не будет работать в Windows. Другой способ не ждать окончания работы скрипта - это использовать proc-open
Код

$desc = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("file", "/tmp/log", "a")
);

$env = array("URL" => $url);
$p = proc_open('/usr/bin/php loadpage.php', $desc, $pipes, dirname(__FILE__), $env);
// Пока страничка загружается, работаем дальше...

Вот и вся наука.
2. Более правильный способ. Заключается он в использовании Stream Functions совместно с stream_set_blocking() и stream_select(). Включение режима "non-blocking" позволяет не ждать когда поток будет доступен для чтения, а stream_select() позваляет из массива потоков выбирать тот поток(и), который доступен для чтения/записи данных в данный момент. Написал пример работы с потоками:
Код

$timeout = "30";
$urls = array(
   "ya.ru",
   "php.net",
   "zend.com",
   "mail.ru",
   "microsoft.com",
   "google.com",
   "forum.vingrad.ru"
   );

$streams = array();

foreach($urls as $url)
{
   $stream = stream_socket_client(
      "tcp://$url:80",
      $errno, $errstr, $timeout,
      STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
   stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
   $streams[$url] = $stream;
}

$toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос

do
{
   $rStreams = $toRead;
   $wStreams = $toWrite;
   $num = stream_select($rStreams, $wStreams, $e = null, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 

   if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
   {
      if (count($wStreams) > 0)
      {
         foreach($wStreams as $write)
         {
            $url = array_search($write, $streams);
            echo "Sending request for $url\n";
            fwrite($write, "GET http://$url/ HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Monzilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n");
            unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
         }
      }

      if (count($rStreams) > 0)
      {
         foreach($rStreams as $read)
         {
            $url = array_search($read, $streams);
            echo "Getting data for $url\n";
            $f = fopen($url, "w");
            while (!feof($read))
            {
               fputs($f, fgets($read, 128));
            }
            fclose($f);
            unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
         }
      }
   }
} while(count($toRead) > 0); // Читать нечего больше

PM MAIL   Вверх
Vbif
Дата 14.6.2007, 19:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 25.2.2006
Где: Реутов

Репутация: нет
Всего: нет



Жаль что такое чудо будет работать лишь на php5
PM MAIL WWW ICQ   Вверх
Levsha
Дата 15.6.2007, 03:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, благодарю smile , разобрался, под себя переделал.
Выглядит это так:
Код

<?
function MyDownload ($urls) {
    $timeout = "30";
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $stream = stream_socket_client(
          "tcp://$url:80",
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
          stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
         $streams[$url] = $stream;
    }
    $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $num = stream_select($rStreams, $wStreams, $e = null, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                //echo "Sending request for $url\n<br>";
                fwrite($write, "GET http://$url/ HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n");
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                //echo "Getting data for $url\n<br>";
                $result[$url] = "";
                while (!feof($read))
                {
                   $result[$url] = $result[$url].fgets($read, 128);   
                }
               unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}

$urls = array(
   "ya.ru",
   "php.net",
   "zend.com",
   "mail.ru",
   "microsoft.com",
   "google.com",
   "forum.vingrad.ru"
   );

$sait = MyDownload ($urls);

echo $sait ["ya.ru"];
?>


Но есть проблема, при выдаче результата, скрипт также выдает серверные заголовки типа:
Код

HTTP/1.1 200 OK
Connection: close
Content-Type: text/html; charset=windows-1251
Accept-Ranges: bytes
ETag: "-604246012"
Last-Modified: Mon, 04 Jun 2007 13:36:05 GMT
Content-Length: 2110
Date: Fri, 15 Jun 2007 00:08:06 GMT
Server: httpd

Как их убрать? Где именно они добавляются?

Добавлено через 12 минут и 5 секунд
И еще: как скачать ссылку типа http://sait.ru/script/fail.php?name=web&z=0&c=110 ?


--------------------
PM   Вверх
Levsha
Дата 15.6.2007, 08:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Цитата

И еще: как скачать ссылку типа http://sait.ru/script/fail.php?name=web&z=0&c=110 ?

Снимаю вопрос: ссылка должна выглядеть вот так tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110


Я Провел тест на время генерации страницы, вместо предидущих 19.38749сек я получил 8.105515сек smile , экономия десяти секунд smile !!!! sTa1kEr, благодарю за науку!

Осталась только проблема серверных заголовков. Конечно переменную можно просто обработать, и убрать все что идет до первого тега, но имхо это неправильно.


--------------------
PM   Вверх
vasac
Дата 15.6.2007, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



PM WWW   Вверх
sTa1kEr
Дата 15.6.2007, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(Vbif @  14.6.2007,  19:04 Найти цитируемый пост)
Жаль что такое чудо будет работать лишь на php5

На 4ом не будет работать только функция stream_socket_client и соответственно асинхронное соединение. Вместо нее можно использовать обычный fsockopen. Все остальное будет работать и на 4ом PHP.
Цитата(Levsha @  15.6.2007,  08:47 Найти цитируемый пост)
Снимаю вопрос: ссылка должна выглядеть вот так tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110

Вообще-то не совсем так... Коннектится нужно к tcp://sait.ru:80, а в запрос посылать уже полный урл. 
Цитата(Levsha @  15.6.2007,  08:47 Найти цитируемый пост)
Осталась только проблема серверных заголовков. Конечно переменную можно просто обработать, и убрать все что идет до первого тега, но имхо это неправильно. 

Я бы разделил хидеры от контента через explode (вместо строчек 40-44):
Код

$buffer = "";
while (!feof($read))
{
   $buffer .= fgets($read, 1024); 
}
$tmp = explode("\r\n\r\n", $buffer);
/* $header[$url] = */ array_shift($tmp);
$result[$url] = implode("\r\n\r\n", $tmp);


Цитата(vasac @  15.6.2007,  10:22 Найти цитируемый пост)
Мультикурл 

Да, есть такое. Надо будет протестировать. Жаль только, что еще сыроват и плохо задокументирован.
PM MAIL   Вверх
teroni
Дата 15.6.2007, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 15.5.2007
Где: Днепропетровск

Репутация: 1
Всего: 22



Цитата(sTa1kEr @  15.6.2007,  12:04 Найти цитируемый пост)
Да, есть такое. Надо будет протестировать. Жаль только, что еще сыроват и плохо задокументирован

А где-нибудь нормальную документацию не видели?
PM MAIL   Вверх
Levsha
Дата 15.6.2007, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Некоторые сайты говорят в ответ:
Цитата

Your browser sent a request that this server could not understand.


Запрос идет такой
Цитата

GET http://$url HTTP/1.1\r\nAccept: */*\r\nAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n

Может что-то неправильно?

Цитата(sTa1kEr @  15.6.2007,  12:04 Найти цитируемый пост)
Я бы разделил хидеры от контента через explode (вместо строчек 40-44):

Спасибо за еще одну гениальную идею  smile 



--------------------
PM   Вверх
sTa1kEr
Дата 15.6.2007, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(teroni @  15.6.2007,  13:11 Найти цитируемый пост)
А где-нибудь нормальную документацию не видели? 

Нет, не видел, да и наврядтли она будет, пока на амереканских зеркалах php.net нету нормально документации.

Levsha, Да... я когда писал этот пример не учел что хост может выдать ошибку или его вовсе не существует.  Нужно добавить проверку.
Код

       if ($errno > 0)
       {
          echo "Error connectiong to $url. $errstr($errno)";
          continue;
       }

Сразу после stream_socket_client().

Добавлено через 11 минут и 28 секунд
Так же на всякий случай еще можно проверять 3ий параметр stream_select(). Доработанный код:
Код

function MyDownload ($urls, $timeout = 30) {
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $stream = @stream_socket_client(// Если не удается законнектится то выводится Warning, а он нам тут совершенно не нужен
          "tcp://$url:80",
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
       if ($errno > 0)
       {
          //echo "Error connectiong to $url. $errstr($errno)<br>\n";
          // либо еще что-нибудь делаем. Пишем в логи итп...
          continue;
       }
       stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
       $streams[$url] = $stream;
    }
    $toException = $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $eStreams = $toException;
       $num = stream_select($rStreams, $wStreams, $eStreams, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                //echo "Sending request for $url<br>\n";
                fwrite($write, "GET http://$url/ HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n");
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                //echo "Getting data for $url\n<br>";
                $buffer = "";
                while (!feof($read))
                {
                   $buffer .= fgets($read, 1024); 
                }
                $tmp = explode("\r\n\r\n", $buffer);
                /* $header[$url] = */array_shift($tmp);
                $result[$url] = implode("\r\n\r\n", $tmp);
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
          if (count($eStreams) > 0)
          {
             foreach($eStreams as $exception)
             {
                $url = array_search($exception, $streams);
                // echo "Fail getting data for $url.<br>\n";
                // Здесь так же кричим, что сервер вернул не то что ожидали и выкидываем этот поток из стека
             }
             unset($toRead[array_search($exception, $toRead)]);
             unset($toWrite[array_search($exception, $toWrite)]);
             unset($toException[array_search($exception, $toException)]);
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}
$urls = array(
   "localhost",
   "localhost2"
   );
$sites = MyDownload ($urls);
echo count($sites);


PM MAIL   Вверх
Levsha
Дата 15.6.2007, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, но сайт то существует, более того, запрос перепроверял через браузер.
Все должно быть...


--------------------
PM   Вверх
vasac
Дата 15.6.2007, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Цитата

GET http://$url HTTP/1.1

Здесь должен указывать путь к документу на сайте, а не URL
PM WWW   Вверх
sTa1kEr
Дата 15.6.2007, 14:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Levsha, вы в $urls пишете ссылки вида tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110 ?
PM MAIL   Вверх
Levsha
Дата 15.6.2007, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Все, нашел, мой был косяк

Добавлено через 1 минуту и 39 секунд
Цитата(sTa1kEr @  15.6.2007,  14:30 Найти цитируемый пост)
Levsha, вы в $urls пишете ссылки вида tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110 ?

Да. Проглядел Host: $url


--------------------
PM   Вверх
sTa1kEr
Дата 15.6.2007, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Код для *полных* URL-ов. Версия: 0.0.3 Pre Alpha
Код

if (!defined("MD_DEBUG"))
   define("MD_DEBUG", false);

function MyDownload ($urls, $timeout = 30) {
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $host = parse_url($url, PHP_URL_HOST);
       if ($host === null)
       {
          if (MD_DEBUG) echo "Host in '$url' is not correct<br>\n";
          continue;
       }
       $port = parse_url($url, PHP_URL_PORT);
       $stream = @stream_socket_client(// Если не удается законнектится то выводится Warning, а он нам тут совершенно не нужен
          "tcp://$host:".($port === null ? "80" : $port),
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
       if ($errno > 0)
       {
          if (MD_DEBUG) echo "Error connectiong to $url. $errstr($errno)<br>\n";
          // либо еще что-нибудь делаем. Пишем в логи итп...
          continue;
       }
       stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
       $streams[$url] = $stream;
    }
    $toException = $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $eStreams = $toException;
       $num = @stream_select($rStreams, $wStreams, $eStreams, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                $host = parse_url($url, PHP_URL_HOST);
                $request = "GET $url HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $host\r\nConnection: Close\r\n\r\n";
                if (MD_DEBUG) echo "Sending request for $url<br>\n$request";
                fwrite($write, $request);
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                if (MD_DEBUG) echo "Getting data for $url<br>\n";
                $buffer = "";
                while (!feof($read))
                {
                   $buffer .= fgets($read, 1024); 
                }
                $tmp = explode("\r\n\r\n", $buffer);
                /* $header[$url] = */array_shift($tmp);
                $result[$url] = implode("\r\n\r\n", $tmp);
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
          if (count($eStreams) > 0)
          {
             foreach($eStreams as $exception)
             {
                $url = array_search($exception, $streams);
                if (MD_DEBUG) echo "Fail getting data for $url.<br>\n";
                // Здесь так же кричим, что сервер вернул не то что ожидали и выкидываем этот поток из стека
             }
             unset($toRead[array_search($exception, $toRead)]);
             unset($toWrite[array_search($exception, $toWrite)]);
             unset($toException[array_search($exception, $toException)]);
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}

// !!! Только полные URL-ы !!!
$urls = array(
   "http://www.yandex.ru/yandsearch?stype=www&nl=0&text=test",
   "http://mail.ru:80/"
   );
$sites = MyDownload ($urls);
var_dump($sites);

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса

Внимание: данный раздел предназначен для решения сложных, нестандартных задач.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Для профи | Следующая тема »


 




[ Время генерации скрипта: 0.1510 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.