Показать сообщение отдельно

  #367  
Старый 27.05.2008, 21:54
d_x
Постоянный
Регистрация: 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==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=='' : array();

    
$carr=array_unique($cook[1]);

    
$cookies=implode('; ',$carr);
    return 
$ret==$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(); //закрываем соединение
?>
 
Ответить с цитированием