{"id":209,"date":"2009-08-08T00:27:29","date_gmt":"2009-08-07T23:27:29","guid":{"rendered":"http:\/\/eriz.pcinside.pl\/weblog\/alternatywa-dla-apache-yaws-php-rewrite-209.html"},"modified":"2009-08-08T00:27:29","modified_gmt":"2009-08-07T23:27:29","slug":"alternatywa-dla-apache-yaws-php-rewrite","status":"publish","type":"post","link":"https:\/\/eriz.pcinside.pl\/weblog\/alternatywa-dla-apache-yaws-php-rewrite-209.html","title":{"rendered":"Alternatywa dla Apache &#8211; YAWS + PHP + Rewrite"},"content":{"rendered":"<p>Nie da si\u0119 temu zaprzeczy\u0107 &#8211; <a href=\"http:\/\/pl.wikipedia.org\/wiki\/Erlang_(j\u0119zyk_programowania)\">Erlang<\/a> ma do\u015b\u0107 dziwn\u0105 sk\u0142adni\u0119, momentami naprawd\u0119 si\u0119 ci\u0119\u017cko po\u0142apa\u0107 po siedzeniu w j\u0119zykach typowo klamerkowych (vide: C, PHP, JS, etc), ale mo\u017cliwo\u015bci napisanych w nim aplikacji naprawd\u0119 pora\u017ca.<\/p>\n<p>I jak by tu nie pr\u00f3bowa\u0107 czego\u015b nowego? Ejabberd (demon Jabbera) \u015bwietnie si\u0119 sprawuje, przez sam\u0105 konstrukcj\u0119 j\u0119zyka, w kt\u00f3rym zosta\u0142 napisany, koder ma dost\u0119p do pot\u0119\u017cnego \u015brodowiska, kt\u00f3re poradzi sobie w naprawd\u0119 trudnych warunkach. Dla przyk\u0142adu &#8211; kto\u015b si\u0119 pofatygowa\u0142, aby <a href=\"http:\/\/www.sics.se\/~joe\/apachevsyaws.html\">przetestowa\u0107 Apache w por\u00f3wnaniu do YAWS<\/a>. Wyniki &#8211; szczerze m\u00f3wi\u0105c &#8211; mnie zszokowa\u0142y&#8230;<\/p>\n<p><!--more--><\/p>\n<p>Apache wysiad\u0142o przy 4 000 jednoczesnych \u017c\u0105daniach. Jednak na tym samym sprz\u0119cie, YAWS wytrzyma\u0142 do ponad <strong>80 000<\/strong> po\u0142\u0105cze\u0144. Kto\u015b jeszcze w\u0105tpi w zarz\u0105dzanie w\u0105tkami w Erlangu? Ja nie, zreszt\u0105 &#8211; autor testu powiedzia\u0142 wprost &#8211; s\u0142abo\u015b\u0107 Apache wynika prawdopodobnie w sposobie zarz\u0105dzania w\u0105tkami w Linuksie. Erlang wykonuje to niezale\u017cnie od platformy poprzez w\u0142asn\u0105 maszyn\u0119 wirtualn\u0105. Radzi sobie tak, jak zosta\u0142a zaprojektowana, czego dowodz\u0105 przeprowadzone testy.<\/p>\n<p>Przy pierwszym zetkni\u0119ciu mia\u0142em pewne obawy &#8211; maszyna wirtualna, od razu przed oczami \u015blamazarno\u015b\u0107 Javy. Jednak by\u0142em mile zaskoczony, \u017ce jednak s\u0105 \u015brodowiska, w kt\u00f3rych wydajno\u015b\u0107 i skalowalno\u015b\u0107 jednocze\u015bnie maj\u0105 znaczenie, do tego zasoby dynamicznie typowane&#8230; Szok&#8230;<\/p>\n<h4>\u015brodowisko uruchomieniowe<\/h4>\n<p>Instalacja pod Uniksami b\u0119dzie bardzo podobna, sprowadzi si\u0119 tylko do innego sposobu instalacji pakiet\u00f3w. Repozytoria, paczki &#8211; to ju\u017c zale\u017cy od konkretnej dystrybucji. Ja poka\u017c\u0119 instalacj\u0119 na przyk\u0142adzie Windows, gdy\u017c w tym \u015brodowisku na co dzie\u0144 pracuj\u0119.<\/p>\n<p>Wspomnia\u0142em, \u017ce Erlang bazuje na maszynie wirtualnej. Aby zacz\u0105\u0107 od czegokolwiek, trzeba najpierw j\u0105 zainstalowa\u0107. Wszystko jest na oficjalnej stronie &#8211; <a href=\"http:\/\/erlang.org\/download.html\">wystarczy pobra\u0107 binark\u0119<\/a> dla Windows. Jakie\u015b 60 MiB, ale warto si\u0119 uzbroi\u0107 w cierpliwo\u015b\u0107. ;] Dla \u015brodowiska Unix wystarcza paczka <em>erlang-lite<\/em>, kt\u00f3ra zawiera wy\u0142\u0105cznie \u015brodowisko uruchomieniowe.<\/p>\n<p><!-- group 1 --><\/p>\n<p class=\"images\"><a href=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-1.png\" rel=\"imagebox-1\" title=\"instalacja Erlanga\"><img decoding=\"async\" src=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-1-thumb.jpg\" alt=\"erlang\" style=\"width:156px;height:120px;\" \/><\/a> <\/p>\n<h4>demon<\/h4>\n<p>Po instalacji maszyny wirtualnej przychodzi pora na w\u0142a\u015bciw\u0105 instalacj\u0119 serwera. Jest ona do\u015b\u0107 banalna, wystarczy nieco popycha\u0107 instalator klikaj\u0105c przycisk <em>dalej<\/em>. <a href=\"http:\/\/yaws.hyber.org\/download\/\">\u015aci\u0105gamy instalk\u0119<\/a> ze strony developer\u00f3w i w zasadzie nie ma czego opisywa\u0107. ;]<\/p>\n<p><!-- group 2 --><\/p>\n<p class=\"images\"><a href=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-2.png\" rel=\"imagebox-2\" title=\"instalacja YAWS\"><img decoding=\"async\" src=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-2-thumb.jpg\" alt=\"YAWS\" style=\"width:160px;height:119px;\" \/><\/a> <\/p>\n<p>My\u015bleli\u015bcie, \u017ce b\u0119dzie ci\u0119\u017cko posadzi\u0107? Przykro mi, \u017ce rozczarowa\u0142em. ;]<\/p>\n<h4>pierwsze uruchomienie<\/h4>\n<p>YAWS nie posiada trybu us\u0142ugi pod Windows (w Uniksie podejrzewam, \u017ce dzia\u0142a ze standardowymi skryptami startowymi), z tego co si\u0119 rozezna\u0142em, wi\u0119c b\u0119dzie trzeba odpala\u0107 przez konsolk\u0119. Wystarczy uruchomi\u0107 wiersz polece\u0144, przej\u015b\u0107 do katalogu <em>bin<\/em> instalacji demona i wyda\u0107 komend\u0119 <em>yaws<\/em> i otworzy\u0107 w przegl\u0105darce stron\u0119 localhosta (<em>127.0.0.1<\/em>).<\/p>\n<p><!-- group 3 --><\/p>\n<p class=\"images\"><a href=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-3.png\" rel=\"imagebox-3\" title=\"dzia\u0142aj\u0105cy YAWS\"><img decoding=\"async\" src=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-3-thumb.jpg\" alt=\"YAWS\" style=\"width:160px;height:69px;\" \/><\/a> <a href=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-4.png\" rel=\"imagebox-3\" title=\"strona startowa\"><img decoding=\"async\" src=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-4-thumb.jpg\" alt=\"strona startowa\" style=\"width:160px;height:104px;\" \/><\/a> <\/p>\n<p>Wszystko dzia\u0142a. ;] Teraz pora zajrze\u0107 do konfiguracji. W przeciwie\u0144stwie do tej, do kt\u00f3rej przyzwyczai\u0142 nas np. Ejabberd, wszystko jest napisane bardzo czytelnie i intuicyjnie. Zmian\u0119 miejsca przechowywania stron tak samo, jak i wirtualne hosty mo\u017cna bardzo \u0142atwo przeprowadzi\u0107.<\/p>\n<p><code lang=\"xml\"><server 0.0.0.0><br \/>\n        port = 81 # to u mnie tylko ;]<br \/>\n        listen = 0.0.0.0<br \/>\n        docroot = \"D:\/tmp\/yaws\"<br \/>\n        allowed_scripts = yaws<br \/>\n<\/server><\/code><\/p>\n<p>Trudne? ;]<\/p>\n<h4>we wn\u0119trzno\u015bciach bestii<\/h4>\n<p>Serwis bez j\u0119zyk\u00f3w skryptowych dzisiaj nie utrzyma si\u0119 za d\u0142ugo (cho\u0107by przez problem redagowania, pewnych standardowych rozwi\u0105za\u0144, itp). YAWS umo\u017cliwia korzystanie w serwisach bezpo\u015brednio z kodu Erlanga. Ma\u0142o tego &#8211; powsta\u0142o ju\u017c kilka framework\u00f3w z my\u015bl\u0105 o dynamicznych serwisach WWW napisanych w\u0142a\u015bnie w tym j\u0119zyku, sam serwer udost\u0119pnia bogat\u0105 bibliotek\u0119 API, z kt\u00f3rej mo\u017cemy korzysta\u0107.<\/p>\n<p>Otwiera to ogromne mo\u017cliwo\u015bci, o kt\u00f3rych &#8211; mam nadziej\u0119 &#8211; b\u0119d\u0119 mia\u0142 okazj\u0119 napisa\u0107 w przysz\u0142o\u015bci. Jednak Erlanga jeszcze nie znam zbyt dobrze, wi\u0119c spr\u00f3bujemy podpi\u0105\u0107 do YAWS-a stary, dobry PHP. Nie jest to arcytrudne zadanie, wystarczy dopisa\u0107 par\u0119 linijek do pliku konfiguracyjnego, najwa\u017cniejsza:<\/p>\n<p><code lang=\"xml\"><br \/>\nphp_exe_path = \"C:\/bin\/server\/php5\/php-cgi.exe\"<br \/>\n<\/code><\/p>\n<p>to wskazuj\u0105ca na \u015bcie\u017ck\u0119 do interpretera (koniecznie do wersji CGI). Umieszczamy j\u0105 poza deklaracj\u0105 danego hosta. Je\u015bli chodzi o dalsz\u0105 konfiguracj\u0119, to wystarczy tylko w\u0142\u0105czy\u0107 obs\u0142ug\u0119 PHP dla hosta poprzez modyfikacj\u0119 jednej linijki do postaci:<\/p>\n<p><code lang=\"xml\">allowed_scripts = yaws php<\/code><\/p>\n<p>Do tego, namierzamy plik <em>php.ini<\/em> i umieszczamy w nim linijk\u0119:<\/p>\n<p><code lang=\"ini\">cgi.force_redirect = 0<\/code><\/p>\n<p>Teraz uruchomienie skryptu PHP powinno spowodowa\u0107 jego wykonanie. :] I tu kieruj\u0119 podzi\u0119kowania dla cz\u0142onk\u00f3w listy mailingowej YAWS, gdyby nie Oni &#8211; nie by\u0142bym w stanie uruchomi\u0107 PHP w YAWS.<\/p>\n<p><!-- group 4 --><\/p>\n<p class=\"images\"><a href=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-5.png\" rel=\"imagebox-4\" title=\"dzia\u0142aj\u0105cy PHP\"><img decoding=\"async\" src=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-5-thumb.jpg\" alt=\"PHP\" style=\"width:160px;height:114px;\" \/><\/a> <\/p>\n<p>Domy\u015blnie plik <em>php.ini<\/em> jest poszukiwany w katalogu systemowym, aby ustawi\u0107 w\u0142asn\u0105 lokalizacj\u0119, dodajemy zmienn\u0105 \u015brodowiskow\u0105 <em>PHPRC<\/em> ze \u015bcie\u017ck\u0105 do katalogu z plikiem konfiguracyjnym.<\/p>\n<p><!-- group 5 --><\/p>\n<p class=\"images\"><a href=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-6.png\" rel=\"imagebox-5\" title=\"zmienna \u015brodowiskowa\"><img decoding=\"async\" src=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-6-thumb.jpg\" alt=\"PHPRC\" style=\"width:116px;height:120px;\" \/><\/a> <\/p>\n<h4>dance me!<\/h4>\n<p>Pozosta\u0142a jeszcze jedna kwestia &#8211; przepisywanie adres\u00f3w (aka. <em>mod_rewrite<\/em>). I tu dopiero zaczyna si\u0119 artyleria. Wspomnia\u0142em wcze\u015bniej o tym, \u017ce YAWS umo\u017cliwia wykonywanie skrypt\u00f3w Erlanga w locie. I w\u0142a\u015bnie w celu przepisania adres\u00f3w go wykorzystamy.<\/p>\n<p>Niestety, nie ma takiej wygody, jak w przypadku <em>htaccess<\/em> &#8211; bez znajomo\u015bci sk\u0142adni Erlanga mo\u017ce by\u0107 ci\u0119\u017cko. Je\u015bli chodzi o np. Zend Framework &#8211; jest <a href=\"http:\/\/www.caldersoft.com\/files\/rewriter.erl\">praktycznie gotowiec<\/a>.<\/p>\n<p>Skrypt ten kopiujemy do katalogu <em>ebin<\/em> serwera. Co robi? Routuje wszystkie \u015bcie\u017cki pr\u00f3cz paru rozszerze\u0144 jak ZF: <em>\/index.php\/param&#8230;<\/em>. Mo\u017cna zmodyfikowa\u0107, no problem. ;] Osobi\u015bcie sprowadzi\u0142em to do takiej postaci:<\/p>\n<p><code lang=\"erlang\">-module(rewriter).<\/p>\n<p>-export([arg_rewrite\/1]).<\/p>\n<p>-include_lib(\"..\/include\/yaws_api.hrl\").<\/p>\n<p>arg_rewrite(Arg) -><br \/>\n    % Decode request path<br \/>\n    Req = Arg#arg.req,<br \/>\n    case Req#http_request.path of<br \/>\n        {abs_path, RawPath} -><br \/>\n            case (catch yaws_api:url_decode_q_split(RawPath)) of<br \/>\n                {'EXIT', _} -><br \/>\n                    Arg1 = Arg;<br \/>\n                {Path, _Query} -><br \/>\n                    % Do not parse file types matching the regexp rule below.<br \/>\n\t\t    % This rule is an exact copy of Apache .htaccess rule.<br \/>\n\t\t    % You can modify it to match your needs.<br \/>\n                    case regexp:first_match(Path, \"\\.(js|ico|gif|jpg|png|css|html|htm)$\") of<br \/>\n                        {match, _Start, _Lenght} -><br \/>\n                            Arg1 = Arg;<br \/>\n                        _Else -><br \/>\n                            Elems = string:tokens(Path, \"\/\"),<br \/>\n                            case Elems of<br \/>\n                                [] -><br \/>\n                                    % Rewrite request to index.php<br \/>\n                                    NewPath = \"\/index.php\" ++ RawPath,<br \/>\n                                    Req1 = Req#http_request{path = {abs_path, NewPath}},<br \/>\n                                    Arg1 = Arg#arg{req = Req1};<br \/>\n                                [H|T] -><br \/>\n                                    % Check if request already begins with index.php<br \/>\n                                    case string:equal(H, \"index.php\") of<br \/>\n                                        true -><br \/>\n                                            % Check for possible index.php duplicates<br \/>\n                                            case T of<br \/>\n                                                [] -><br \/>\n                                                    Arg1 = Arg;<br \/>\n                                                [H1|T1] -><br \/>\n                                                    case string:equal(H1, \"index.php\") of<br \/>\n                                                        true -><br \/>\n                                                            % If duplicates found, remove them<br \/>\n                                                            L = lremove(\"index.php\", [T1]),<br \/>\n                                                            NewPath = \"\/index.php?query=\" ++ join(L, \"\/\"),<br \/>\n                                                            Req1 = Req#http_request{path = {abs_path, NewPath}},<br \/>\n                                                            Arg1 = Arg#arg{req = Req1};<br \/>\n                                                        false -><br \/>\n                                                            Arg1 = Arg<br \/>\n                                                    end<br \/>\n                                            end;<br \/>\n                                        false -><br \/>\n                                            % Rewrite request to index.php<br \/>\n                                            NewPath = \"\/index.php?query=\" ++ RawPath,<br \/>\n                                            Req1 = Req#http_request{path = {abs_path, NewPath}},<br \/>\n                                            Arg1 = Arg#arg{req = Req1}<br \/>\n                                    end<br \/>\n                            end<br \/>\n                    end<br \/>\n            end;<br \/>\n        _Else -><br \/>\n            Arg1 = Arg<br \/>\n    end,<br \/>\n    Arg1.<\/p>\n<p>% Remove all occurences of Elem from the beginning of the list<br \/>\nlremove(_Elem, []) -><br \/>\n    [];<br \/>\nlremove(Elem, List) -><br \/>\n    [H|T] = List,<br \/>\n    case string:equal(H, \"index.php\") of<br \/>\n        true -><br \/>\n            lremove(Elem, T);<br \/>\n        false -><br \/>\n            List<br \/>\n    end.<\/p>\n<p>% Join list into a string with elements separated with Sep<br \/>\njoin([], Sep) -><br \/>\n    Sep;<br \/>\njoin([H|T], Sep) -><br \/>\n    H ++ lists:concat([Sep ++ X || X <- T]).<\/code><\/p>\n<p>co przekszta\u0142ca URL do postaci <em>\/index.php?query=param\/...<\/em>. Zapisany skrypt <em>rewriter.erl<\/em> nale\u017cy teraz skompilowa\u0107. Odpalamy wiersz polece\u0144 w katalogu <em>ebin<\/em> YAWS, wydajemy komend\u0119 <em>erl<\/em>. Uruchomi si\u0119 interpreter, kt\u00f3ry pos\u0142u\u017cy nam do wygenerowania binarki dla serwera. Wklepujemy komend\u0119 <em>c(rewriter.erl).<\/em> i po naci\u015bni\u0119ciu enter powinni\u015bmy otrzyma\u0107 komunikat z potwierdzeniem oraz plik <em>rewriter.beam<\/em>, kt\u00f3ry b\u0119dzie modu\u0142em przekierowa\u0144.<\/p>\n<p>Pozostaje jeszcze kwestia konfiguracji. Linijk\u0119 z <em>ebin_dir<\/em> modyfikujemy do postaci:<\/p>\n<p><code lang=\"xml\">ebin_dir = \"C:\/bin\/server\/Yaws-1.84\/ebin\"<\/code><\/p>\n<p>a dla hosta:<\/p>\n<p><code lang=\"xml\">arg_rewrite_mod = rewriter<\/code><\/p>\n<p>Teraz pora na restart serwera i test:<\/p>\n<p><!-- group 6 --><\/p>\n<p class=\"images\"><a href=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-7.png\" rel=\"imagebox-6\" title=\"przepisany adres\"><img decoding=\"async\" src=\"\/weblog\/stuff\/209-alternatywa-dla-apache-yaws-php-rewrite-7-thumb.jpg\" alt=\"rewrite\" style=\"width:160px;height:89px;\" \/><\/a> <\/p>\n<p>Jak wida\u0107, wszystko dzia\u0142a. ;]<\/p>\n<h4>epilog<\/h4>\n<p>Erlang jest naprawd\u0119 fajnym \u015brodowiskiem (tylko ta sk\u0142adnia... :S), udost\u0119pnia \u015bwietne API (m.in. baz\u0119 Mnesia, kt\u00f3ra jest transakcyjn\u0105, odporn\u0105 na b\u0142\u0119dy baz\u0105 danych, zorientowan\u0105 obiektowo)... Mam nadziej\u0119, \u017ce b\u0119dzie za jaki\u015b czas powa\u017cn\u0105 konkurencj\u0105 nie tylko dla Ruby, czy Pythona, ale r\u00f3wnie\u017c i dla samego PHP.<\/p>\n<p>Oby tylko czas na wszystko pozwoli\u0142... ;]<\/p>\n<p>Ewentualne pomy\u0142ki wybaczcie - dopiero raczkuj\u0119 w Erlangu, zapraszam do dyskusji.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nie da si\u0119 temu zaprzeczy\u0107 &#8211; Erlang ma do\u015b\u0107 dziwn\u0105 sk\u0142adni\u0119, momentami naprawd\u0119 si\u0119 ci\u0119\u017cko po\u0142apa\u0107 po siedzeniu w j\u0119zykach typowo klamerkowych (vide: C, PHP, JS, etc), ale mo\u017cliwo\u015bci napisanych w nim aplikacji naprawd\u0119 pora\u017ca. I jak by tu nie pr\u00f3bowa\u0107 czego\u015b nowego? Ejabberd (demon Jabbera) \u015bwietnie si\u0119 sprawuje, przez sam\u0105 konstrukcj\u0119 j\u0119zyka, w kt\u00f3rym [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[31,113,30,112],"_links":{"self":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts\/209"}],"collection":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/comments?post=209"}],"version-history":[{"count":0,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/posts\/209\/revisions"}],"wp:attachment":[{"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/media?parent=209"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/categories?post=209"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eriz.pcinside.pl\/weblog\/wp-json\/wp\/v2\/tags?post=209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}