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_INET, SOCK_STREAM, SOL_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_INET, SOCK_STREAM, SOL_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, $buf, strlen($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); ?>
Я тебе уже говорил что скриптик прикольный, только жалко его не возможно поставить на сервак... P.S>А да еще заметил одну фишку с socket, когда работаешь с протоколами например с SMTP or FTP то команды посылаются нормально через socket, если посылать запросы HTTP сначало один запрос с заголовков, а потом второй, то первый пройдет, а второй почему то не хочет проходить.. фиг знает почему, это было так маленькое отступление наболевшего
Вообще-то все правильно Посмотри...он эти переменные просто определяет что они существуют для дальнейшего использования без ошибок !
Для каждого HTTP запроса нужно создавать сокет заново. Клиент посылает 1 запрос - получает от сервера 1 ответ - связь окончена. Когда-то тут цитировали рфц по этому поводу, не помню уже где )
По идее скрипт должен вырубаться с сообщением: "socket_create() failed, reason: socket library is not loaded"
все хорошо, но для каждого нового подключения необходимо создавать новый паток. В твоем варианте все работает, но вот скорсть страдает, т.к. все запросы становяться в очередь и ждут окончания выполнения придыдущего. А есле это будет скачка тяжолого файла? вобщем думаю понял что я имел ввиду
Вообще этот прокси расчитан на 5 коннектов одновременно по дефолту(что можно поменять в настройках) раз, а во вторых многопоточность в пхп - это извращение как таковое....
Эт я видел, но каая разница скок конектов, начнеш через него файл скачивать и все.... один конект... Согласен, но а что делать..
Как юзать можно? Реально, чтобы прописать в браузере ИП сайта и порт 80 где он стоит и чтобы работал?
Измени на что нить другое: $set['port']=3333;//порт для прокси серва PS Кхм а перевести самому слабо было?) Правда хер пойми че те надо. Но вообщем алгоритм юзания следующий. Берем скрипт этого проксика засовываем на какой нить хост. Запускаем этот скрипт (как запускать писать не буду). Если запустился без ошибок значит все ок. Далее в браузере пишем в качестве адреса прокси IP адрес хоста и порт который вы указали в настройках (для танкистов $set['port']). И можете спокойно работать через этот проксег. PS Ляд ну пожалуйста научитесь писать нормально чего вам надо, в конце концов оно надо вам. Почему мы должны угадывать что вам нужно?