|
Постоянный
Регистрация: 25.03.2008
Сообщений: 670
Провел на форуме: 4137635
Репутация:
2407
|
|
Обновил класс из предыдущего поста, теперь можно удобно работать с прокси.
Код класса:
PHP код:
<?php
/* WEBsock class by DX */
class websock
{
/*все переменные private*/
var $sock;
var $connection=0;
var $keepalive=300;
var $request='';
var $browser='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0';
var $proto='1.0';
var $addr='';
var $success=0;
var $proxy='';
var $pport=0;
var $port=0;
var $s_addr='';
var $s_port=0;
/*** Конструктор. $addr - адрес или IP сайта, $port - порт. ***/
function websock($addr,$port=80)
{
if(!function_exists('socket_create'))
return;
$this->addr=$addr;
$this->s_addr=$addr;
$this->s_port=$port;
if(!preg_match("/^(\d{1,3}\.){3}\d{1,3}$/",$addr))
$addr=gethostbyname($addr);
if(!$addr) return;
$this->sock=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if(!$this->sock)
return;
$this->success=1;
}
/*** Подключает сокет (через прокси или напрямую). ***/
function sconnect()
{
if($this->proxy)
{
if(!socket_connect($this->sock,$this->proxy,$this->pport)) return;
}
else
{
if(!socket_connect($this->sock,$this->s_addr,$this->s_port)) return;
}
if(!socket_set_nonblock($this->sock)) return;
}
/*** Устанавливает прокси с ip $addr и портом $port. ***/
function set_proxy($addr,$port)
{
$this->proxy=$addr;
$this->pport=$port;
}
/*** Проверка успешности создания сокета и подключения к нему. ***/
function check_success()
{
return $this->success;
}
/*** Запись в сокет. $data - данные для записи в сокет. Возвращает число байт, записанных в сокет. Если $data не указано, то будет записаны заголовки, созданные функцикей get_header() (см. ниже). ***/
function swrite($data='')
{
if(!$data) $data=$this->request;
if(socket_select($r=NULL,$w=array($this->sock),$f=NULL,5)!=1)
return false;
return socket_write($this->sock,$data);
}
/*** Чтение $bytes байт из сокета. Возвращает считанный контент. ***/
function sread($bytes)
{
if(socket_select($r=array($this->sock),$w=NULL,$f=NULL,5)!=1)
return false;
return socket_read($this->sock,$bytes);
}
/*** Чтение из сокета всего доступного содержимого. Эта функция не работает с HTTP/1.1. $stepbytes - сколько байтов считывать за раз. Возвращает считанный контент. ***/
function sreadfull($stepbytes=128)
{
$reading='';
while(($ret=$this->sread($stepbytes))!='')
{
$reading.=$ret;
}
$reading=$this->get_content_headers($reading);
return $reading;
}
/*** Установка типа соединения. $conn==0 - close, $conn==1 - keep-alive; $keepalive - время поддержки соединения. ***/
function set_connection($conn=0,$keepalive=300)
{
$this->connection=$conn==0 ? 0 : 1;
$this->keepalive=$keepalive;
}
function set_proto($proto='1.0') //set 1.0 or 1.1
{
$this->proto=$proto;
}
/*** Универсальная функция чтения из сокета, читает правильно независимо от типа соединения. Возвращает массив: $c[0] - заголовки, $c[1] - содержимое ***/
function http11read($stepbytes=128)
{
$c=$this->sreadfull($stepbytes);
if(strpos($c[0],'Transfer-Encoding: chunked')!==false)
return array($c[0],$this->remove_lengths($c[1]));
else
return $c;
}
/*** Получение cookies из заголовка ответа сервера и представление их в виде, удобном для вставки в заголовок Cookie. ***/
/*** $header - заголовок ответа сервера; $ret==0 - будет возвращена строка для заголовка Cookie, $ret==1 - будет возвращён массив cookies. ***/
function get_cookie($header,$ret=0)
{
preg_match_all('/Set-Cookie: (.+);/iUs',$header,$cook);
if(!isset($cook[1])) return $ret==0 ? '' : array();
$carr=array_unique($cook[1]);
$cookies=implode('; ',$carr);
return $ret==0 ? $cookies : $carr;
}
/*** Обрабатывает страницу с Transfer-encoding: chunked. Возвратит страницу без разбиений. ***/
function remove_lengths($res)
{
$len=1;
$nlen=0;
$curlen=0;
$ret='';
$tmp=explode("\r\n",$res);
foreach($tmp as $line)
{
if($len==1)
{
if($line=="\r\n")
{
$ret.=$line."\r\n";
continue;
}
$nlen=base_convert($line,16,10);
if($nlen==0) continue;
$len=0;
$curlen=0;
continue;
}
$curlen+=strlen($line."\r\n");
$ret.=$line."\r\n";
if($curlen>=$nlen)
{
$len=1;
continue;
}
}
return $ret;
}
/*** Разбивает полученные данные на заголовок и содержимое. $res - весь контент. Возвратит массив: $ret[0] - заголовки, $ret[1] - содержимое. ***/
function get_content_headers($res)
{
$ret=explode("\r\n\r\n",$res,2);
return $ret;
}
/*** Устанавливает виртуальный браузер. ***/
function set_browser($browser='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0')
{
$this->browser=$browser;
}
/*** Формирует заголовки для записи в сокет. ***/
/*** $service_uri - SERVICE_URI. Например, для http://site.com/aaa/bbb.php это /aaa/bbb.php ***/
/*** $page - страница. Для примера выше это site.com. Если сокет был создан как new websock('site.com'), то страницу можно не указывать. Если же как new websock('1.2.3.4'), то необходимо указывать. ***/
/*** $data - передаваемые скрипту данные (только для POST) ***/
/*** $method - GET/POST и т.д. ***/
/*** $cookie - cookies в виде строки ***/
/*** $ref - Referer ***/
/*** $addheaders - дополнительные заголовки, которые мы хотим установить ***/
/*** Возвращает запрос и устанавливает его как запрос по умолчанию. ***/
function get_header($service_uri,$page='',$data='',$method='GET',$cookie='',$ref='',$addheaders='')
{
if(!$page) $page=$this->addr;
if($this->proxy)
$request="$method http://{$this->s_addr}:{$this->s_port} HTTP/{$this->proto}\r\n";
else
$request="$method $service_uri HTTP/{$this->proto}\r\n";
$request.="Host: $page\r\n";
if($this->browser) $request.="User-Agent: {$this->browser}\r\n";
if($ref) $request.="Referer: $ref\r\n";
if($method=='POST')
{
$request.="Content-Type: application/x-www-form-urlencoded\r\n";
$request.="Content-Length: ".strlen($data)."\r\n";
}
if($this->connection==0)
{
$request.="Connection: close\r\n";
}
else
{
$request.="Keep-alive: {$this->keepalive}\r\n";
$request.="Connection: keep-alive\r\n";
}
if($addheaders)
$request.=$addheaders;
if($cookie)
$request.="Cookie: $cookie\r\n";
$request.="\r\n";
$request.=$data;
$this->request=$request;
return $request;
}
/*** Закрывает соединение ***/
function sclose()
{
return socket_close($this->sock);
}
/*** Возвращает последнюю ошибку работы с сокетами. ***/
function serr()
{
return socket_last_error($this->sock);
}
}
?>
Пример получения страницы через прокси:
PHP код:
<?php
/* скрипт получает страницу http://myip.ru через HTTP/1.1 и Connection: keep-alive, используя прокси */
require_once("websock.php"); //подключение файла с классом
$s=new websock('myip.ru',80); //создание нового сокета: http://myip.ru:80
//впишите здесь рабочий прокси
$s->set_proxy('203.162.2.139','80'); //устанавливаем адрес прокси-сервера и порт (можно убрать эту строку, тогда прокси не будет использоваться)
$s->sconnect(); //подключаем сокет
$s->set_connection(1,300); //keep-alive: 300
$s->set_proto('1.1'); //HTTP 1.1
$s->get_header('/'); //формируем заголовок для запроса к серверу (получаем корень http://myip.ru/)
$s->swrite(); //пишем его в сокет
$ret=$s->http11read(); //универсальная функция чтения из сокета, неважно, какие заданы параметры подключения. Читаем всё возвращённое содержимое.
print $ret[1]; //$ret[0] - заголовки, $ret[1] - содержимое
$s->sclose(); //закрываем соединение
?>
|