PHP Proxy Server

Discussion in 'PHP' started by Dr.Z3r0, 22 Feb 2008.

  1. Dr.Z3r0

    Dr.Z3r0 Leaders of the World

    Joined:
    6 Jul 2007
    Messages:
    284
    Likes Received:
    595
    Reputations:
    567
    PHP Proxy Server v1.0 pre-realase

    Вообщем вот проксик написал.
    Писал для себя скажем так для развития. Интересовала библиотека socket. Вот собственно из этого и получился прокси серв.

    Возможности эт собственно сам прокси сервер, тунелирование, логирование и пр.

    Для работы требуется библиотека socket!
    PHP:
    <?php
    /////////////////////////////////////////
    //  PHP Proxy Server v1.0 pre-realase  //
    //         Created by I-I()/Ib         //
    //              22.02.08               //
    /////////////////////////////////////////
    $set['port']=3333;//порт для прокси серва
    $set['mxconnect']=5;//максимальное количество одновременных подключений
    $set['lenpack']=10240;//max кол-во байт на прием/отссылку за один раз от/к клиент(а/у)
    $set['dishost']='microsoft.com';//Хост запросив который мы вырубим проксик
    /////////////////////////////////////////
    $set['usagent']='Mozilla/5.0 ( Windows; U; AOL 5.0; TWRAITH )';//Заменять User-Agent на это... (false оставить прежним)
    $set['xforwadfor']=0;//X-Forwarded-For: 0-не указывать/удалить существующий, 1-указывать реальный, 2-генерить случайно
    $set['referer']=0;//Referer: 0-удалять, 1-оставить
    $set['chngprx']=0;//0-Менять заголовок указывающий на то что используется прокси сервер, 1-не менять
    $set['addcapt']=0;//1-Добавлять заголовок указывающий версию этого прокси серва, 0-не добалять
    /////////////////////////////////////////
    $set['allip']=true;//true-прокси для всех ип, false только для $set['acssip']
    $set['acssip']=array('127.0.');//маски разрешенных ип...
    /////////////////////////////////////////
    $set['logerror']='error.log';//Файл лога ошибок, false-не писать...
    $set['logacess']='acess.log';//Лог запросов прокси, false-не писать...
    $set['savacess']=1;//0-Указать только ип и время, 1-указать ип время и удаленный хост
    /////////////////////////////////////////
    $set['tnlnbld']=false;//Включить поддержку тунелирования проксиком
    $set['fltnl']='proxy.txt';//Файл список всех прокси серверов
    $set['rntnl']=true;//Рандомно изменять порядок серверов
    $set['ndtnl']=false;//Последний сервер в списке всегда конечный
    $set['nmtnl']='Data-Send';//Имя параметра в заголвке в котором будет передаваться весь список прокси
    /////////////////////////////////////////

    function parse_packet(&$packet, &$host, &$error$ip){
        global 
    $set;

        
    $error=false;
        
    //Валидность ипа
        
    if(!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/',$ip)){
            
    $error='Proxy don\'t understend your ip. Sorry...';
        }else{
            
    //Разрешен ли проксик для всех ипов
            
    if(!$set['allip']){
                
    $error='This proxy can not used from anything ip. Acsess denieded.';
                foreach(
    $set['acssip'] as $key){
                    if(
    preg_match('/'.preg_quote($key).'/',$ip)){
                        
    $error=false;
                        break;
                    }
                }
            }
        }

        if(!
    $error){
            
    //Проверка валидности пакета
            
    if(!preg_match('/^(GET|POST|HEAD) \S+ HTTP\/1\.[1|0]\r\n([\w-]+: [\w|\W]+\r\n)+\r\n[\w|\W]*/i',$packet))$error='Proxy don\'t understand your packet. Sorry...';
            else{
                
    //Выдираем имя хоста
                
    if(!preg_match('/Host: ([^\r\n]+)/i',$packet,$tmp))$error='In your packet don\'t writing remote host. Sorry...';
                else{
                    if(!
    preg_match('/^[\w\.\-:]+$/',$tmp[1]))$error='Remote host not valid. Sorry...';
                    else{
                        
    $host=$tmp[1];
                        
    $tmp='';
                        
    //Лог обращений к проксику
                        
    if($set['logacess']){
                            
    $fp=fopen($set['logacess'], 'a');
                            
    fputs($fp,$ip.' ['.date('H:i d.m.Y',time()).'] '.$host."\r\n");
                            
    fclose($fp);
                        }
                        
    //Меняем User-Agent
                        
    if($set['usagent'])$packet=preg_replace('/User-Agent: [^\r\n]+/i','User-Agent: '.$set['usagent'],$packet);
                        
    //Меняем Referer
                        
    if($set['referer']===0)$packet=preg_replace('/Referer: [^\r\n]+\r\n/i','',$packet);
                        
    //Меняем лишние заголовки
                        
    if($set['chngprx']===0)$packet=preg_replace('/Proxy-Connection: /','Connection: ',$packet);
                        
    //Операции с X-Forwarded-For
                        
    if($set['xforwadfor']===0)$packet=preg_replace('/X-Forwarded-For: [^\r\n]+\r\n/i','',$packet);
                        else if(
    $set['xforwadfor']===1)$packet=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".'X-Forwarded-For: '.$ip,$packet);
                        else if(
    $set['xforwadfor']===2)$packet=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".'X-Forwarded-For: '.gen_ran_ip(),$packet);
                        
    //Указываем версию проксика
                        
    if($set['addcapt']===1)$packet=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".'Use-Proxy: PPS v1.0',$packet);
                    }
                }
            }
        }

        if(!
    $error)return true;
        else return 
    false;
    }

    function 
    gen_ran_ip(){
        
    $ip=rand(80,255);
        
    $ip.='.'.rand(80,255);
        
    $ip.='.'.rand(80,255);
        
    $ip.='.'.rand(80,255);

        return 
    $ip;
    }

    function 
    eror_rep($error,$ip){
        global 
    $set;

        if(
    $error){
            
    //Лог ошибок
            
    if($set['logerror']){
                
    $fp=fopen($set['logerror'], 'a');
                
    fputs($fp,$ip.' ['.date('H:i d.m.Y',time()).']'.$error."\r\n");
                
    fclose($fp);
            }
            
    $packet_ret='HTTP/1.1 500 Error
    Server: PPS v1.0
    Connection: Close
    Transfer-Encoding: chunked
    Content-Type: text/html

    '
    ;
            
    $tmp='<html>
    <head>
    <title>Proxy Error...</title>
    <head>
    <body>
    Proxy return error:<br>
    '
    .$error.'
    </body>
    </html>'
    ;
            
    $packet_ret.=dechex(strlen($tmp))."\r\n".$tmp."\r\n".'0'."\r\n\r\n";
            return 
    $packet_ret;
        }else return 
    false;

    }

    error_reporting(0);
    set_time_limit(0);
    ignore_user_abort(true);
    //Подключенна ли данная библиотека
    if(!function_exists('socket_create'))die("socket_create() failed, reason: socket library is not loaded");
    //Создание сокета
    if(!($sock=@socket_create(AF_INETSOCK_STREAMSOL_TCP)))die("socket_create() failed, reason: ".socket_last_error()."<br>\r\n".socket_strerror(socket_last_error()));
    //Открываем порт
    if(!(@socket_bind($sock'127.0.0.1'$set['port'])))die("socket_bind() failed, reason: ".socket_last_error()."<br>\r\n".socket_strerror(socket_last_error()));
    //Ждем подключений
    if(!@socket_listen($sock$set['mxconnect']))die("socket_listen() failed, reason: ".socket_last_error()."<br>\r\n".socket_strerror(socket_last_error()));

    while(
    1){
        
    //Создаем новый ресурс сокета на новое подключение
        
    if(!($msgsock=@socket_accept($sock))){
            
    socket_close($msgsock);
            continue;
        }
        
    //Узнаем ип клиента
        
    $ip='';
        if(!@
    socket_getpeername($msgsock,$ip)){
            
    socket_close($msgsock);
            continue;
        }

        
    $zzz='';
        
    $buf='';
        
    $pak='';
        
    //Читаем пакет от клиента
        
    while(1){
            
    $tmp=@socket_read($msgsock$set['lenpack'],PHP_BINARY_READ);
            if(!empty(
    $tmp)){
                if(!
    is_array($pak)){
                    
    $buf.=$tmp;
                    
    //Прием заголовка окончен
                    
    if(preg_match('/\r\n\r\n/i',$buf)){
                        
    //Определяемся с методом передачи данных
                        
    if(preg_match('/^(GET|POST|HEAD)/i',$buf,$zzz)){
                            
    $pak['type']=$zzz[1];
                            
    $zzz='';
                            
    //Для GET и HEAD одного заголовка достаточно
                            
    if(($pak['type']==='GET')||($pak['type']==='HEAD')){
                                
    $pak['header']=$buf;
                                
    $pak['receiv']='';
                                break;
                            }else{
                                
    //Выдираем Content-Length для метода POST
                                
    if(preg_match('/Content-Length: (\d+)\r\n/i',$buf,$zzz)){
                                    
    $pak['length']=$zzz[1];
                                    
    //Делим пакет на заголовок и данные
                                    
    preg_match('/([\w|\W]+)\r\n\r\n([\w|\W]*)/i',$buf,$zzz);
                                    
    $pak['header']=$zzz[1];
                                    
    $pak['receiv']=$zzz[2];
                                    
    $zzz='';
                                    if(
    strlen($pak['receiv'])==$pak['length'])break;
                                }else break;
                            }
                        }else{
                            
    $pak['header']='';
                            
    $pak['receiv']='';
                            
    $pak['length']='0';
                            break;
                        }
                    }
                }else{
                    
    //Собираем до конца все данные
                    
    $pak['receiv'].=$tmp;
                    if(!(
    strlen($pak['receiv'])<$pak['length']))break;
                }
                
    $tmp='';
            }
        }
        
    $buf=$pak['header']."\r\n\r\n".$pak['receiv'];

        
    $tmp='';
        if(
    parse_packet($buf,$host,$error,$ip)){
            
    //Вырубить проксик
            
    if($host===$set['dishost']){
                
    socket_close($msgsock);
                
    socket_close($sock);
                die();
            }

            
    //Поддержка тунелирования
            
    $proxy='';
            if(
    $set['tnlnbld']){
                
    //Передан ли параметр с прокси сервами
                
    if(preg_match('/'.preg_quote($set['nmtnl']).': ([^\r\n]+)/',$buf,$tmp)){
                    
    $tmp=explode('|',base64_decode($tmp[1]));
                    if(!empty(
    $tmp)){
                        
    //Убираем адрес следующего прокси сервера
                        
    $host=$tmp[0];
                        if(
    count($tmp)>1){
                            
    $proxy='';
                            for(
    $i=1;$i<count($tmp);$i++)$proxy.=$tmp[$i].'|';
                            
    $proxy=substr($proxy,0,strlen($proxy)-1);
                            
    $proxy=base64_encode($proxy);
                            
    //Записываем это все в заголовок
                            
    $buf=preg_replace('/'.preg_quote($set['nmtnl']).': ([^\r\n]+)/i',$set['nmtnl'].': '.$proxy,$buf);
                            
    $tmp='';
                        }else{
                            
    $buf=preg_replace('/'.preg_quote($set['nmtnl']).': ([^\r\n]+)\r\n/i','',$buf);
                        }
                    }
                    
    $tmp='';
                }else{
                    
    //Существует ли файл со списоком(предполагается что этот сервер - 1ый)
                    
    if(file_exists($set['fltnl'])){
                        
    $tmp=file($set['fltnl']);
                        
    $host=trim($tmp[0]);
                        if(
    count($tmp)>1){
                            
    $proxy='';
                            
    $xxxx='';
                            
    //Перемешивание
                            
    if($set['rntnl']){
                                
    //Конечный проксик один и тот же всегда
                                
    if($set['ndtnl']){
                                    
    $yyyy=$tmp[count($tmp)-1];
                                    for(
    $i=1;$i<count($tmp)-1;$i++)$xxxx[$i-1]=trim($tmp[$i]);
                                    
    shuffle($xxxx);
                                    
    $xxxx[]=$yyyy;
                                    
    $yyyy='';
                                }else{
                                    for(
    $i=1;$i<count($tmp);$i++)$xxxx[$i-1]=trim($tmp[$i]);
                                    
    shuffle($xxxx);
                                }
                            }else{
                                for(
    $i=1;$i<count($tmp);$i++)$xxxx[$i-1]=trim($tmp[$i]);
                            }
                            
    $tmp='';
                            foreach(
    $xxxx as $tmp)$proxy.=$tmp.'|';
                            
    $proxy=substr($proxy,0,strlen($proxy)-1);
                            
    $proxy=base64_encode($proxy);
                            
    //Записываем это все в заголовок
                            
    $buf=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".$set['nmtnl'].': '.$proxy,$buf);
                            
    $xxxx='';
                        }
                        
    $tmp='';
                    }
                }
            }
            
    $proxy='';
            
    $tmp='';

            
    $port=80;
            
    //Если в хосте указан порт то его нужно выдрать
            
    if(preg_match('/^([^:]+)(:\d+)*$/',$host,$tmp)){
                
    $host=$tmp[1];
                if(isset(
    $tmp[2])){
                    
    $port=$tmp[2];
                    
    preg_match('/^:(\d+)$/',$port,$tmp);
                    
    $port=$tmp[1];
                }
            }

            
    $tmp='';
            
    //Если в кач-ве хоста передано имя домена, то его нуно преобразовать в айпишник...
            
    if(!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/',$host)){
                
    $tmp=gethostbyname($host);
                if(
    $tmp===$host){
                    
    //Имя домена не найденно
                    
    $tmp=eror_rep('Remote server not found. Sorry...',$ip);
                    
    socket_write($msgsock,$tmp,strlen($tmp));
                    
    $error=true;
                }else 
    $host=$tmp;
                
    $tmp='';
            }

            if(!
    $error){
                
    //Посылка запроса на удаленный сервер
                
    $sock2=socket_create(AF_INETSOCK_STREAMSOL_TCP);
                
    //Подключение
                
    if(!(@socket_connect($sock2$host$port))){
                    
    $tmp=eror_rep('Can\'t connect ro remote server. Reason:'."<br>\r\n".socket_strerror(socket_last_error()),$ip);
                    
    socket_write($msgsock,$tmp,strlen($tmp));
                    break;
                }else{
                    
    //Отправка пакета
                    
    if(!(@socket_write($sock2$bufstrlen($buf)))){
                        
    $tmp=eror_rep('Can\'t send packet ro remote server. Reason:'."<br>\r\n".socket_strerror(socket_last_error()),$ip);
                        
    socket_write($msgsock,$tmp,strlen($tmp));
                        break;
                    }else{
                        
    //Чтение
                        
    while($tmp=@socket_read($sock2$set['lenpack'])){
                            
    //Отправка приянтых данных клиенту
                            
    if(!$tmp)break;
                            
    socket_write($msgsock,$tmp,strlen($tmp));
                        }
                    }
                }
                
    socket_close($sock2);
            }
        }else{
            
    //Отправка текста ошибки клиенту
            
    $tmp=eror_rep($error."<br>\r\n",$ip);
            
    socket_write($msgsock,$tmp,strlen($tmp));
        }
        
    $ip='';
        
    $buf='';
        
    $pak='';
        
    socket_close($msgsock);
    }
    socket_close($sock);
    ?>
     
    7 people like this.
  2. bul.666

    bul.666 булка

    Joined:
    6 Jun 2006
    Messages:
    719
    Likes Received:
    425
    Reputations:
    140
    Не лучшебы использовать unset() ?
     
  3. DIAgen

    DIAgen Banned Life!

    Joined:
    2 May 2006
    Messages:
    1,055
    Likes Received:
    376
    Reputations:
    460
    Я тебе уже говорил что скриптик прикольный, только жалко его не возможно поставить на сервак...

    P.S>А да еще заметил одну фишку с socket, когда работаешь с протоколами например с SMTP or FTP то команды посылаются нормально через socket, если посылать запросы HTTP сначало один запрос с заголовков, а потом второй, то первый пройдет, а второй почему то не хочет проходить.. фиг знает почему, это было так маленькое отступление наболевшего:)
     
  4. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,193
    Reputations:
    252
    Вообще-то все правильно :)
    Посмотри...он эти переменные просто определяет что они существуют для дальнейшего использования без ошибок !
     
  5. xaker-boss

    xaker-boss Elder - Старейшина

    Joined:
    6 Mar 2007
    Messages:
    251
    Likes Received:
    49
    Reputations:
    -11
    Отлично работает, спасибо
     
  6. ElteRUS

    ElteRUS Elder - Старейшина

    Joined:
    11 Oct 2007
    Messages:
    367
    Likes Received:
    460
    Reputations:
    93
    Для каждого HTTP запроса нужно создавать сокет заново. Клиент посылает 1 запрос - получает от сервера 1 ответ - связь окончена. Когда-то тут цитировали рфц по этому поводу, не помню уже где )
     
  7. heks

    heks Banned

    Joined:
    24 Aug 2007
    Messages:
    713
    Likes Received:
    95
    Reputations:
    12
    у меня что то не работает как можно проверить присутствует ли библиотека сокет
     
    #7 heks, 24 Feb 2008
    Last edited: 24 Feb 2008
  8. Dr.Z3r0

    Dr.Z3r0 Leaders of the World

    Joined:
    6 Jul 2007
    Messages:
    284
    Likes Received:
    595
    Reputations:
    567
    По идее скрипт должен вырубаться с сообщением:
    "socket_create() failed, reason: socket library is not loaded"
     
  9. Pernat1y

    Pernat1y Elder - Старейшина

    Joined:
    20 Dec 2007
    Messages:
    479
    Likes Received:
    79
    Reputations:
    7
    посмотри лог ошибок апача, и проверь, подключен-ли php_sockets.dll расширениях (php.ini)
     
  10. nc.STRIEM

    nc.STRIEM Members of Antichat

    Joined:
    5 Apr 2006
    Messages:
    1,036
    Likes Received:
    347
    Reputations:
    292
    все хорошо, но для каждого нового подключения необходимо создавать новый паток.
    В твоем варианте все работает, но вот скорсть страдает, т.к. все запросы становяться в очередь и ждут окончания выполнения придыдущего. А есле это будет скачка тяжолого файла? вобщем думаю понял что я имел ввиду
     
  11. Dr.Z3r0

    Dr.Z3r0 Leaders of the World

    Joined:
    6 Jul 2007
    Messages:
    284
    Likes Received:
    595
    Reputations:
    567
    Вообще этот прокси расчитан на 5 коннектов одновременно по дефолту(что можно поменять в настройках) раз, а во вторых многопоточность в пхп - это извращение как таковое....
     
    #11 Dr.Z3r0, 24 Feb 2008
    Last edited: 31 May 2011
  12. nc.STRIEM

    nc.STRIEM Members of Antichat

    Joined:
    5 Apr 2006
    Messages:
    1,036
    Likes Received:
    347
    Reputations:
    292
    Эт я видел, но каая разница скок конектов, начнеш через него файл скачивать и все.... один конект...

    Согласен, но а что делать..
     
  13. sabe

    sabe Elder - Старейшина

    Joined:
    16 Mar 2007
    Messages:
    313
    Likes Received:
    178
    Reputations:
    14
    как исправить ?
     
  14. Developer

    Developer Elder - Старейшина

    Joined:
    3 May 2006
    Messages:
    152
    Likes Received:
    25
    Reputations:
    10
    Как юзать можно? Реально, чтобы прописать в браузере ИП сайта и порт 80 где он стоит и чтобы работал?
     
  15. Dr.Z3r0

    Dr.Z3r0 Leaders of the World

    Joined:
    6 Jul 2007
    Messages:
    284
    Likes Received:
    595
    Reputations:
    567
    Измени на что нить другое:
    $set['port']=3333;//порт для прокси серва
    PS Кхм а перевести самому слабо было?)


    Правда хер пойми че те надо. Но вообщем алгоритм юзания следующий. Берем скрипт этого проксика засовываем на какой нить хост. Запускаем этот скрипт (как запускать писать не буду). Если запустился без ошибок значит все ок. Далее в браузере пишем в качестве адреса прокси IP адрес хоста и порт который вы указали в настройках (для танкистов $set['port']). И можете спокойно работать через этот проксег.

    PS Ляд ну пожалуйста научитесь писать нормально чего вам надо, в конце концов оно надо вам. Почему мы должны угадывать что вам нужно?
     
  16. DVD_RW

    DVD_RW Banned

    Joined:
    27 Apr 2008
    Messages:
    0
    Likes Received:
    202
    Reputations:
    -36
    эм...за нубский вопрос сорри... а на coolpage.biz пойдёт? ><
     
    2 people like this.
  17. Romaxa55

    Romaxa55 Banned

    Joined:
    19 Oct 2005
    Messages:
    144
    Likes Received:
    30
    Reputations:
    4
    Пишет
    Проблеммаа с самим хостингом?

    Скорей всего сокет не подключин на хосте
     
    #17 Romaxa55, 25 Aug 2008
    Last edited: 27 Aug 2008
  18. sharky_fish

    sharky_fish New Member

    Joined:
    25 Oct 2008
    Messages:
    11
    Likes Received:
    2
    Reputations:
    0
    А на каком бесплатном хостинге работает? Может ктото подсказать?
    Или можно ПМ. Спасибо.
     
    1 person likes this.
  19. ntldr

    ntldr Elder - Старейшина

    Joined:
    4 Dec 2007
    Messages:
    367
    Likes Received:
    140
    Reputations:
    23
    искал давно!
     
  20. sharky_fish

    sharky_fish New Member

    Joined:
    25 Oct 2008
    Messages:
    11
    Likes Received:
    2
    Reputations:
    0
    Наверное уже не судьба получить ответ :)