<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4106195950283171870</id><updated>2015-06-04T01:13:48.290+02:00</updated><category term="CHEATSHEETS"/><category term="PHP"/><category term="PHP5"/><category term="Symfony2"/><category term="APACHE2"/><category term="Blogger"/><category term="CHEATSHEETS_SYMFONY"/><category term="HTML5_CSS3"/><category term="JAVASCRIPT"/><category term="UPGRADE"/><category term="QUICKLINKS"/><category term="CHEATSHEETS_JQUERY"/><category term="GD2"/><category term="GIT_SVN"/><category term="HTTP"/><category term="XML_JSON_SOAP"/><category term="cURL"/><category term="jQuery"/><category term="CHEATSHEETS_PHP"/><category term="CHEATSHEETS_SYMFONY2"/><category term="HTML5"/><category term="PDO"/><category term="QUICKTIPS"/><category term="APACHE2_rewrite"/><category term="CHEATSHEETS_APACHE2"/><category term="CHEATSHEETS_SQL"/><category term="CSS3"/><category term="GIT"/><category term="PHP_porady"/><category term="SQL"/><category term="SQL_porady"/><category term="XML"/><category term="APACHE2_auth"/><category term="APACHE2_httpd"/><category term="CHEATSHEETS_CSS"/><category term="CHEATSHEETS_HTML"/><category term="CHEATSHEETS_HTTP"/><category term="CHEATSHEETS_REGEXP"/><category term="CHEATSHEETS_XML"/><category term="Doctrine"/><category term="PHP_wyrazenia_regularne"/><category term="PHP_zaawansowane"/><category term="SVN"/><category term="Smarty"/><category term="302"/><category term="AJAX"/><category term="APACHE2_vhosts"/><category term="CHEATSHEETS_AJAX"/><category term="CHEATSHEETS_DOCTRINE"/><category term="CHEATSHEETS_GIT"/><category term="CHEATSHEETS_JAVASCRIPT"/><category term="CHEATSHEETS_LINUX"/><category term="CHEATSHEETS_OTHER"/><category term="CHEATSHEETS_SMARTY"/><category term="CHEATSHEETS_SVN"/><category term="Composer"/><category term="FOLLOWLOCATION"/><category term="JSON"/><category term="JS_porady"/><category term="LINUX"/><category term="OTHER"/><category term="PHP_bezpieczenstwo"/><category term="Propel"/><category term="SOAP"/><category term="ZendFramework"/><category term="ciasteczka"/><category term="cookies"/><category term="curl_setopt"/><category term="follow"/><category term="google drive"/><category term="header"/><category term="hosting"/><category term="hostowanie"/><category term="instalacja"/><category term="location"/><category term="poradnik"/><category term="przekierowania"/><category term="repozytorium"/><category term="tutorial"/><title type='text'>PHP eVERYWHERE</title><subtitle type='html'>PHP5, SQL, HTML5, CSS3, XML, JSON, SOAP, Apache2 - artykuły, tutoriale, porady, praktyczne zastosowania.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default?start-index=26&amp;max-results=25'/><author><name>Marcin Szczygliński</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>96</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-1538721816456079164</id><published>2015-06-04T00:44:00.001+02:00</published><updated>2015-06-04T00:46:42.807+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JSON"/><category scheme="http://www.blogger.com/atom/ns#" term="XML_JSON_SOAP"/><title type='text'>[JSON] Podstawy i struktura formatu JSON</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-BSyKGf3ctGc/VWD0mbPZB1I/AAAAAAAAH8o/PfWVac3ynDk/s1600/icoJSON.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-BSyKGf3ctGc/VWD0mbPZB1I/AAAAAAAAH8o/PfWVac3ynDk/s1600/icoJSON.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;JSON to skrót od JavaScript Object Notation, w wolnym tłumaczeniu Notacja Obiektowa JavaScriptu. Jak sama nazwa wskazuje, format stanowi podzbiór języka JavaScript, w którym to służy on jako wewnętrzny język do opisywania obiektów. Nie ogranicza to bynajmniej pola, na którym można go stosować do samego tylko JavaScriptu, a wręcz przeciwnie - pomimo nazwy format ten jest używany powszechnie do wymiany danych we wszystkich praktycznie językach. Jest absolutnie niezależny od platformy, gdyż jego implementacja moze znaleźć się w praktycznie dowolnej aplikacji. Jest to zatem bardzo uniwersalny format, z powodzeniem wykorzystywany w celu wymiany danych pomiędzy aplikacjami. JSON jest bardzo lekkim formatem - jego składnia ograniczona jest do minimum, jest to wręcz banalnie prosty, tekstowy format, w którym poza samymi danymi stosuje się raptem kilka innych ograniczników, takich jak przecinek, czy nawiasy. Przez taki minimalizm jest on niestety trochę mniej czytelny dla człowieka, niż np. XML, ale za to nadrabia małym rozmiarem, gdyż nie posiada w sobie żadnych elementów takich jak znaczniki w XML-u. Warto znać JSON-a, gdyż jest on bardzo przydatny w wymianie danych, szczególnie sieciowych. W artykule tym omówimy podstawowe rzeczy, takie jak składnia, a w następnych artykułach zobaczymy jak pracować na danych z JSON-a w językach PHP i Javascript.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Podstawowe zasady&lt;/h2&gt;W JSON-ie obowiązuje kilka kluczowych reguł jakich należy się trzymać podczas tworzenia pliku JSON:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;każdy dokument powinien być kodowany w UTF-8&lt;/li&gt;&lt;li&gt;każdy dokument JSON musi zawierać się w głównym nawiasie klamrowym&lt;/li&gt;&lt;li&gt;każdy dokument musi zawierać jeden główny element, w którym zawiera się cała reszta&lt;/li&gt;&lt;li&gt;wszystkie nazwy elementów/kluczy i ich wartości objęte muszą być cudzysłowami&lt;/li&gt;&lt;li&gt;pary klucz-wartość oddzielamy dwukropkiem (klucz : wartość)&lt;/li&gt;&lt;li&gt;elementy występujące obok siebie oddzielamy przecinkiem&lt;/li&gt;&lt;li&gt;zawartość elementu obejmujemy w nawiasy klamrowe&lt;/li&gt;&lt;li&gt;tablice obejmujemy w nawiasy kwadratowe&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Struktura JSON-a&lt;/h2&gt;Każdy plik JSON musi zawierac się w jednym głównym nawiasie klamrowym, najprostszy, pusty dokument JSON wyglądać będzie więc tak:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;}[/code]&lt;br /&gt;Dodajmy teraz nazwę dla głównego elementu, który jest wymagany, niech to będzie np. &quot;rodzina&quot;:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;rodzina&quot;: {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;W JSON-ie każdą definicję obiektu/elementu, która zawierać będzie więcej niż jedno pole obejmujemy w nawias klamrowy.&lt;br /&gt;Dodajmy teraz jakiś element do naszego głównego elementu, niech to będzie np. pole o nazwie &quot;nazwa&quot;.&lt;br /&gt;W JSON-ie wartości dla danych pól podajemy na zasadzie:&lt;br /&gt;[code]&quot;klucz&quot; : &quot;wartość&quot;[/code]&lt;br /&gt;a w przypadku, gdy mamy do podania wartości kilku pól, to rodzielamy je przecinkiem:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&quot;klucz1&quot; : &quot;wartość1&quot;,&lt;br /&gt;&quot;klucz2&quot; : &quot;wartość2&quot;,&lt;br /&gt;&quot;klucz3&quot; : &quot;wartość3&quot;&lt;br /&gt;}[/code]&lt;br /&gt;Jak widzimy, w przypadku ilości większej, niż jedno pole całość obejmujemy w nawias klamrowy.&lt;br /&gt;Dodajmy teraz pole &quot;nazwa&quot; do naszego głównego elementu:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;rodzina&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;nazwa&quot; : &quot;Kowalscy&quot;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;Powyższy zapis w XML-u wyglądałby tak:&lt;br /&gt;&lt;h4&gt;XML:&lt;/h4&gt;[code]&lt;br /&gt;&amp;lt;rodzina&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;nazwa&amp;gt;Kowalscy&amp;lt;/nazwa&amp;gt;&lt;br /&gt;&amp;lt;/rodzina&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Teraz dodajmy kolejny element o nazwie &quot;dziadkowie&quot;:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;rodzina&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;nazwa&quot; : &quot;Kowalscy&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;dziadkowie&quot; : { &amp;nbsp; &lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;A w nim kolejny element o nazwie &quot;dziadek&quot; z polami:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;imie&lt;/li&gt;&lt;li&gt;nazwisko&lt;/li&gt;&lt;li&gt;oraz element &quot;dzieci&quot;, w którym znajdą się kolejne elementy:&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;rodzina&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;nazwa&quot; : &quot;Kowalscy&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;dziadkowie&quot; : { &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&quot;dziadek&quot; : {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;imie&quot; : &quot;Alojzy&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;nazwisko&quot; : &quot;Kowalski&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;dzieci&quot; : { &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;Powyższy zapis w XML-u wyglądałby tak:&lt;br /&gt;&lt;h4&gt;XML:&lt;/h4&gt;[code]&lt;br /&gt;&amp;lt;rodzina&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;nazwa&amp;gt;Kowalscy&amp;lt;/nazwa&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;dziadkowie&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;dziadek&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;imie&amp;gt;Alojzy&amp;lt;/imie&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;nazwisko&amp;gt;Kowalski&amp;lt;/nazwisko&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;dzieci&amp;gt; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/dzieci&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/dziadek&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/dziadkowie&amp;gt;&lt;br /&gt;&amp;lt;/rodzina&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;A w widoku drzewka wygląda to tak:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-4XZO0_rdces/VW-A1NUaE5I/AAAAAAAAIlY/nR-EHUzcmbo/s1600/d1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;536&quot; src=&quot;http://4.bp.blogspot.com/-4XZO0_rdces/VW-A1NUaE5I/AAAAAAAAIlY/nR-EHUzcmbo/s640/d1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak teraz dodać innego dziadka?&lt;br /&gt;Zrobienie tego w poniższy sposób będzie błędne:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;rodzina&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;nazwa&quot; : &quot;Kowalscy&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;dziadkowie&quot; : { &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;dziadek&quot; : {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;imie&quot; : &quot;Alojzy&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;nazwisko&quot; : &quot;Kowalski&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;dzieci&quot; : { &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;`},&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;dziadek&quot; : {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;imie&quot; : &quot;Alfred&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;nazwisko&quot; : &quot;Kowalski&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;dzieci&quot; : { &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; } &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; } &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;&lt;br /&gt;Otóż musimy naszych dziadków ująć w tablicę, a robimy to za pomocą nawiasów kwadratowych:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;rodzina&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;nazwa&quot; : &quot;Kowalscy&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;dziadkowie&quot; : [&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&quot;imie&quot; : &quot;Alojzy&quot;, &quot;nazwisko&quot; : &quot;Kowalski&quot;, &quot;dzieci&quot; : {} },&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&quot;imie&quot; : &quot;Albert&quot;, &quot;nazwisko&quot; : &quot;Kowalski&quot;, &quot;dzieci&quot; : {} }&lt;br /&gt;&amp;nbsp; &amp;nbsp; ] &amp;nbsp; &lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;&lt;br /&gt;Powyższy zapis w XML-u wyglądałby tak:&lt;br /&gt;&lt;h4&gt;XML:&lt;/h4&gt;[code]&lt;br /&gt;&amp;lt;rodzina&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;nazwa&amp;gt;Kowalscy&amp;lt;/nazwa&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;dziadkowie&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;dziadek&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;imie&amp;gt;Alojzy&amp;lt;/imie&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;nazwisko&amp;gt;Kowalski&amp;lt;/nazwisko&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;dzieci&amp;gt; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/dzieci&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/dziadek&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;dziadek&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;imie&amp;gt;Albert&amp;lt;/imie&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;nazwisko&amp;gt;Kowalski&amp;lt;/nazwisko&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;dzieci&amp;gt; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/dzieci&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/dziadek&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/dziadkowie&amp;gt;&lt;br /&gt;&amp;lt;/rodzina&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;A w widoku drzewka prezentuje się tak:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-2NV597Rw3fk/VW-A5QAEaqI/AAAAAAAAIlg/ok8FnBSV4t8/s1600/d2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://4.bp.blogspot.com/-2NV597Rw3fk/VW-A5QAEaqI/AAAAAAAAIlg/ok8FnBSV4t8/s640/d2.jpg&quot; width=&quot;540&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak więc widzimy elementy tablicowe umieszczamy w nawiasach kwadratowych, na zasadzie:&lt;br /&gt;[code]&lt;br /&gt;&quot;tablica&quot; : [&lt;br /&gt;&amp;nbsp; {&quot;elementA1&quot; : &quot;wartośćA1&quot;, &quot;elementA2&quot; : &quot;wartośćA2&quot;},&lt;br /&gt;&amp;nbsp; {&quot;elementB1&quot; : &quot;wartośćB1&quot;, &amp;nbsp;&quot;elementB2&quot; : &quot;wartośćB2&quot;},&lt;br /&gt;&amp;nbsp; &amp;nbsp;...&lt;br /&gt;][/code]&lt;br /&gt;&lt;br /&gt;Następnie dodać możemy kolejne zagnieżdżone elementy, jak &quot;ojcowie&quot;, &quot;synowie&quot;, &quot;wnukowie&quot; itd. Ale z tym już polecam poeksperymentować w ramach pracy domowej i pooglądać sobie wyniki swojej pracy na:&amp;nbsp;&lt;a href=&quot;http://codebeautify.org/jsonviewer&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://codebeautify.org/jsonviewer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Wykorzystanie JSON-a&lt;/h2&gt;JSON jest powszechnie wykorzystywany w komunikacji sieciowej. Dane przesyłane JSON-em są najzwyczajniej w świecie przesyłane szybciej, gdyż objętość dokumentu JSON jest mniejsza, niż dokumentu z tymi samymi danymi zapisanymi w formacie XML. Jest w związku z tym również szeroko stosowany podczas przesyania danych AJAX-em. JSON jest ponadto wewnętrznie wykorzystywany przez Javascript jako jego naturalny język zapisu obiektów. Praca z JSON-em jest wygodna zarówno po stronie Javascriptu, jak i PHP, gdzie możemy dowolnie wymieniać się danymi. Ponadto konwersja pomiędzy JSON-em, a XML-em jest dziecinnie prosta, tak samo jak serializacja i deserializacja obiektów i tablic robiona przy pomocy formatu JSON-a. W następnym artykule poznamy metody służące do pracy z tym formatem, zarówno w PHP, jak i w Javascripcie.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/1538721816456079164/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/json-podstawy-i-struktura-formatu-json.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1538721816456079164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1538721816456079164'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/json-podstawy-i-struktura-formatu-json.html' title='[JSON] Podstawy i struktura formatu JSON'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-BSyKGf3ctGc/VWD0mbPZB1I/AAAAAAAAH8o/PfWVac3ynDk/s72-c/icoJSON.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-4413385007819199716</id><published>2015-06-03T22:19:00.000+02:00</published><updated>2015-06-03T23:02:45.351+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="XML"/><category scheme="http://www.blogger.com/atom/ns#" term="XML_JSON_SOAP"/><title type='text'>[XML] Podstawy, składnia i przestrzenie nazw w XML</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-a-3Xg-G59xI/VWD04LtyHnI/AAAAAAAAH_Y/8l1ulyUG_Lk/s1600/icoXML.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-a-3Xg-G59xI/VWD04LtyHnI/AAAAAAAAH_Y/8l1ulyUG_Lk/s1600/icoXML.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;XML, czyli EXtensible Markup Language jest uniwersalnym językiem służącym do opisu danych przy pomocy znaczników. Od lat jest niekwestionowanym standardem jeżeli chodzi o zapisywanie zbiorów danych. Nie ma praktycznie języka, który nie posiadałby lub nie mógł posiadać implementacji XML-a. Czyni to XML-a językiem niesamowicie uniwersalnym, całkowicie niezależnym od danej platformy, architektury, czy rodzaju oprogramowania. Za pomocą XML-a komunikować się może praktycznie każdy z każdym i wszystko ze wszystkim, co jest zresztą powszechnie wykorzystywane - w końcu właśnie w tym celu ten język powstał. Kolejnym atutem XML-a jest jego prosta budowa oparta na znacznikach. Poza tym jest łatwiejszy w czytaniu dla człowieka niż np. JSON - nie stanowi żadnego problemu &quot;przeczytanie&quot; prostego dokumentu XML bez użycia żadnych parsujących narzędzi. W artykule tym po krótce omówimy sobie strukturę dokumentów XML, a w następnych artykułach przeanalizujemy tworzenie, odczyt i przetwarzanie dokumentów XML za pomocą PHP oraz Javascriptu.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Definicja standardu&lt;/h2&gt;Każdy dokument XML zaczynamy od definicji standardu XML dokumentu i podania kodowania znaków dla niego:&lt;br /&gt;[code]&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;[/code]&lt;br /&gt;Możemy pominąć podawanie tych parametrów, przyjęte zostaną wtedy wartości domyślne, takie jak powyżej, jednakże przyjęło się, że podajemy taką definicję na początku każdego dokumentu.&lt;br /&gt;&lt;br /&gt;Przykład prostego dokumentu XML&lt;br /&gt;[code]&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;books category=&quot;fantasy&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;book&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;title&amp;gt;Hobbit&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;author&amp;gt;J.R.R. Tolkien&amp;lt;/author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/book&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;book&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;title&amp;gt;Wieża Jaskółki&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;author&amp;gt;Andrzej Sapkowski&amp;lt;/author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/book&amp;gt;&lt;br /&gt;&amp;lt;/books&amp;gt;[/code]&lt;br /&gt;&lt;h2&gt;Znaczniki&lt;/h2&gt;Struktura dokumentu opiera się na znacznikach, w których opisujemy poszczególne elementy. Znacznik taki ma postać:&lt;br /&gt;[code]&amp;lt;znacznik&amp;gt;jakaś zawartość&amp;lt;/znacznik&amp;gt;[/code]&lt;br /&gt;Przykładowo, opisując tytuł książki, możemy opisać go znacznikiem:&lt;br /&gt;[code]&amp;lt;title&amp;gt;Pan Tadeusz&amp;lt;/title&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Każdy znacznik może posiadać atrybuty go opisujące, które definiujemy następująco:&lt;br /&gt;[code]&amp;lt;znacznik atrybut1=&quot;wartość1&quot; atrybut2=&quot;wartość2&quot; [...]&amp;gt;[/code]&lt;br /&gt;Przykładowo:&lt;br /&gt;[code]&amp;lt;person name=&quot;Jan Kowalski&quot; age=&quot;28&quot;&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Znaczniki można w sobie zagnieżdzać, tj. każdy znacznik może posiadać w sobie kolejne znaczniki. Mówimy wtedy, że znacznik położony wyżej jest rodzicem znacznika położonego niżej, a znacznik położony niżej w hierarchi jest dzieckiem znacznika, w którym się zawiera. Popatrzmy na przykład z książką:&lt;br /&gt;[code]&amp;lt;book&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;title&amp;gt;Pan Tadeusz&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;author&amp;gt;Adam Mickiewicz&amp;lt;/author&amp;gt;&lt;br /&gt;&amp;lt;/book&amp;gt;[/code]&lt;br /&gt;Znaczniki &amp;lt;title&amp;gt; i &amp;lt;author&amp;gt; są dziećmi znacznika &amp;lt;book&amp;gt; (zawierają się w nim), jednocześnie znacznik &amp;lt;book&amp;gt; jest tutaj ich rodzicem. Zagnieżdżać możemy oczywiście głębiej, popatrzmy na przykład:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;shop&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;books category=&quot;poemat&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;book&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;title&amp;gt;Pan Tadeusz&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;first_name&amp;gt;Adam&amp;lt;/first_name&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;last_name&amp;gt;Mickiewicz&amp;lt;/last_name&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/book&amp;gt; &lt;br /&gt;&amp;nbsp; &amp;lt;/books&amp;gt;&lt;br /&gt;&amp;lt;/shop&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Składnia i restrykcje&lt;/h2&gt;XML jest bardzo restrykcyjny jeśli chodzi o składnię:&lt;br /&gt;W każdym dokumencie musi istnieć jeden nadrzędny, główny znacznik, w którym zawierać się będą pozostałe.&lt;br /&gt;Znacznik główny nazywamy korzeniem (root). W przypadku powyżej takim root-em dokumentu jest &amp;lt;shop&amp;gt;&amp;lt;/shop&amp;gt;.&lt;br /&gt;&lt;br /&gt;Wszystkie znaczniki muszą zostać zamknięte w odpowiedniej kolejności - tak jak zostały otwarte.&lt;br /&gt;Przykład niepoprawny:&lt;br /&gt;[code]&amp;lt;books&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;book&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;title&amp;gt;Pan Tadeusz&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;author&amp;gt;Adam Mickiewicz&amp;lt;/author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/books&amp;gt;&lt;br /&gt;&amp;lt;/book&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Przykład poprawny:&lt;br /&gt;[code]&amp;lt;books&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;book&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;title&amp;gt;Pan Tadeusz&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;author&amp;gt;Adam Mickiewicz&amp;lt;/author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/book&amp;gt;&lt;br /&gt;&amp;lt;/books&amp;gt;[/code] &lt;br /&gt;&lt;br /&gt;Wszystkie puste znaczniki, a więc takie które nie posiadają znacznika zamykającego:&lt;br /&gt;[code]&amp;lt;znacznik&amp;gt;&amp;lt;/znacznik&amp;gt;[/code]&lt;br /&gt;muszą zostać domknięte za pomocą:&lt;br /&gt;[code]&amp;lt;znacznik /&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Nazwa znacznika może składać się ze znaków alfanumerycznych (litery a-z, A-Z, cyfry 0-9), nie powinna zawierać polskich znaków. W nazwie znacznika możemy użyć trzech znaków specjalnych:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;podkreślnika - &quot;&lt;b&gt;_&lt;/b&gt;&quot;&lt;/li&gt;&lt;li&gt;myślnika - &quot;&lt;b&gt;-&lt;/b&gt;&quot;&lt;/li&gt;&lt;li&gt;i kropki - &quot;&lt;b&gt;.&lt;/b&gt;&quot;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Pozostałe znaki specjalne są zabronione. Ponadto nazwa znacznika nie może rozpoczynać się od znaku specjalnego oraz od ciągu &quot;xml&quot;, &quot;XML&quot;, &quot;Xml&quot; i pozostałych konfiguracji słowa &quot;xml&quot;.&lt;br /&gt;&lt;br /&gt;Wszystkie znaczniki HTML ujęte pomiędzy znaczniki XML muszą zostać zamienione na encje.&lt;br /&gt;&lt;br /&gt;Nigdzie w dokumencie (poza otwieraniem i zamykaniem znaczników) nie wolno nam użyć znaków:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;&amp;lt;&lt;/b&gt; (lt)&lt;/li&gt;&lt;li&gt;&lt;b&gt;&amp;gt;&lt;/b&gt; (gt)&lt;/li&gt;&lt;li&gt;&lt;b&gt;&amp;amp;&lt;/b&gt; (ampersand)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Musimy zamienić je na encje:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;&amp;lt;&lt;/b&gt; na &amp;amp;lt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&amp;gt;&lt;/b&gt; na &amp;amp;gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&amp;amp;&lt;/b&gt; na &amp;amp;amp;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Wartości atrybutów podajemy zawsze w cudzysłowach lub apostrofach.&lt;br /&gt;&lt;br /&gt;Komentarze w dokumencie XML umieszczamy podobnie jak w HTML-u:&lt;br /&gt;[code]&amp;lt;!-- komentarz --&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Wszystko to co ma nie być przetwarzane przez parser XML umieszczamy w bloku:&lt;br /&gt;[code]&amp;lt;![CDATA[&lt;br /&gt;...&lt;br /&gt;]]&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Walidacja&lt;/h2&gt;Dokument XML przygotowany lub wygenerowany niepoprawnie nie zostanie sparsowany. W sieci istnieje cała masa stron oferujących sprawdzanie poprawności składni dokumentów XML, są to tzw. walidatory. Przykładowo jeden z nich: &lt;a href=&quot;https://validator.w3.org/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://validator.w3.org/&lt;/a&gt; - walidator oferuje możliwość sprawdzenia dokumentu XML po podaniu jego URL-a, pliku lokalnego lub dokumentu wklejonego bezpośrednio do formularza. A na tej stronie wygenerujemy sobie widok drzewka z dokumentu XML:&amp;nbsp;&lt;a href=&quot;http://codebeautify.org/xmlviewer&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://codebeautify.org/xmlviewer&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Przestrzenie nazw&lt;/h2&gt;Przestrzenie nazw (namespaces) zostały stworzone w celu zdefiniowania sposobu opisu znaczników, które mogą mieć różne znaczenie w zależności od typu elementu. Przykładowo - znacznik &amp;lt;title&amp;gt; może mieć jasno określone znaczenie dla danego typu elementu, ale dla innego typu może już oznaczać coś innego. Inny przykład: w jednym dokumencie może znaleźć się opis książki oraz opis faktury za nią. W obu przypadkach istnieć może znacznik &amp;lt;author&amp;gt;, tyle tylko, że w przypadku książki oznacza on autora książki, a w przypadku faktury osobę ją wystawiającą. Jak aplikacja przetwarzająca takiego XML-a ma teraz to odróżnić i nie stwierdzić, że osobą wystawiającą fakturę za &quot;Pana Tadeusza&quot; jest np. Adam Mickiewicz? Dlatego właśnie wprowadzono nazewnictwo oparte na przestrzeniach nazw. Kolejną korzyścią jest to, iż w jednym dokumencie możemy wykorzystać tyle przestrzeni ile tylko chcemy, tak więc przykładowy znacznik &amp;lt;title&amp;gt; wykorzystać możemy w jednym dokumencie w kilku różnych kontekstach - różnych dla każdej z przestrzeni nazw.&lt;br /&gt;&lt;br /&gt;Przestrzeń nazw z jakiej będziemy korzystać określamy za pomocą:&lt;br /&gt;[code]xmlns:PREFIX = &quot;URI_DO_SPECYFIKACJI&quot;[/code]&lt;br /&gt;&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;xmlns&lt;/b&gt; - to nazwa specjalnego atrybutu, którym określamy przestrzeń (xmlns to skrót od XML NameSpace)&lt;/li&gt;&lt;li&gt;&lt;b&gt;PREFIX&lt;/b&gt; - określa skróconą nazwę przestrzeni, czyli jej prefix, który dodawać będziemy później do znaczników&lt;/li&gt;&lt;li&gt;&lt;b&gt;URI_DO_SPECYFIKACJI&lt;/b&gt; - adres prowadzący do opisu danej przestrzeni nazw. W zasadzie może on nawet prowadzić do nikąd, choć wg zaleceń prowadzić powinien on do dokumentu opisującego daną przestrzeń.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Przykładowa definicja przestrzeni nazw:&lt;br /&gt;[code]&amp;lt;b:book xmlns:b=&quot;http://books.com/ns&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;b:author&amp;gt;Adam Mickiewicz&amp;lt;/b:author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;b:title&amp;gt;Pan Tadeusz&amp;lt;/b:title&amp;gt;&lt;br /&gt;&amp;lt;/b:book&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Jak widać korzystamy tutaj z trzech znaczników:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&amp;lt;book&amp;gt;&lt;/li&gt;&lt;li&gt;&amp;lt;author&amp;gt;&lt;/li&gt;&lt;li&gt;&amp;lt;title&amp;gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Każdy z nich deklarowany jest w przestrzeni nazw:&lt;br /&gt;[code]http://books.com/ns[/code]&lt;br /&gt;której skrótowym prefixem jest:&lt;br /&gt;[code]b[/code]&lt;br /&gt;&lt;br /&gt;Nazwę znacznika w danej przestrzeni definiujemy na zasadzie:&lt;br /&gt;[code]&amp;lt;PREFIX:ZNACZNIK&amp;gt;[/code]&lt;br /&gt;w naszym przykładzie:&lt;br /&gt;[code]&amp;lt;b:book&amp;gt;&lt;br /&gt;&amp;lt;b:author&amp;gt;&lt;br /&gt;&amp;lt;b:title&amp;gt;[/code]&lt;br /&gt;Należy tutaj pamiętać, że również i znaczniki zamykające muszą posiadać prefiksy przestrzeni nazw, o ile taki wystąpił w znaczniku otwierającym.&lt;br /&gt;&lt;br /&gt;Przestrzeń nazw obowiązuje od miejsca jej zadeklarowania, tak więc nie możemy najpierw użyć znaczników z danej przestrzeni, a dopiero później jej zadeklarować.&lt;br /&gt;Ponadto - przestrzeń nazw obowiązuje jedynie dla znacznika, w którym została określona oraz we wszystkich znacznikach w nim zawartych (bez względu na stopien zagnieżdżenia)&lt;br /&gt;Zdefiniowanie zatem przestrzeni w głównym elemencie dokumentu spowoduje, że przestrzeń będzie obowiązywać dla całego dokumentu, gdyż wszystkie pozostałe znaczniki się w nim zawierają.&lt;br /&gt;&lt;br /&gt;Można także stworzyć przestrzeń nazw domyślną dla wszystkich elementów zawierających.&lt;br /&gt;W przypadku takim nie musimy już podawać prefixa przestrzeni przy znacznikach dzieci.&lt;br /&gt;Deklaracja przestrzeni domyślnej odbywa się również bez podawania prefixu:&lt;br /&gt;Przykład:&lt;br /&gt;[code]&amp;lt;book xmlns=&quot;http://books.com/ns&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;author&amp;gt;Adam Mickiewicz&amp;lt;/author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;title&amp;gt;Pan Tadeusz&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;book&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;W powyższym przykładzie wszystkie znaczniki zawarte pomiędzy &amp;lt;book&amp;gt;&amp;lt;/book&amp;gt; znajdują się domyślnie w przestrzeni nazw &quot;http://books.com/ns&quot;.&lt;br /&gt;&lt;br /&gt;Przestrzenie nazw mogą również dotyczyć atrybutów:&lt;br /&gt;[code]&amp;lt;b:book xmlns:b=&quot;http://books.com/ns&quot; b:hardcover=&quot;yes&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;b:author&amp;gt;Adam Mickiewicz&amp;lt;/b:author&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;b:title&amp;gt;Pan Tadeusz&amp;lt;/b:title&amp;gt;&lt;br /&gt;&amp;lt;/b:book&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Jeśli dla danego znacznika nie jest zdefiniowana żadna przestrzeń nazw to mówimy, ze występuje on w domyślnej, globalnej przestrzeni nazw.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/4413385007819199716/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/xml-podstawy-skladnia-i-przestrzenie-nazw-w-xml.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/4413385007819199716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/4413385007819199716'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/xml-podstawy-skladnia-i-przestrzenie-nazw-w-xml.html' title='[XML] Podstawy, składnia i przestrzenie nazw w XML'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-a-3Xg-G59xI/VWD04LtyHnI/AAAAAAAAH_Y/8l1ulyUG_Lk/s72-c/icoXML.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-3045453951852043091</id><published>2015-06-03T18:58:00.000+02:00</published><updated>2015-06-03T18:58:20.236+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><category scheme="http://www.blogger.com/atom/ns#" term="Propel"/><title type='text'>[PHP][Propel] Instalacja oraz wstęp do Propel ORM</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-RL2ZZu9xBs0/VWD0x5LbtHI/AAAAAAAAH-M/vipxDtU9ndA/s1600/icoPHP_propel.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-RL2ZZu9xBs0/VWD0x5LbtHI/AAAAAAAAH-M/vipxDtU9ndA/s1600/icoPHP_propel.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Propel do biblioteka służąca do mapowania obiektowo-relacyjnego, w skrócie ORM. Podobnie jak biblioteka Doctrine sprawia on, że praca na bazie danych odbywa się za pomocą zwykłych obiektów. Jest odrobinę łatwiejszy w użyciu, niż Doctrine, co jednak nie znaczy, że jest gorszy. Praca z obiema bibliotekami jest w zasadzie podobna, opiera się ona na przygotowaniu schematu bazy danych, wygenerowaniu odpowiednich metod dla modelu, a następnie na pracy na modelu jak na zwykłych obiektach. Propela, podobnie jak Doctrine możemy w prosty sposób połączyć z popularnymi frameworkami, jak Zend, czy Symfony - integracja taka zostanie tutaj opisana w którymś z artykułów. W poniższym natomiast artykule pobierzemy i zainstalujemy sobie bibliotekę Propela, skonfigurujemy ją, uruchomimy, a następnie przygotujemy prosty, testowy model bazy i zobaczymy jak to mniej więcej działa. Artykuł przedstawia procedurę w systemach Windows, na Linuxach jednak wszystko (poza oczywiście innymi ścieżkami) wygląda podobnie.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Instalacja Propel ORM&lt;/h2&gt;Oficjalna strona Propela to: &lt;a href=&quot;http://propelorm.org/&quot; target=&quot;_blank&quot;&gt;http://propelorm.org&lt;/a&gt;. &lt;br /&gt;Samego Propela pobierzemy sobie za pomocą Composera, przygotowując plik &quot;composer.json&quot; w odpowiednim katalogu dla naszego projektu. Na potrzeby artykułu niech będzie to katalog:&lt;br /&gt;[code]C:/www/propel[/code]&lt;br /&gt;(na screenach będzie to u mnie c:/wamp/www/propel/)&lt;br /&gt;W stworzonym katalogu utwórzmy plik &quot;composer.json&quot; o treści:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;propel/propel&quot;: &quot;~2.0@dev&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;zapiszmy, a następnie będąc w utworzonym katalogu zainstalujmy z poziomu terminala:&lt;br /&gt;[code]&lt;br /&gt;$ cd c:/www/propel&lt;br /&gt;$ composer install[/code]&lt;br /&gt;Pobierze to nam najnowszą wersję Propela z gałęzi 2.x.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-yIZ_hhj4f2Y/VW8shF80ylI/AAAAAAAAIkQ/3SpZvB3qbD4/s1600/c1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;592&quot; src=&quot;http://2.bp.blogspot.com/-yIZ_hhj4f2Y/VW8shF80ylI/AAAAAAAAIkQ/3SpZvB3qbD4/s640/c1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Możemy też pobrać za pomocą Gita:&lt;br /&gt;[code]&lt;br /&gt;$ cd c:/www&lt;br /&gt;$ git clone git://github.com/propelorm/Propel2.git propel[/code]&lt;br /&gt;&lt;br /&gt;lub zwyczajnie pobrać plik .zip lub .tar.gz ze strony projektu i rozpakować do c:/www/propel. Ja polecam jednak metodę z Composerem.&lt;br /&gt;&lt;br /&gt;Propel wraz z biblioteką zainstaluje nam małe narzędzie konsolowe w katalogu:&lt;br /&gt;[code]/vendor/bin[/code]&lt;br /&gt;które posłuży nam później do zautomatyzowania wielu operacji.&lt;br /&gt;Jeśli chcemy później korzystać z polecenia propel bez podawania ścieżki, dodajmy ten folder do zmiennej PATH w Windowsie.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Pierwszy projekt&lt;/h2&gt;Możemu już zainicjować swój pierwszy projekt i możemy to zrobić na dwa sposoby: ręcznie, lub za pomocą narzędzia konsolowego, które lekko nam ten proces zautomatyzuje.&lt;br /&gt;&lt;br /&gt;Pół automatycznie zrobimy to za pomocą:&lt;br /&gt;[code]$ propel init[/code]&lt;br /&gt;My jednak omówmy sobie ręczne przygotowanie Propela.&lt;br /&gt;&lt;h4&gt;Testowa baza&lt;/h4&gt;Dobrze byłoby abyśmy na starcie mieli conajmniej dwie tabele, tak aby pokazać definicję kluczy obcych, zrobimy więc podobną strukturę jak w dokumentacji Propela, czyli sklep z książkami. Nasza testowa baza będzie mieć nazwę &quot;shop&quot; i składać się będzie z dwóch prostych tabel:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;book&lt;/li&gt;&lt;li&gt;author&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Tabela:&lt;/strong&gt; book &lt;br /&gt;&lt;table border=&quot;0&quot; style=&quot;width: 100%px;&quot;&gt;  &lt;tbody&gt;&lt;tr&gt;    &lt;th scope=&quot;col&quot;&gt;Nazwa pola&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Typ&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Dodatkowe&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Klucz obcy&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Opis&lt;/th&gt;  &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;id&lt;/td&gt;    &lt;td&gt;integer&lt;/td&gt;    &lt;td&gt;&lt;strong&gt;PRIMARY KEY&lt;/strong&gt;, AUTO_INCREMENT&lt;em&gt;, NOT NULL&lt;/em&gt;&lt;/td&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;ID książki&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;title&lt;/td&gt;    &lt;td&gt;varchar(255)&lt;/td&gt;    &lt;td&gt;&lt;em&gt;NOT NULL&lt;/em&gt;&lt;/td&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;tytuł książki&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;author_id&lt;/td&gt;    &lt;td&gt;integer&lt;/td&gt;    &lt;td&gt;&lt;em&gt;NOT NULL&lt;/em&gt;&lt;/td&gt;    &lt;td&gt;author.id&lt;/td&gt;    &lt;td&gt;ID autora&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;price&lt;/td&gt;    &lt;td&gt;integer&lt;/td&gt;    &lt;td&gt;&lt;em&gt;NOT NULL&lt;/em&gt;&lt;/td&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;cena książki&lt;/td&gt;  &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Tabela:&lt;/strong&gt; author  &lt;br /&gt;&lt;table border=&quot;0&quot; style=&quot;width: 100%px;&quot;&gt;  &lt;tbody&gt;&lt;tr&gt;    &lt;th scope=&quot;col&quot;&gt;Nazwa pola&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Typ&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Dodatkowe&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Klucz obcy&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;Opis&lt;/th&gt;  &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;id&lt;/td&gt;    &lt;td&gt;integer&lt;/td&gt;    &lt;td&gt;&lt;strong&gt;PRIMARY KEY&lt;/strong&gt;, AUTO_INCREMENT&lt;em&gt;, NOT NULL&lt;/em&gt;&lt;/td&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;ID autora&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;first_name&lt;/td&gt;    &lt;td&gt;varchar(100)&lt;/td&gt;    &lt;td&gt;&lt;em&gt;NOT NULL&lt;/em&gt;&lt;/td&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;imię autora&lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;last_name&lt;/td&gt;    &lt;td&gt;varchar(100)&lt;/td&gt;    &lt;td&gt;&lt;em&gt;NOT NULL&lt;/em&gt;&lt;/td&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;nazwisko autora&lt;/td&gt;  &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt;Uwaga: bazy na razie nie tworzymy, wyobraźmy sobie jedynie jej strukturę.&lt;/b&gt;&lt;br /&gt;&lt;h2&gt;Schemat bazy - schema.xml&lt;/h2&gt;Na początek utworzyć musimy opis struktury naszej bazy w pliku:&lt;br /&gt;[code]schema.xml[/code]&lt;br /&gt;Plik ten zapisujemy w katalogu głównym naszego projektu, czyli w naszym przypadku w:&lt;br /&gt;[code]c:/www/propel/[/code]&lt;br /&gt;&lt;br /&gt;Jak już widać po rozszerzeniu, opis naszej bazy przygotowywać będziemy w języku XML.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;1) &amp;lt;database&amp;gt;&lt;/h4&gt;Głównym tagiem w pliku XML musi być zawsze tag &amp;lt;database&amp;gt;, a w jego atrybutach powinniśmy podać nazwę naszej bazy oraz sposób w jaki będą inkrementowane wartości w polach typu &quot;auto increment&quot;. Domyślnie jest to &quot;native&quot;, co oznacza mniej więcej tyle, iż zajmie się tym automatycznie już sama baza.&lt;br /&gt;[code]&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;database name=&quot;shop&quot; defaultIdMethod=&quot;native&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;!-- tutaj następnie definicje tabel --&amp;gt;&lt;br /&gt;&amp;lt;/database&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;2) &amp;lt;table&amp;gt;&lt;/h4&gt;Następnie zdefiniować musimy tabele w naszej bazie. Każda tabela musi zostać objęta tagiem &amp;lt;table&amp;gt; a w jej atrybutach musimy podać jej nazwę oraz opjonalnie nazwę klasy dla niej używaną przez Propela, o ile chcemy, aby była inna niż prawdziwa nazwa tabeli. Jeśli nie zdefiniujemy atrybutu &quot;phpName&quot; to Propel automatycznie wykorzysta nazwę tabeli, wykorzystując zapis camelCase, tj. klasa dla tabeli &quot;book&quot; otrzymałaby automatycznie nazwę &quot;Book&quot;, a np. klasa dla tabeli &quot;user_config&quot; otrzymała by nazwę &quot;UserConfig&quot; - zgodnie z zapisem formatu camelCase.&lt;br /&gt;[code]&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;database name=&quot;shop&quot; defaultIdMethod=&quot;native&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;table name=&quot;book&quot; phpName=&quot;Book&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!-- tutaj następnie definicje pól/komun --&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;table name=&quot;author&quot; phpName=&quot;Author&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!-- tutaj następnie definicje pól/komun --&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br /&gt;&amp;lt;/database&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;3) &amp;lt;column&amp;gt;&lt;/h4&gt;Mamy już definicję bazy i tabel, pora zdefiniować kolumny w tabelach. Robimy to za pomocą znaczników &amp;lt;column&amp;gt;, podając następujące atrybuty:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;name&lt;/b&gt; - nazwa kolumny, np. &quot;title&quot;&lt;/li&gt;&lt;li&gt;&lt;b&gt;type&lt;/b&gt; - typ kolumny, np. &quot;varchar&quot;&lt;/li&gt;&lt;li&gt;&lt;b&gt;size&lt;/b&gt; - długość pola, np &quot;120&quot; dla varchar&lt;/li&gt;&lt;li&gt;&lt;b&gt;required &lt;/b&gt;- czy pole jest wymagane, np. &quot;true&quot;&lt;/li&gt;&lt;li&gt;&lt;b&gt;autoIncrement &lt;/b&gt;- czy pole jest typu &quot;AUTO INCREMENT&quot;, np. &quot;true&quot;&lt;/li&gt;&lt;li&gt;&lt;b&gt;primaryKey &lt;/b&gt;- czy pole posiada klucz podstawowy, np. &quot;true&quot;&lt;/li&gt;&lt;li&gt;&lt;b&gt;phpName &lt;/b&gt;- analogicznie jak przy nazwie tabeli, możemy podać nazwę pod jaką bedzie dane pole deniniował Propel&lt;/li&gt;&lt;/ul&gt;Schemat naszej bazy będzie więc w tej chwili wyglądać tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;database name=&quot;shop&quot; defaultIdMethod=&quot;native&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;table name=&quot;book&quot; phpName=&quot;Book&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;id&quot; type=&quot;integer&quot; required=&quot;true&quot; primaryKey=&quot;true&quot; autoIncrement=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;title&quot; type=&quot;varchar&quot; size=&quot;255&quot; required=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;author_id&quot; type=&quot;integer&quot; required=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;price&quot; type=&quot;integer&quot; required=&quot;true&quot; /&amp;gt; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;table name=&quot;author&quot; phpName=&quot;Author&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;id&quot; type=&quot;integer&quot; required=&quot;true&quot; primaryKey=&quot;true&quot; autoIncrement=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;first_name&quot; type=&quot;varchar&quot; size=&quot;100&quot; required=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;last_name&quot; type=&quot;varchar&quot; size=&quot;100&quot; required=&quot;true&quot; /&amp;gt; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br /&gt;&amp;lt;/database&amp;gt;[/code]&lt;br /&gt;Ważna sprawa: zawsze pamiętajmy w XML-u o zamykaniu znaczników, które nie mają taga zamykającego za pomocą:&lt;br /&gt;[code]/&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Klucze obce&lt;/h4&gt;Zdefiniować musimy jeszcze klucze obce dla poszczególnych tabel, dokonujemy tego za pomocą taga:&lt;br /&gt;[code]&amp;lt;foreign-key&amp;gt;[/code]&lt;br /&gt;któremu w atrybutach podajemy:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;foreignTable &lt;/b&gt;- nazwę obcej tabeli&lt;/li&gt;&lt;li&gt;&lt;b&gt;phpName&lt;/b&gt; - opcjonalnie własną nazwę dla relacji, jeśli nie podana, to Propel przypisze tu nazwę z obcej tabeli&lt;/li&gt;&lt;li&gt;&lt;b&gt;refPhpName&lt;/b&gt; - opcjonalnie własną nazwę dla relacji, ale widzianą przez obcą tabelę&lt;/li&gt;&lt;/ul&gt;Przykladowo - nasza tabela &quot;book&quot; zawiera jeden klucz obcy, a jest nim pole &quot;author_id&quot;. Relacja prowadzi do tabeli &quot;author&quot; i jej pola &quot;id&quot;. Aby teraz zdefiniować relację z tabelą &quot;author&quot;, wpiszemy dla tabeli &quot;book&quot; taką definicję:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;foreign-key foreignTable=&quot;author&quot; phpName=&quot;Author&quot; refPhpName=&quot;Book&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;!-- tutaj podajemy definicje kolumn --&amp;gt;&lt;br /&gt;&amp;lt;/foreign-key&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Powyższe określa nam relację z obcą tabelą, musimy teraz jeszcze podać jakich kolumn te relacje dotyczą, robimy to za pomocą taga:&lt;br /&gt;[code]&amp;lt;reference&amp;gt;[/code]&lt;br /&gt;jako atrybuty podając mu:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;local &lt;/b&gt;- nazwę pola z obecnej tabeli&lt;/li&gt;&lt;li&gt;&lt;b&gt;foreign&lt;/b&gt; - nazwę pola z tabeli obcej&lt;/li&gt;&lt;/ul&gt;Przykladowo - nasza tabela &quot;book&quot; zawiera jeden klucz obcy, a jest nim pole &quot;author_id&quot;.&lt;br /&gt;Aby teraz zdefiniować relację z tabelą &quot;author&quot; i jej polem &quot;id&quot;, wpiszemy dla tabeli &quot;book&quot; taką definicję:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;foreign-key foreignTable=&quot;author&quot; phpName=&quot;Author&quot; refPhpName=&quot;Book&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;reference local=&quot;author_id&quot; foreign=&quot;id&quot; /&amp;gt;&lt;br /&gt;&amp;lt;/foreign-key&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Oczywiście dla każdej tabeli możemy podać wiele relacji, użyjemy wtedy kilku tagów &amp;lt;reference&amp;gt;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;Finalnie schemat naszej bazy wygląda tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;br /&gt;&amp;lt;database name=&quot;shop&quot; defaultIdMethod=&quot;native&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;table name=&quot;book&quot; phpName=&quot;Book&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;id&quot; type=&quot;integer&quot; required=&quot;true&quot; primaryKey=&quot;true&quot; autoIncrement=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;title&quot; type=&quot;varchar&quot; size=&quot;255&quot; required=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;author_id&quot; type=&quot;integer&quot; required=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;price&quot; type=&quot;integer&quot; required=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;foreign-key foreignTable=&quot;author&quot; phpName=&quot;Author&quot; refPhpName=&quot;Book&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;reference local=&quot;author_id&quot; foreign=&quot;id&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/foreign-key&amp;gt; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;table name=&quot;author&quot; phpName=&quot;Author&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;id&quot; type=&quot;integer&quot; required=&quot;true&quot; primaryKey=&quot;true&quot; autoIncrement=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;first_name&quot; type=&quot;varchar&quot; size=&quot;100&quot; required=&quot;true&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;column name=&quot;last_name&quot; type=&quot;varchar&quot; size=&quot;100&quot; required=&quot;true&quot; /&amp;gt; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;lt;/table&amp;gt;&lt;br /&gt;&amp;lt;/database&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Zapiszmy więc taki powyższy schemat do pliku:&lt;br /&gt;[code]schema.xml[/code]&lt;br /&gt;Mamy w tym momencie gotowy schemat naszej bazy danych, pora teraz na utworzenie dla niej modelu.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Konfiguracja&lt;/h2&gt;Musimy teraz przygotować model dla naszej bazy, czyli wygenerować wszystkie niezbędne klasy, które będą ją opisywały w postaci obiektów, a także wszelkie niezbędne metody, jak gettery i settery, które pozwolą nam na pobieranie i ustawianie wartości pól. Propel zrobi to za nas automatycznie, nie będziemy więc musieli tworzyć klas ręcznie. Na podstawie definicji pobranej ze stworzonego schematu sam wygeneruje odpowiednie klasy i metody. Musimy jednak dokonać małej konfiguracji, podać parametry połączenia itp.&lt;br /&gt;Plik z konfiguracją dla Propela powinien mieć nazwę &quot;propel&quot; oraz rozszerzenie odpowiednie dla języka, w którym został napisany, czyli:&lt;br /&gt;[code]propel.php, propel.xml, propel.json lub propel.yaml[/code]&lt;br /&gt;i powinien zostać umieszczony w tym samym katalogu co plik ze schematem, czyli &quot;schema.xml&quot;.&lt;br /&gt;Może zostać również umieszczony w podfolderze &quot;/config&quot; lub &quot;/conf&quot;. My na razie umieśćmy go w naszym katalogu głównym, obok pliku &quot;schema.xml&quot;.&lt;br /&gt;Plik z konfiguracją, jak już wspomniałem wyżej przygotować możemy w jednym z 4 języków:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;PHP&lt;/li&gt;&lt;li&gt;XML&lt;/li&gt;&lt;li&gt;JSON&lt;/li&gt;&lt;li&gt;YAML&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Wybór jest dowolny, jednak najczęściej używanym formatem jest YAML, ze względu na swoją prościutką i miłą dla oka składnię. Konfiguracja jest dość rozbudowana i opisana w pełni w dokumentacji Propela, jednakże nie musimy na razie w nią wnikać, gdyż domyślnie Propel wymaga podania jedynie kluczowych informacji, dotyczących nazwy bazy i parametrów naszego połączenia z bazą. Jak pamiętamy, naszą bazę nazwaliśmy w schemacie:&lt;br /&gt;[code]shop[/code]&lt;br /&gt;Stwórzmy więc teraz plik z konfiguracją dla bazy &quot;shop&quot;.&lt;br /&gt;W języku YAML będzie miał on taką postać:&lt;br /&gt;[code]&lt;br /&gt;# propel.yaml&lt;br /&gt;propel:&lt;br /&gt;&amp;nbsp; database:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; connections:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; shop:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; adapter: mysql&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; classname: Propel\Runtime\Connection\ConnectionWrapper&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dsn: &quot;mysql:host=localhost;dbname=nazwa_bazy&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; user: nazwa_użytkownika_bazy&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; password: hasło_użytkownika_bazy&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; attributes:&lt;br /&gt;&amp;nbsp; runtime:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; defaultConnection: shop&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; connections:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - shop&lt;br /&gt;&amp;nbsp; generator:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; defaultConnection: shop&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; connections:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - shop[/code]&lt;br /&gt;gdzie oczywiście w pola:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;host - podajemy adres serwera bazy&lt;/li&gt;&lt;li&gt;mysql - tutaj podajemy nazwę adaptera, w przykładzie podałem MySQL&lt;/li&gt;&lt;li&gt;nazwa_bazy - nazwa naszej bazy&lt;/li&gt;&lt;li&gt;nazwa_użytkownika_bazy - nazwa użytkownika&lt;/li&gt;&lt;li&gt;hasło_użytkownika_bazy - i jego hasło&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Plik taki zapisujemy jako:&lt;br /&gt;[code]propel.yaml[/code]&lt;br /&gt;Więcej o konfiguracji przeczytacie tutaj: &lt;a href=&quot;http://propelorm.org/documentation/10-configuration.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://propelorm.org/documentation/10-configuration.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Generowanie SQL&lt;/h2&gt;Mamy już dwa pliki:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;schema.xml &lt;/b&gt;- czyli schemat bazy&lt;/li&gt;&lt;li&gt;&lt;b&gt;propel.yaml&lt;/b&gt; - konfigurację bazy&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Musimy więc teraz wygenerować zapytanie SQL, które zbuduje nam tabele w bazie na podstawie podanego przez nas schematu. Do wygenerowania takiego zapytania użyjemy oferowanego z Propelem narzędzia:&lt;br /&gt;[code]/vendor/bin/propel[/code]&lt;br /&gt;Wejdźmy teraz w terminalu do katalogu z naszym projektem:&lt;br /&gt;[code]$ cd c:/www/propel[/code]&lt;br /&gt;I wykonajmy następujące polecenie:&lt;br /&gt;[code]$ propel sql:build[/code]&lt;br /&gt;lub&lt;br /&gt;[code]$ &quot;/vendor/bin/propel&quot; sql:build[/code]&lt;br /&gt;jeśli nie dodaliśmy katalogu /vendor/bin do zmiennej PATH w Windowsie.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-LgMaLHBFPj8/VW8srDgc3WI/AAAAAAAAIkY/GcGgQ5AuFGw/s1600/c2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;192&quot; src=&quot;http://3.bp.blogspot.com/-LgMaLHBFPj8/VW8srDgc3WI/AAAAAAAAIkY/GcGgQ5AuFGw/s640/c2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Narzędzie to utworzyło nam katalog:&lt;br /&gt;[code]/generated_sql[/code]&lt;br /&gt;A w nim 2 pliki:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;shop.sql&lt;/li&gt;&lt;li&gt;sqldb.map&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Spójrzmy teraz na zawartość pliku &quot;shop.sql&quot;:&lt;br /&gt;[code]&lt;br /&gt;# This is a fix for InnoDB in MySQL &amp;gt;= 4.1.x&lt;br /&gt;# It &quot;suspends judgement&quot; for fkey relationships until are tables are set.&lt;br /&gt;SET FOREIGN_KEY_CHECKS = 0;&lt;br /&gt;&lt;br /&gt;-- ---------------------------------------------------------------------&lt;br /&gt;-- book&lt;br /&gt;-- ---------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;DROP TABLE IF EXISTS `book`;&lt;br /&gt;&lt;br /&gt;CREATE TABLE `book`&lt;br /&gt;(&lt;br /&gt;&amp;nbsp; &amp;nbsp; `id` INTEGER NOT NULL AUTO_INCREMENT,&lt;br /&gt;&amp;nbsp; &amp;nbsp; `title` VARCHAR(255) NOT NULL,&lt;br /&gt;&amp;nbsp; &amp;nbsp; `author_id` INTEGER NOT NULL,&lt;br /&gt;&amp;nbsp; &amp;nbsp; `price` INTEGER NOT NULL,&lt;br /&gt;&amp;nbsp; &amp;nbsp; PRIMARY KEY (`id`),&lt;br /&gt;&amp;nbsp; &amp;nbsp; INDEX `book_fi_ea464c` (`author_id`),&lt;br /&gt;&amp;nbsp; &amp;nbsp; CONSTRAINT `book_fk_ea464c`&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; FOREIGN KEY (`author_id`)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; REFERENCES `author` (`id`)&lt;br /&gt;) ENGINE=InnoDB;&lt;br /&gt;&lt;br /&gt;-- ---------------------------------------------------------------------&lt;br /&gt;-- author&lt;br /&gt;-- ---------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;DROP TABLE IF EXISTS `author`;&lt;br /&gt;&lt;br /&gt;CREATE TABLE `author`&lt;br /&gt;(&lt;br /&gt;&amp;nbsp; &amp;nbsp; `id` INTEGER NOT NULL AUTO_INCREMENT,&lt;br /&gt;&amp;nbsp; &amp;nbsp; `first_name` VARCHAR(100) NOT NULL,&lt;br /&gt;&amp;nbsp; &amp;nbsp; `last_name` VARCHAR(100) NOT NULL,&lt;br /&gt;&amp;nbsp; &amp;nbsp; PRIMARY KEY (`id`)&lt;br /&gt;) ENGINE=InnoDB;&lt;br /&gt;&lt;br /&gt;# This restores the fkey checks, after having unset them earlier&lt;br /&gt;SET FOREIGN_KEY_CHECKS = 1;[/code]&lt;br /&gt;&lt;br /&gt;Jak widzimy wygenerowaliśmy pełne zapytanie SQL służace do utworzenia tabel w bazie.&lt;br /&gt;&lt;br /&gt;Uwaga: każde ponowne użycie polecenia:&lt;br /&gt;[code]$ propel sql:build[/code]&lt;br /&gt;tworzy te zapytanie na nowo, więc musimy je wywołać przy każdej modyfikacji schematu bazy.&lt;br /&gt;Pora teraz na wygenerowanie klas dla modelu.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Generowanie klas modelu&lt;/h2&gt;Do wygenerowania wszystkich niezbędnych klas dla naszego modelu ponownie użyjemy polecenia &quot;propel&quot;.&lt;br /&gt;Wpiszmy teraz w terminalu:&lt;br /&gt;[code]$ propel model:build[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-xT1nmMOL1ok/VW8swXnFtsI/AAAAAAAAIkg/F_6lLeVW_xE/s1600/c3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;192&quot; src=&quot;http://3.bp.blogspot.com/-xT1nmMOL1ok/VW8swXnFtsI/AAAAAAAAIkg/F_6lLeVW_xE/s640/c3.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Wygenerowało to nam katalog:&lt;br /&gt;[code]/generated-classes[/code]&lt;br /&gt;A w nim wszystkie wymagane klasy niezbędne do pracy z naszymi tabelami:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-1YMKtDdQnFs/VW8s0P1nWzI/AAAAAAAAIko/1Upa92yw-K8/s1600/w1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;178&quot; src=&quot;http://1.bp.blogspot.com/-1YMKtDdQnFs/VW8s0P1nWzI/AAAAAAAAIko/1Upa92yw-K8/s640/w1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Propel utworzył nam 3 rodzaje klas:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;klasę modelu&lt;/b&gt;, np. Book, która reprezentuje wiersz z tabeli jako obiekt&lt;/li&gt;&lt;li&gt;&lt;b&gt;klasę zapytań&lt;/b&gt;, np. BookQuery, która zawiera definicje metod slużacych do operacji na wierszach/obiektach&lt;/li&gt;&lt;li&gt;&lt;b&gt;klasę mapowania&lt;/b&gt;, np. Map/BookTableMap, która zawiera metody statyczne służace do operowania na wierszu/obiekcie&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Uwaga: każde ponowne użycie polecenia:&lt;/b&gt;&lt;br /&gt;[code]$ propel model:build[/code]&lt;br /&gt;tworzy te klasy na nowo, więc musimy je wywołać przy każdej modyfikacji schematu bazy. Nie należy też w tych klasach umieszczać swojego kodu, gdyż ten przepadnie po kolejnym generowaniu modelu.&lt;br /&gt;&lt;br /&gt;Mamy już gotowe klasy modelu, musimy je teraz dołączyć do autoloadera, tak aby były dostępne w naszym kodzie. Zmodyfikujmy więc plik &quot;composer.json&quot; znajdujący się w katalogu głównym, tak aby wyglądał następująco:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;propel/propel&quot;: &quot;~2.0@dev&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; }, &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;autoload&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;classmap&quot;: [&quot;generated-classes/&quot;]&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;Następnie zaktualizujmy Composera:&lt;br /&gt;[code]$ composer update[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-gpGAxbQGunw/VW8s5IkbqRI/AAAAAAAAIkw/IpyQjOsmoLU/s1600/c4.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;192&quot; src=&quot;http://1.bp.blogspot.com/-gpGAxbQGunw/VW8s5IkbqRI/AAAAAAAAIkw/IpyQjOsmoLU/s640/c4.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Sprawi to, że przebudujemy autoloader Composera, co za tym idzie, nasze klasy modelu zawarte w katalogu:&lt;br /&gt;[code]/generated-classes[/code]&lt;br /&gt;będą ładowane automatyczne jeśli skorzystamy z autoloadera wygenerowanego przez Composera.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Plik konfiguracyjny&lt;/h2&gt;Musimy teraz wygenerować plik z domyślną konfiguracją dla połączenia z bazą danych.&lt;br /&gt;Poprzednio podaliśmy konfigurację w języku YAML, użyjemy teraz polecenia Propela, które na podstawie tego pliku przygotuje nam plik PHP z konfiguracją, który dołączymy do swojego projektu:&lt;br /&gt;&lt;br /&gt;[code]$ propel config:convert[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-f2PnBz6c_rQ/VW8s9PZaVJI/AAAAAAAAIk4/sc_LyZcLXxo/s1600/c5.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;192&quot; src=&quot;http://1.bp.blogspot.com/-f2PnBz6c_rQ/VW8s9PZaVJI/AAAAAAAAIk4/sc_LyZcLXxo/s640/c5.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Polecenie utworzyło nam katalog:&lt;br /&gt;[code]/generated-conf[/code]&lt;br /&gt;a w nim plik:&lt;br /&gt;[code]config.php[/code]&lt;br /&gt;&lt;br /&gt;o treści:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$serviceContainer = \Propel\Runtime\Propel::getServiceContainer();&lt;br /&gt;$serviceContainer-&amp;gt;checkVersion(&#39;2.0.0-dev&#39;);&lt;br /&gt;$serviceContainer-&amp;gt;setAdapterClass(&#39;shop&#39;, &#39;mysql&#39;);&lt;br /&gt;$manager = new \Propel\Runtime\Connection\ConnectionManagerSingle();&lt;br /&gt;$manager-&amp;gt;setConfiguration(array (&lt;br /&gt;&amp;nbsp; &#39;classname&#39; =&amp;gt; &#39;Propel\\Runtime\\Connection\\ConnectionWrapper&#39;,&lt;br /&gt;&amp;nbsp; &#39;dsn&#39; =&amp;gt; &#39;mysql:host=localhost;dbname=NAZWA_BAZY&#39;,&lt;br /&gt;&amp;nbsp; &#39;user&#39; =&amp;gt; &#39;UŻYTKOWNIK&#39;,&lt;br /&gt;&amp;nbsp; &#39;password&#39; =&amp;gt; &#39;HASŁO&#39;,&lt;br /&gt;&amp;nbsp; &#39;attributes&#39; =&amp;gt;&lt;br /&gt;&amp;nbsp; array (&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;ATTR_EMULATE_PREPARES&#39; =&amp;gt; false,&lt;br /&gt;&amp;nbsp; ),&lt;br /&gt;));&lt;br /&gt;$manager-&amp;gt;setName(&#39;shop&#39;);&lt;br /&gt;$serviceContainer-&amp;gt;setConnectionManager(&#39;shop&#39;, $manager);&lt;br /&gt;$serviceContainer-&amp;gt;setDefaultDatasource(&#39;shop&#39;);[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Utworzenie tabeli w bazie&lt;/h2&gt;Przyszła pora na utworzenie naszych opisanych w schemacie tabel w bazie.&lt;br /&gt;Jak pamiętamy, Propel utworzył nam do tego zapytanie SQL, aby teraz wykonać to zapytanie z poziomu Propela, użyjemy polecenia:&lt;br /&gt;&lt;br /&gt;[code]$ propel sql:insert[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-3mWE8-iUn5k/VW8tBez31FI/AAAAAAAAIlA/eh8vWrD0PNQ/s1600/c6.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;192&quot; src=&quot;http://3.bp.blogspot.com/-3mWE8-iUn5k/VW8tBez31FI/AAAAAAAAIlA/eh8vWrD0PNQ/s640/c6.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Utworzyło to nam odpowiednie tabele w bazie danych, co możemy sprawdzić np. za pomocą PHPMyAdmina.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Testujemy&lt;/h2&gt;Pozostało nam teraz sprawdzenie działania Propela w praktyce.&lt;br /&gt;Utwórzmy sobie w głównym folderze naszego projektu plik testowy, np.:&lt;br /&gt;[code]test.php[/code]&lt;br /&gt;w którym przetestujemy Propela.&lt;br /&gt;&lt;br /&gt;Na początek musimy dołączyć autoloader oraz plik z konfiguracją dla Propela:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// test.php&lt;br /&gt;// dołączamy autoloader Composera&lt;br /&gt;require_once __DIR__.&#39;/vendor/autoload.php&#39;;&lt;br /&gt;&lt;br /&gt;// dołączamy plik z konfiguracją&lt;br /&gt;require_once __DIR__.&#39;/generated-conf/config.php&#39;;&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Dodajemy nowy &lt;strike&gt;rekord&lt;/strike&gt; obiekt&lt;/h4&gt;Napiszmy teraz prosty kod dodający do bazy nowego autora:&lt;br /&gt;[code]&lt;br /&gt;$author = new Author();&lt;br /&gt;$author-&amp;gt;setFirstName(&#39;Adam&#39;);&lt;br /&gt;$author-&amp;gt;setLastName(&#39;Mickiewicz&#39;);&lt;br /&gt;$book-&amp;gt;save();[/code]&lt;br /&gt;&lt;br /&gt;Nasz plik &quot;test.php&quot; wyglądać więc będzie w całości tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// test.php&lt;br /&gt;// dołączamy autoloader Composera&lt;br /&gt;require_once __DIR__.&#39;/vendor/autoload.php&#39;;&lt;br /&gt;&lt;br /&gt;// dołączamy plik z konfiguracją&lt;br /&gt;require_once __DIR__.&#39;/generated-conf/config.php&#39;;&lt;br /&gt;&lt;br /&gt;// tworzymy nowego autora&lt;br /&gt;$author = new Author();&lt;br /&gt;&lt;br /&gt;// ustawiamy imię i nazwisko&lt;br /&gt;$author-&amp;gt;setFirstName(&#39;Adam&#39;);&lt;br /&gt;$author-&amp;gt;setLastName(&#39;Mickiewicz&#39;);&lt;br /&gt;&lt;br /&gt;// zapisujemy&lt;br /&gt;if($author-&amp;gt;save())&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; echo &#39;Dodano autora o id: &#39;.$author-&amp;gt;getId();&lt;br /&gt;}&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Wejdźmy teraz na:&lt;br /&gt;[code]http://localhost/propel/test.php[/code]&lt;br /&gt;i zobaczmy, czy wszystko działa:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-dlILtcKeuuE/VW8tHv0suBI/AAAAAAAAIlI/pSX3bfHtUZU/s1600/w2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;178&quot; src=&quot;http://3.bp.blogspot.com/-dlILtcKeuuE/VW8tHv0suBI/AAAAAAAAIlI/pSX3bfHtUZU/s640/w2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Voila! Dodaliśmy nowego autora do bazy za pomocą Propela.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Podsumowanie&lt;/h2&gt;Jak widzimy, utworzenie nowego rekordu sprowadza się teraz do prostego utworzenia obiektu i wywołania metody &quot;save()&quot;. I to tyle tytułem wstępu, w kolejnych artykułach nauczymy się korzystać z Propela, pobierać i aktualizować rekordy, obsługiwać relacje itd. Na chwilę obecną potrafimy już przygotować schemat bazy, zbudować prosty model oraz wiemy jak to wszystko mniej więcej działa, więc na wstęp i wprowadzenie powinno nam wystarczyć.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/3045453951852043091/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/php-propel-instalacja-oraz-wstep-do-propel-orm.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3045453951852043091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3045453951852043091'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/php-propel-instalacja-oraz-wstep-do-propel-orm.html' title='[PHP][Propel] Instalacja oraz wstęp do Propel ORM'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-RL2ZZu9xBs0/VWD0x5LbtHI/AAAAAAAAH-M/vipxDtU9ndA/s72-c/icoPHP_propel.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-1487821199145981101</id><published>2015-06-02T21:02:00.000+02:00</published><updated>2015-06-02T21:10:41.982+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><category scheme="http://www.blogger.com/atom/ns#" term="ZendFramework"/><title type='text'>[PHP][Zend2] Instalacja i podstawy frameworka Zend2</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-2gfoQxf4E4Q/VWD00HYKJlI/AAAAAAAAH-k/l4c2W7_cfg0/s1600/icoPHP_zend.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-2gfoQxf4E4Q/VWD00HYKJlI/AAAAAAAAH-k/l4c2W7_cfg0/s1600/icoPHP_zend.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Zend to jeden z najpopularniejszych i najprzyjemniejszych w użyciu frameworków do PHP. Jest bardzo rozbudowanym środowiskiem, a mimo tego jego nauka nie stwarza większych problemów (jak to czasem może mieć miejsce w przypadku Symfony). Posiada bardzo obszerną dokumentację oraz niesamowicie rozbudowaną społeczność swoich użytkowników, jest więc prawie pewne, że napotykając na dany problem zawsze znajdziemy jakieś rozwiązanie, czy wskazówkę. Za pomocą Zenda stworzyć można praktycznie każdą aplikację webową, zawiera on w sobie bardzo domyślnych komponentów, zaczynając od absolutnie podstawowych, na bardziej wyspecjalizowanych skończywszy. Obecnie rozwijana jest wersja 2 frameworka, a za niedługo światło dzienne ujrzy wersja trzecia. Tutaj zajmiemy się właśnie tą drugą wersją i w cyklu artykułów nauczymy się krok po kroku pisania aplikacji za pomocą frameworka Zend. Na samym początku, podobnie jak w większości artykułów tutaj - cykl tutoriali zaczynamy od opisu instalacji, wstępu i podstawowej konfiguracji środowiska. Zaczynamy więc.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;Instalacja&lt;/h2&gt;Oficjalną stronę frameworka i sam framework do pobrania znajdziemy pod adresem: &lt;a href=&quot;http://framework.zend.com/&quot; target=&quot;_blank&quot;&gt;http://framework.zend.com&lt;/a&gt;, znajduje się tam także obszerna dokumentacja wraz z całą masą przykładów, z którą warto się oczywiście zapoznać. Zainstalować można Zenda na kilka sposobów i z kilku źródeł, my pobierzemy sobie archiwum ze szkieletem aplikacji, ale możemy też pobrać &quot;czystą&quot; wersję w postaci archium .zip ze strony, lub z GitHUB-a: &lt;a href=&quot;https://github.com/zendframework/zf2&quot; target=&quot;_blank&quot;&gt;https://github.com/zendframework/zf2&lt;/a&gt;.&lt;br /&gt;Instalując natomiast Zenda za pomocą Composera - &lt;a href=&quot;http://framework.zend.com/downloads/composer&quot; target=&quot;_blank&quot;&gt;http://framework.zend.com/downloads/composer&lt;/a&gt; - możemy wybrać sobie pakiety jakie chcemy wraz z Zendem zainstalować.&lt;br /&gt;My pobierzemy sobie wersję z aplikacją testową z GitHUB-a, a następnie zainstalujemy ją za pomocą Composera.&lt;br /&gt;&lt;br /&gt;Pobierzmy teraz instalkę Zenda z GitHuba którymś z poniższych sposobów:&lt;br /&gt;1) albo klonując repozytorium:&lt;br /&gt;[code]$ cd C:/www/&lt;br /&gt;$ git clone git://github.com/zendframework/ZendSkeletonApplication.git zend[/code]&lt;br /&gt;2) albo jako archiwum .zip: &lt;a href=&quot;https://github.com/zendframework/ZendSkeletonApplication/archive/master.zip&quot; target=&quot;_blank&quot;&gt;https://github.com/zendframework/ZendSkeletonApplication/archive/master.zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;W drugim przypadku rozpakujmy sobie pliki, np. do folderu:&lt;br /&gt;[code]C:/www/zend[/code]&lt;br /&gt;lub oczywiście gdziekolwiek indziej, na screenach będzie to u mnie &quot;c:/wamp/www/zend&quot;, jednakże dla przykładu będę podawał tutaj &quot;c:/www/zend/&quot;.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-FTvUJ48A528/VW37PdB_onI/AAAAAAAAIiw/aSaT-rp9o1w/s1600/c1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;374&quot; src=&quot;http://1.bp.blogspot.com/-FTvUJ48A528/VW37PdB_onI/AAAAAAAAIiw/aSaT-rp9o1w/s640/c1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Mając już pobrane lub rozpakiwane pliki, uruchomimy teraz Composera.&lt;br /&gt;Wchodzimy z poziomu terminalu do katalogu z Zendem i wykonujemy polecenie:&lt;br /&gt;[code]$ composer install[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-Pec-ka3ykQk/VW37WK50r2I/AAAAAAAAIi4/y8Wiqh_C1NU/s1600/c2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;316&quot; src=&quot;http://3.bp.blogspot.com/-Pec-ka3ykQk/VW37WK50r2I/AAAAAAAAIi4/y8Wiqh_C1NU/s640/c2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Zend doinstaluje sobie kilka bibliotek i będzie już gotowy do pracy.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Vhost&lt;/h2&gt;Następnym krokiem będzie utworzenie vhosta wskazującego na katalog:&lt;br /&gt;[code]/public[/code]&lt;br /&gt;w katalogu z Zendem, czyli w naszym przykładzie:&lt;br /&gt;[code]c:/www/zend/public[/code]&lt;br /&gt;Jest to ważne, gdyż tylko folder /public będziemy udostępniać poprzez WWW. Cała reszta kodu i katalogów będzie z tego poziomu niedostępna. Jak stworzyć vhosta w Apache&#39;u - opisałem krok po kroku w &lt;a href=&quot;http://phpeverywhere.blogspot.com/2015/05/apache-jak-stworzyc-i-skonfigurowac-wirtualnego-hosta.html&quot; target=&quot;_blank&quot;&gt;tym artykule&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tworzymy zatem vhosta wskazującego na katalog /public i nazywamy go np.:&lt;br /&gt;[code]zend.localhost[/code]&lt;br /&gt;&lt;br /&gt;Gdy mamy już vhosta wchodzimy na niego, aby sprawdzić, czy Zend zainstalowany został poprawnie.&lt;br /&gt;Jeśli wszystko poszło zgodnie z planem, powinniśmy zobaczyć coś mniej więcej takiego:&lt;br /&gt;[code]http://zend.localhost/[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-bkzsCK_QqLc/VW3-3wgwE4I/AAAAAAAAIj8/ZkL9d33MYUE/s1600/w1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;418&quot; src=&quot;http://1.bp.blogspot.com/-bkzsCK_QqLc/VW3-3wgwE4I/AAAAAAAAIj8/ZkL9d33MYUE/s640/w1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Struktura katalogów frameworka&lt;/h2&gt;Przyjrzyjmy się teraz strukturze katalogów z aplikacją Zenda:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-9bb_bR2o6tU/VW37f0d5AoI/AAAAAAAAIjA/O1B57ZUAKsY/s1600/w2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;468&quot; src=&quot;http://2.bp.blogspot.com/-9bb_bR2o6tU/VW37f0d5AoI/AAAAAAAAIjA/O1B57ZUAKsY/s640/w2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;config&lt;/b&gt; - zawiera globalne pliki konfiguracyjne&lt;/li&gt;&lt;li&gt;&lt;b&gt;data&lt;/b&gt; - zawierać będzie inne pliki, takie jak cache, upload, logi&lt;/li&gt;&lt;li&gt;&lt;b&gt;module&lt;/b&gt; - najważniejsza część naszej aplikacji, z definicjami naszych kontrolerów, modeli, widoków itd.&lt;/li&gt;&lt;li&gt;&lt;b&gt;public&lt;/b&gt; - folder publiczny dostępny z poziomu WWW, css, pliki js itp.&lt;/li&gt;&lt;li&gt;&lt;b&gt;vendor&lt;/b&gt; - zewnętrzne biblioteki, m.in. główne biblioteki frameworka Zend&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Moduły, kontrolery, akcje&lt;/h2&gt;Najważniejszym dla nas katalogiem będzie /module. To właśnie w nim będziemy trzymać kod naszych kontrolerów, ustawienia, widoki i generalnie całą strukturę naszej aplikacji. Jak widzimy tutaj, w Zendzie każda aplikacja składa się z tzw. modułów. Moduły z koleji składają się z kontrolerów i ich akcji. Naszym głównym modułem może być więc ta część aplikacji, która jest dostępna użytkownikom (front-end), a kolejnym modułem może być sekcja administracyjna dostępna tylko dla administratora (back-end). Z koleji każdy z tych modułów może składać się z wielu kontrolerów, z czego każdy będzie oddzielną sekcją, np. jeden kontroler odpowiedzialny za obsługę użytkowników, inny za obsługę komentarzy na stronie, jeszcze inny za artykuły it. Kontrolery z koleji mogą być podzielone na akcje takie jak: dodaj, edytuj, wyświetl itd.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-EJ2HVai0K7E/VW37mVZb06I/AAAAAAAAIjI/t7fUQk2ceGM/s1600/w3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;226&quot; src=&quot;http://4.bp.blogspot.com/-EJ2HVai0K7E/VW37mVZb06I/AAAAAAAAIjI/t7fUQk2ceGM/s640/w3.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Na przykładzie tej szkieletowej aplikacji widzimy, że:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;aplikacja składa się z jednego modułu o nazwie Application:&lt;br /&gt;&lt;i&gt;/module/Application&lt;/i&gt;&lt;/li&gt;&lt;li&gt;moduł Application składa się z jednego domyślnego kontrolera o nazwie IndexController:&lt;br /&gt;&lt;i&gt;/module/Application/src/Application/Controller/IndexController.php&lt;/i&gt;&lt;/li&gt;&lt;li&gt;kontroler IndexController składa się z jednej domyślnej akcji: indexAction:&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;[code]&lt;br /&gt;public function indexAction()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; return new ViewModel();&lt;br /&gt;}[/code]&lt;br /&gt;&lt;br /&gt;Kontroler &quot;Index&quot; powinien być zawsze domyślnym kontrolerem w module, natomiast akcja &quot;index&quot; domyślną akcją w kontrolerze.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Routing&lt;/h2&gt;Do poszczególnych kontrolerów i ich akcji dostajemy się w Zendzie na zasadzie:&lt;br /&gt;[code]http://nasza_aplikacja.com/moduł/kontroler/akcja[/code]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Przykładowo:&lt;/b&gt;&lt;br /&gt;[code]http://zend.localhost/application/index/index[/code]&lt;br /&gt;zwróci nam akcję &quot;index&quot; z kontrolera &quot;index&quot; z modułu &quot;application&quot;.&lt;br /&gt;Identyczne działanie będzie mieć wpisanie adresu:&lt;br /&gt;[code]http://zend.localhost/application/index[/code]&lt;br /&gt;gdzie jak widać podaliśmy jedynie nazwę modułu i kontrolera bez podania akcji, a mimo to wyświetliła nam się akcja &quot;index&quot;. Stało się tak, ponieważ akcja &quot;index&quot; jest tutaj akcją domyślną i wywołuje się automatycznie, gdy nie podamy tutaj żadnej innej akcji w wywołaniu. Analogicznie ma się sprawa z kontrolerem:&lt;br /&gt;[code]http://zend.localhost/application[/code]&lt;br /&gt;wywoła kontroler &quot;index&quot; z akcją &quot;index&quot;, gdyż kontroler &quot;index&quot; jest tutaj kontrolerem domyślnym.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Konfiguracja modułu - module.config.php&lt;/h2&gt;Domyślny kontroler i domyślną akcję możemy zmienić w głównym pliku konfiguracyjnym naszego modułu:&lt;br /&gt;[code]/module/application/config/module.config.php[/code]&lt;br /&gt;&lt;br /&gt;Otwórzmy sobie ten plik.&lt;br /&gt;Jak widzimy główna konfiguracja modułu składa się z tablicy:&lt;br /&gt;[code]&lt;br /&gt;array(&lt;br /&gt;&quot;router&quot; =&amp;gt; opcje,&lt;br /&gt;&quot;service_manager&quot; =&amp;gt; opcje,&lt;br /&gt;&quot;translator&quot; =&amp;gt; opcje,&lt;br /&gt;&quot;controllers&quot; =&amp;gt; opcje,&lt;br /&gt;&quot;view_manager&quot; =&amp;gt; opcje,&lt;br /&gt;&quot;console&quot; =&amp;gt; opcje&lt;br /&gt;)[/code]&lt;br /&gt;Poszczególne sekcje konfiguracji omówimy sobie w kolejnych artykułach.&lt;br /&gt;&lt;br /&gt;Zobaczmy teraz jak wygląda plik z definicją kontrolera:&lt;br /&gt;[code]/module/Application/src/Application/Controller/IndexController.php[/code]&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;namespace Application\Controller;&lt;br /&gt;&lt;br /&gt;use Zend\Mvc\Controller\AbstractActionController;&lt;br /&gt;use Zend\View\Model\ViewModel;&lt;br /&gt;&lt;br /&gt;class IndexController extends AbstractActionController&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; public function indexAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return new ViewModel();&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tworzymy własną akcję&lt;/h2&gt;Dodajmy do kontrolera Index nową akcję, np. o nazwie &quot;hello&quot;:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;namespace Application\Controller;&lt;br /&gt;&lt;br /&gt;use Zend\Mvc\Controller\AbstractActionController;&lt;br /&gt;use Zend\View\Model\ViewModel;&lt;br /&gt;&lt;br /&gt;class IndexController extends AbstractActionController&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; public function indexAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return new ViewModel();&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; // nowa akcja&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;public function helloAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return new ViewModel();&lt;br /&gt;&amp;nbsp; &amp;nbsp; } &amp;nbsp; &lt;br /&gt;}[/code]&lt;br /&gt;Zapiszmy plik i zobaczmy co się stanie po wejściu w adres:&lt;br /&gt;[code]http://zend.localhost/application/index/hello[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-Qyxj8g13_Qo/VW37uta0DcI/AAAAAAAAIjQ/oNwpapgy8LM/s1600/w4.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;520&quot; src=&quot;http://3.bp.blogspot.com/-Qyxj8g13_Qo/VW37uta0DcI/AAAAAAAAIjQ/oNwpapgy8LM/s640/w4.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać otrzymamy błąd i załadowany zostanie widok określony w pliku:&lt;br /&gt;[code]/module/application/config/module.config.php[/code]&lt;br /&gt;w sekcji:&lt;br /&gt;[code]&lt;br /&gt;&amp;nbsp;&#39;template_map&#39; =&amp;gt; array(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;layout/layout&#39; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; =&amp;gt; __DIR__ . &#39;/../view/layout/layout.phtml&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;application/index/index&#39; =&amp;gt; __DIR__ . &#39;/../view/application/index/index.phtml&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;error/404&#39; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; =&amp;gt; __DIR__ . &#39;/../view/error/404.phtml&#39;, &amp;nbsp;// &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; nasz widok z błędem&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;error/index&#39; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; =&amp;gt; __DIR__ . &#39;/../view/error/index.phtml&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ),[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Warstwa widoku&lt;/h2&gt;Aby przejść dalej opowiedzmy sobie o widokach.&lt;br /&gt;Pliki naszego widoku przechowywane są w formie plików:&lt;br /&gt;[code].phtml[/code]&lt;br /&gt;w katalogu:&lt;br /&gt;[code]/module/Application/view/[/code]&lt;br /&gt;&lt;br /&gt;Głównym plikiem widoku jest &quot;layout.phtml&quot;.&lt;br /&gt;To dopiero do layoutu dołączane są pozostałe widoki jakie określamy dla danych akcji.&lt;br /&gt;Widoki dołączane są do layoutu w miejscu wystąpienia:&lt;br /&gt;[code]&amp;lt;?php echo $this-&amp;gt;content; ?&amp;gt;[/code]&lt;br /&gt;Rozwiązanie takie pozwala nam na modularną budowę widoków dla naszej aplikacji.&lt;br /&gt;Utwórzmy teraz widok dla akcji, którą dodaliśmy akapit wyżej. Stwórzmy plik:&lt;br /&gt;[code]/module/Application/view/application/index/hello.phtml[/code]&lt;br /&gt;i wpiszmy w nim jako zawartość:&lt;br /&gt;[code]&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;[/code]&lt;br /&gt;Nastepnie ponownie spróbujmy wywołać akcję &quot;hello&quot;:&lt;br /&gt;[code]http://zend.localhost/application/index/hello[/code]&lt;br /&gt;Jak widzimy nasza akcja została wywołana z naszym nowym widokiem:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-cfAAiU1JPso/VW37z5nYY1I/AAAAAAAAIjY/dud50rsEzns/s1600/w5.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;336&quot; src=&quot;http://2.bp.blogspot.com/-cfAAiU1JPso/VW37z5nYY1I/AAAAAAAAIjY/dud50rsEzns/s640/w5.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tworzymy własny kontroler&lt;/h2&gt;Umiemy już dodawać akcję do kontrolera, w takim razie dodajmy teraz całkowicie nowy kontroler, np. o nazwie &quot;Users&quot;. Utwórzmy plik z definicją nowego kontrolera:&lt;br /&gt;[code]/module/Application/src/Application/Controller/UsersController.php[/code]&lt;br /&gt;o treści:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;namespace Application\Controller;&lt;br /&gt;&lt;br /&gt;use Zend\Mvc\Controller\AbstractActionController;&lt;br /&gt;use Zend\View\Model\ViewModel;&lt;br /&gt;&lt;br /&gt;class UsersController extends AbstractActionController&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; public function indexAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return new ViewModel();&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;public function profileAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return new ViewModel();&lt;br /&gt;&amp;nbsp; &amp;nbsp; } &amp;nbsp; &lt;br /&gt;&amp;nbsp; &lt;br /&gt;}[/code]&lt;br /&gt;Nasz nowy kontroler będzie posiadał dwie akcje:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;index&lt;/b&gt; - akcję domyślną wyświetlającą np. listę użytkowników&lt;/li&gt;&lt;li&gt;&lt;b&gt;profile&lt;/b&gt; - akcję wyświetlającą profil danego użytkownika&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Następnie utwórzmy folder z widokami dla nowego kontrolera:&lt;br /&gt;[code]/module/Application/view/application/users/[/code]&lt;br /&gt;a w nim dwa pliki z widokami, po jednym dla każdej z akcji:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1) /module/Application/view/application/users/index.phtml &lt;/b&gt;o treści:&lt;br /&gt;[code]&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;h2&amp;gt;index - lista userów&amp;lt;/h2&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2)&lt;/b&gt; &lt;b&gt;/module/Application/view/application/users/profile.phtml &lt;/b&gt;o treści:&lt;br /&gt;[code]&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;h2&amp;gt;profile - profil usera&amp;lt;/h2&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Mamy już plik z definicją klasy naszego kontrolera oraz 2 pliki z widokami dla jego akcji.&lt;br /&gt;Czas sprawdzić, co nam się wyświetli po wywołaniu naszego nowego kontrolera:&lt;br /&gt;[code]http://zend.localhost/application/users[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-fWgj1NDj7Gg/VW376ovAEpI/AAAAAAAAIjg/bkayRi0SsE4/s1600/w6.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;348&quot; src=&quot;http://4.bp.blogspot.com/-fWgj1NDj7Gg/VW376ovAEpI/AAAAAAAAIjg/bkayRi0SsE4/s640/w6.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Niestety, ale wyświetlił nam się błąd. Dlaczego?&lt;br /&gt;Ponieważ pomimo, iż mamy gotowe pliki dla kontrolera i widoku, to taki kontroler nie został dodany w konfiguracji modułu. Musimy więc tego dokonać.&lt;br /&gt;Otwórzmy więc plik z konfiguracją:&lt;br /&gt;[code]/module/application/config/module.config.php[/code]&lt;br /&gt;&lt;br /&gt;i w sekcji:&lt;br /&gt;[code]&lt;br /&gt;&#39;controllers&#39; =&amp;gt; array(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;invokables&#39; =&amp;gt; array(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;Application\Controller\Index&#39; =&amp;gt; &#39;Application\Controller\IndexController&#39; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ),&lt;br /&gt;&amp;nbsp; &amp;nbsp; ),[/code]&lt;br /&gt;dodajmy nasz nowy kontroler: &lt;br /&gt;[code]&lt;br /&gt;&#39;controllers&#39; =&amp;gt; array(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;invokables&#39; =&amp;gt; array(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;Application\Controller\Index&#39; =&amp;gt; &#39;Application\Controller\IndexController&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &#39;Application\Controller\Users&#39; =&amp;gt; &#39;Application\Controller\UsersController&#39; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ),&lt;br /&gt;&amp;nbsp; &amp;nbsp; ),[/code]&lt;br /&gt;Zapiszmy plik z konfiguracją i sprawdźmy teraz:&lt;br /&gt;[code]http://zend.localhost/application/users[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-whO7dG9TPE8/VW38ErjrcaI/AAAAAAAAIjw/mOiBGTpdAqc/s1600/w7.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;358&quot; src=&quot;http://2.bp.blogspot.com/-whO7dG9TPE8/VW38ErjrcaI/AAAAAAAAIjw/mOiBGTpdAqc/s640/w7.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Bingo! Nasz kontroler działa.&lt;br /&gt;Sprawdźmy jeszcze akcję dla wyświetlania profilu:&lt;br /&gt;[code]http://zend.localhost/application/users/profile[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-2-QlGJxJEQM/VW38AGlKKlI/AAAAAAAAIjo/1UtxPgTLk7I/s1600/w8.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;390&quot; src=&quot;http://1.bp.blogspot.com/-2-QlGJxJEQM/VW38AGlKKlI/AAAAAAAAIjo/1UtxPgTLk7I/s640/w8.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I znowu bingo! Nasza druga akcja również się wyświetliła.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Podsumowanie&lt;/h2&gt;Na chwilę obecną umiemy więc już dodać swój własny kontroler i akcję i myślę, że to powinno wystarczyć tytułem wprowadzenia. W kolejnych artykułach będziemy działać dalej.&lt;br /&gt;Mam nadzieję, że wszystko opisałem tutaj jasno i zrozumiale. Tak na marginesie - jak chyba widać Zend jest bardzo intuicyjny do opanowania i o wiele łatwiejszy w użyciu, niż np. również opisywany na tej stronie framework Symfony. Stąd też taka mała sugestia dla początkujących - jeśli dopiero zaczynamy przygodę z frameworkami, to najlepiej zacząć ją właśnie od Zenda, niż brać się od razu za wielkie i skomplikowane Symfony. I to tyle na teraz, do następnego!</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/1487821199145981101/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/php-zend2-instalacja-i-podstawy-frameworka-zend2.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1487821199145981101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1487821199145981101'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/php-zend2-instalacja-i-podstawy-frameworka-zend2.html' title='[PHP][Zend2] Instalacja i podstawy frameworka Zend2'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-2gfoQxf4E4Q/VWD00HYKJlI/AAAAAAAAH-k/l4c2W7_cfg0/s72-c/icoPHP_zend.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-821936260844612134</id><published>2015-06-02T16:12:00.000+02:00</published><updated>2015-06-02T21:40:28.604+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><category scheme="http://www.blogger.com/atom/ns#" term="Symfony2"/><title type='text'>[PHP][Symfony2] Instalacja i pierwsze uruchomienie Symfony2 krok po kroku</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-cIiR9TsX2uA/VWD0zTR_qhI/AAAAAAAAH-Y/3jsAbSP5rMA/s1600/icoPHP_symfony.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-cIiR9TsX2uA/VWD0zTR_qhI/AAAAAAAAH-Y/3jsAbSP5rMA/s1600/icoPHP_symfony.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Framework Symfony to jeden z najpotężniejszych frameworków napisanych dla PHP. Jest to też zarazem jeden z najpopularniejszych frameworków na świecie, warto byłoby zatem znać choćby jego podstawy. Nie jest to jednak framework łatwy w nauce, a na początku jego ogrom może nieco przytłaczać. Wszystko jednak można opanować i w cyklu artykułów tutaj postaramy się nauczyć pracy z Symfony krok po kroku. Będziemy używać wersji z gałęzi 2.x.x, gdyż wprowadza ona niesamowicie dużą ilość ilość zmian w stosunku do swoich starszych wersji, tj. wersji Legacy z gałęzi 1.x.x. Zasadniczą różnicą powiędzy wersjami 1 i 2 jest wprowadzenie zupełnie innej architektury w tej drugiej, opartej na mechaniźmie tzw. komponentów, o których oczywiście nauczymy się tutaj. Zacznijmy zatem pracę z Symfony2 i na początek pobiermy, zainstalujmy, uruchomijmy i skonfigurujmy swoje pierwsze środowisko oparte na Symfony2. Opiszę procedurę dla systemów z rodziny Windows, zakładając, że mamy zainstalowany i działający serwer Apache. Pierwsze uruchomienie Symfony dla osób nieznających tego frameworka jest nieco problematyczne, więc opiszę wszystko dokładnie krok po kroku.&lt;br /&gt;&lt;br /&gt;Przygodę rozpoczynamy od oficjalnej strony frameworka, która znajduje się pod adresem: &lt;a href=&quot;http://www.symfony.com/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.symfony.com&lt;/a&gt;.&amp;nbsp;Znajdziemy tutaj informacje o najnowszej wersji, przejrzymy bazę komponentów i uzyskamy dostęp do całej dokumentacji, a ta jest naprawdę obszerna. Istnieje również polska wersja dokumentacji, dostępna pod adresem: &lt;a href=&quot;http://symfony-docs.pl/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://symfony-docs.pl/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;Instalacja Symfony2&lt;/h2&gt;Stwórzmy więc sobie katalog na naszą instalację Symfony, np.:&lt;br /&gt;[code]C:/www/symfony[/code]&lt;br /&gt;(będę tutaj używał takiego katalogu dla przykładu, na screenach będzie to u mnie c:/www.wamp/www/symfony)&lt;br /&gt;&lt;br /&gt;Wejdźmy teraz do naszego utworzonego katalogu z poziomu konsoli i pobierzmy małą aplikację dla Symfony, która będzie nam służyła do zarządzania projektem, wpiszmy w konsoli:&lt;br /&gt;[code]$ php -r &quot;readfile(&#39;http://symfony.com/installer&#39;);&quot; &amp;gt; symfony[/code]&lt;br /&gt;W tym miejscu do naszego katalogu powinien pobrać się plik &quot;symfony&quot;, którego teraz użyjemy do inicjalizacji pierwszego projektu:&lt;br /&gt;[code]$ php symfony new myApp[/code]&lt;br /&gt;Pobierze nam to teraz cały pakiet Symfony2 i zainicjuje nasz projekt o nazwie &quot;myApp&quot;.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-CCCFuSCOh1o/VW22mEI4FWI/AAAAAAAAIhQ/71zgs-6qQow/s1600/c1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;428&quot; src=&quot;http://1.bp.blogspot.com/-CCCFuSCOh1o/VW22mEI4FWI/AAAAAAAAIhQ/71zgs-6qQow/s640/c1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Dla naszej aplikacji został utworzony katalog &quot;/myApp&quot;, a w nim następująca struktura folderów:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-Q8qQzufyH9M/VW22rTv1KNI/AAAAAAAAIhY/8-Gx9sQXdgA/s1600/w1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;206&quot; src=&quot;http://1.bp.blogspot.com/-Q8qQzufyH9M/VW22rTv1KNI/AAAAAAAAIhY/8-Gx9sQXdgA/s640/w1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Teraz musimy się na chwilę zatrzymać i omówić sobie strukturę katalogów w symfony.&lt;br /&gt;Po pierwsze - głównym folderem dostępnym przez WWW (document rootem naszej aplikacji) będzie:&lt;br /&gt;[code]/web[/code]&lt;br /&gt;Do naszej aplikacji będziemy więc dostawać się tak:&lt;br /&gt;[code]http://localhost/symfony/myApp/web[/code]&lt;br /&gt;jednakże tutaj pojawia się mała sprawa, gdyż jedynie ten folder powinien być dostępny publicznie, wszelkie pozostałe katalogi powinny być z poziomu WWW niedostępne.&lt;br /&gt;Uczynić to możemy za pomocą ustawienia sobie vhosta kierującego na katalog &quot;/web&quot; z naszym projektem. O tym jak utworzyć vhosta w Apache&#39;u pisałem &lt;a href=&quot;http://phpeverywhere.blogspot.com/2015/05/apache-jak-stworzyc-i-skonfigurowac-wirtualnego-hosta.html&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;tutaj&lt;/b&gt;&lt;/a&gt;.&lt;br /&gt;Stwórzmy więc vhosta o nazwie np.:&lt;br /&gt;[code]symfony.localhost[/code]&lt;br /&gt;i kierującego na:&lt;br /&gt;[code]C:/www/symfony/myApp/web[/code]&lt;br /&gt;tak abyśmy po wpisaniu:&lt;br /&gt;[code]http://symfony.localhost/[/code]&lt;br /&gt;byli kierowani wprost do tego folderu. Oczywiście jeśli tego nie zrobimy, to dostawać się do naszej aplikacji będziemy poprzez:&lt;br /&gt;[code]http://localhost/symfony/myApp/web/[/code]&lt;br /&gt;Polecam jednak sposób z vhostem, gdyż pozwoli nam to na zrozumienie pewnej koncepcji, która zakłada, iż powinniśmy zawsze wydzielać dostępny publicznie katalog webowy od całej reszty kodu, do której nie powinno być żadnego dostępu z zewnątrz. To jedna sprawa, druga to taka, że metoda z wirtualnym hostem jest zwyczajnie wygodniejsza podczas pracy.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Pierwsze uruchomienie&lt;/h2&gt;Symfony mamy już zainstalowane, zobaczmy teraz jak to działa.&lt;br /&gt;Po wpisaniu w przeglądarkę adresu:&lt;br /&gt;[code]http://symfony.localhost[/code]&lt;br /&gt;lub jeśli nie utworzyliśmy vhosta:&lt;br /&gt;[code]http://localhost/symfony/myApp/web/[/code]&lt;br /&gt;który to adres prowadzi tak naprawdę do front-controllera:&lt;br /&gt;[code]c:/www/symfony/myApp/web/app.php[/code]&lt;br /&gt;zostaniemy na starcie przywitani brakiem dostępu.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-k-p9HqeZb-c/VW22zHa3qCI/AAAAAAAAIhg/s2wTECWzr8U/s1600/w2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;270&quot; src=&quot;http://3.bp.blogspot.com/-k-p9HqeZb-c/VW22zHa3qCI/AAAAAAAAIhg/s2wTECWzr8U/s640/w2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Dzieje się tak dlatego, gdyż domyślnie pracujemy na środowisku developerskim i dostęp do środowiska produkcyjnego jest zablokowany. Na starcie mamy dostęp jedynie do środowiska developerskiego, do którego wchodzimy poprzez:&lt;br /&gt;[code]http://symfony.localhost/app_dev.php[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-PVorTrhL4-k/VW225QStOyI/AAAAAAAAIho/tq_huowmYIg/s1600/w4.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://3.bp.blogspot.com/-PVorTrhL4-k/VW225QStOyI/AAAAAAAAIho/tq_huowmYIg/s640/w4.jpg&quot; width=&quot;490&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Tu wyświetli nam się błąd routingu, ale o tym za chwilę.&lt;br /&gt;&lt;br /&gt;Symfony oczywiście pozwala na konfigurację środowiska w jakim obecnie się znajdujemy, dostępne są 3 środowiska:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;dev&lt;/b&gt; - środowisko developerskie&lt;/li&gt;&lt;li&gt;&lt;b&gt;prod&lt;/b&gt; - środowisko produkcyjne&lt;/li&gt;&lt;li&gt;&lt;b&gt;tests&lt;/b&gt; - środowisko testowe&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Aby móc teraz dostać się do naszego środowiska produkcyjnego, musimy w pliku:&lt;br /&gt;[code]/web/app.php[/code]&lt;br /&gt;zmienić linijkę:&lt;br /&gt;[code]$kernel = new AppKernel(&#39;prod&#39;, false);[/code]&lt;br /&gt;na&lt;br /&gt;[code]$kernel = new AppKernel(&#39;prod&#39;, true);[/code]&lt;br /&gt;Od tej chwili mamy dostęp do wersji produkcyjnej pod adresem:&lt;br /&gt;[code]http://symfony.localhost/[/code]&lt;br /&gt;a dokładnie do:&lt;br /&gt;[code]c:/www/symfony/myApp/web/app.php[/code]&lt;br /&gt;do którego to pliku prowadzą wszystkie requesty, co zdefiniowane jest w pliku &quot;/web/.htaccess&quot;:&lt;br /&gt;[code]RewriteRule .? %{ENV:BASE}/app.php [L][/code]&lt;br /&gt;&lt;br /&gt;Spróbujmy teraz wejść w adres:&lt;br /&gt;[code]http://symfony.localhost[/code]&lt;br /&gt;Na starcie zostaniemy przywitani błędem:&lt;br /&gt;[code]No route found for &quot;GET /&quot;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-OGa2JCegk40/VW23F4IFv6I/AAAAAAAAIhw/JqTKD8TQ3lU/s1600/w3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://3.bp.blogspot.com/-OGa2JCegk40/VW23F4IFv6I/AAAAAAAAIhw/JqTKD8TQ3lU/s640/w3.jpg&quot; width=&quot;616&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Wyjątek ten mówi nam o braku definicji dla routingu domyślnego (/), czyli dla ścieżki głównej naszej aplikacji.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Kontrolery i akcje&lt;/h2&gt;Aby przejść dalej i rozwiązać powyższy problem musimy nauczyć się kilku podstawowych pojęć. Otóż Symfony działa w pełnym modelu MVC, a więc jego struktura jest podzielona na warstwy modelu, kontrolera i widoku.&lt;br /&gt;Do plików z definicjami naszych kontrolerów dostaniemy się w katalogu:&lt;br /&gt;[code]/src/AppBundle/Controller/[/code]&lt;br /&gt;Do plików widoku natomiast tutaj:&lt;br /&gt;[code]/app/Resources/views/[/code]&lt;br /&gt;&lt;br /&gt;Otwórzmy sobie dostępny domyślnie przykładowy plik controllera:&lt;br /&gt;[code]/src/AppBundle/Controllers/DefaultController.php[/code]&lt;br /&gt;Jego zawartość powinna wyglądać następująco:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;namespace AppBundle\Controller;&lt;br /&gt;&lt;br /&gt;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;&lt;br /&gt;use Symfony\Bundle\FrameworkBundle\Controller\Controller;&lt;br /&gt;&lt;br /&gt;class DefaultController extends Controller&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; /**&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* @Route(&quot;/app/example&quot;, name=&quot;homepage&quot;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;br /&gt;&amp;nbsp; &amp;nbsp; public function indexAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return $this-&amp;gt;render(&#39;default/index.html.twig&#39;);&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;Jak widać mamy tutaj definicję klasy kontrolera o nazwie &quot;DefaultController&quot;.&lt;br /&gt;Trzeba tutaj zrozumieć w jaki sposób działają kontrolery i routing w Symfony.&lt;br /&gt;Otóż kontroler to jakaś sekcja naszej aplikacji, np. jeden kontroler może odpowiadać za obsługę kont użytkowników, inny za obsługę newsów na stronie, jeszcze inny za wyświetlanie i edycję komentarzy. Każdy taki kontroler jest podzielony na jakieś akcje, np. kontroler do obsługi użytkowników może być podzielony na akcje takie jak dodawanie użytkownika, edycja użytkownika, wyświetlanie profilu itp.&lt;br /&gt;Domyślną akcją dla kontrolera jest zawsze akcja o nazwie:&lt;br /&gt;[code]index[/code]&lt;br /&gt;Poszczególne akcje definiujemy w klasie naszego kontrolera stosując się do składni:&lt;br /&gt;[code]nazwaAction()[/code]&lt;br /&gt;czyli po nazwie akcji (pisanej zawsze małymi literami, np. &quot;edit&quot;, &quot;add&quot;, &quot;profile&quot; dodajemy suffix Action.&lt;br /&gt;&lt;br /&gt;Przykładowy kontroler do obsługi użytkowników definiujacy trzy akcje może wyglądać np. tak:&lt;br /&gt;[code]&lt;br /&gt;class UsersController extends Controller&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; public function addAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // [...]&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; public function editAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // [...]&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; public function profileAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // [...]&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;&lt;br /&gt;Do danej akcji musimy się jednak jakoś dostać z poziomu aplikacji, np.:&lt;br /&gt;[code]http://aplikacja.com/users/add[/code]&lt;br /&gt;lub&lt;br /&gt;[code]http://aplikacja.com/users/profile[/code]&lt;br /&gt;I tutaj do akcji wkracza tzw. routing&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Routing&lt;/h2&gt;Konfiguracja routingu dla kontrolerów i akcji to bardzo obszerny temat i tutaj liźniemy tylko zasadę jego działania na bazie naszego przykładowego projektu.&lt;br /&gt;Wróćmy do naszego domyślnego kontrolera i zobaczmy, że przed definicją metody z akcją &quot;index&quot; znajduje się adnotacja blokowa o treści:&lt;br /&gt;[code]&lt;br /&gt;/**&lt;br /&gt;* @Route(&quot;/app/example&quot;, name=&quot;homepage&quot;)&lt;br /&gt;*/[/code]&lt;br /&gt;Określa ona trasę routingu dla akcji po tej definicji występującej.&lt;br /&gt;W tym przypadku dla akcji &quot;index&quot; definiowany jest routing o ścieżce &quot;/app/example&quot;.&lt;br /&gt;Oznacza to, iż do definiowanej tutaj akcji dostaniemy się po wpisaniu w przeglądarce adresu:&lt;br /&gt;[code]http://symfony.localhost/app/example[/code]&lt;br /&gt;&lt;br /&gt;Dalsza część kodu, czyli definicja akcji &quot;index&quot;:&lt;br /&gt;[code]&lt;br /&gt;public function indexAction()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; return $this-&amp;gt;render(&#39;default/index.html.twig&#39;);&lt;br /&gt;}[/code]&lt;br /&gt;w tym przypadku zwraca nam do wyświetlenia widok wczytywany z pliku:&lt;br /&gt;[code]/app/Resources/views/default/index.html.twig[/code]&lt;br /&gt;którego treść wygląda tak:&lt;br /&gt;[code]&lt;br /&gt;{% extends &#39;base.html.twig&#39; %}&lt;br /&gt;&lt;br /&gt;{% block body %}&lt;br /&gt;&amp;nbsp; &amp;nbsp; Homepage.&lt;br /&gt;{% endblock %}[/code]&lt;br /&gt;Temat widoków to również bardzo obszerny temat, więc na razie wystarczy abyśmy wiedzieli jedynie jak to mniej więcej działa.&lt;br /&gt;&lt;br /&gt;Wpiszmy teraz w przeglądarce:&lt;br /&gt;[code]http://symfony.localhost/app/example[/code]&lt;br /&gt;Jak widzimy, tym razem nie pojawił nam się już błąd związany z brakiem zdefiniowanego routingu, a wyświetlił nam się szablon zwrócony przez akcję &quot;index&quot; z naszego kontrolera:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-gfjIf-0Zv6g/VW23QBY-9BI/AAAAAAAAIh4/905A8i15RB8/s1600/w5.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;168&quot; src=&quot;http://3.bp.blogspot.com/-gfjIf-0Zv6g/VW23QBY-9BI/AAAAAAAAIh4/905A8i15RB8/s640/w5.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Stwórzmy sobie teraz dla testu nowy plik widoku o nazwie:&lt;br /&gt;[code]/app/Resources/views/default/hello.html.twig[/code]&lt;br /&gt;i wpiszmy do niego:&lt;br /&gt;[code]&lt;br /&gt;{% extends &#39;base.html.twig&#39; %}&lt;br /&gt;&lt;br /&gt;{% block body %}&lt;br /&gt;&amp;nbsp; &amp;nbsp; Hello World!&lt;br /&gt;{% endblock %}[/code]&lt;br /&gt;Następnie utwórzmy nową akcję i routing do niej w pliku:&lt;br /&gt;[code]/src/AppBundle/Controllers/DefaultController.php[/code]&lt;br /&gt;dopisując ją do klasy kontrolera:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;namespace AppBundle\Controller;&lt;br /&gt;&lt;br /&gt;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;&lt;br /&gt;use Symfony\Bundle\FrameworkBundle\Controller\Controller;&lt;br /&gt;&lt;br /&gt;class DefaultController extends Controller&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; /**&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* @Route(&quot;/app/example&quot;, name=&quot;homepage&quot;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;br /&gt;&amp;nbsp; &amp;nbsp; public function indexAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return $this-&amp;gt;render(&#39;default/index.html.twig&#39;);&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; // nasza nowa akcja&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;/**&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;* @Route(&quot;/app/hello&quot;, name=&quot;hello&quot;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;*/&lt;br /&gt;&amp;nbsp; &amp;nbsp; public function helloAction()&lt;br /&gt;&amp;nbsp; &amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return $this-&amp;gt;render(&#39;default/hello.html.twig&#39;);&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;&lt;br /&gt;Dodaliśmy nową akcję, do której dostaniemy się po wpisaniu:&lt;br /&gt;[code]http://symfony.localhost/app/hello[/code]&lt;br /&gt;Zróbmy więc to i zobaczmy co się stanie:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-s5-OVlYtJ1s/VW23VEvd9lI/AAAAAAAAIiA/HAP-N4ewa0k/s1600/w6.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;266&quot; src=&quot;http://1.bp.blogspot.com/-s5-OVlYtJ1s/VW23VEvd9lI/AAAAAAAAIiA/HAP-N4ewa0k/s640/w6.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Coś jest nie tak. Ale co? Otóż wszystko jest w jak najlepszym porządku, zapomnieliśmy jedynie o jednej małej rzeczy - o cache&#39;u.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;cache:clear&lt;/h2&gt;Symfony parsuje i cache&#39;uje wiele elementów, aby generowały się one szybciej. W naszym powyższym przypadku dokonaliśmy zmian w strukturze szablonów dodając nowy element dla akcji &quot;hello&quot;.&lt;br /&gt;Poprzedni cache jednak tego nie uzwględnia, musimy więc wyczyścić stary cache, aby utworzyć nowy. Służy do tego skrypt:&lt;br /&gt;[code]app/console[/code]&lt;br /&gt;który znajdziemy w katalogu z naszą aplikacją.&lt;br /&gt;Console to tak naprawdę narzędzie, którego będziemy używać często, a jego możliwości nie ograniczają się jedynie do czyszczenia cache&#39;u.&lt;br /&gt;Wejdźmy teraz w terminalu do katalogu z naszą aplikacją, czyli do:&lt;br /&gt;[code]C:/www/symfony/myApp/[/code]&lt;br /&gt;i z jej poziomu wywołajmy:&lt;br /&gt;[code]$ php app/console cache:clear[/code]&lt;br /&gt;Polecenie to wyczyści nam cache, ale uwaga - jedynie dla środowiska developerskiego.&lt;br /&gt;Jeśli chcemy wyczyścić cache dla innego środowiska, np. produkcyjnego, to podajemy jego nazwę:&lt;br /&gt;[code]$ php app/console cache:clear --env=prod[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-zWvxx88Agy4/VW24fHrf9rI/AAAAAAAAIig/jNmi8xXUSNY/s1600/cc1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;176&quot; src=&quot;http://3.bp.blogspot.com/-zWvxx88Agy4/VW24fHrf9rI/AAAAAAAAIig/jNmi8xXUSNY/s640/cc1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Po wykonaniu powyższego, czyli wyczyszczeniu folderu cache wejdźmy ponownie na:&lt;br /&gt;[code]http://symfony.localhost/app/hello[/code]&lt;br /&gt;Voila! Nasza dodana akcja wyświetliła się prawidłowo:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-MegpJbKbBok/VW23Y7FBvwI/AAAAAAAAIiI/72Yl10J521w/s1600/w7.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;210&quot; src=&quot;http://4.bp.blogspot.com/-MegpJbKbBok/VW23Y7FBvwI/AAAAAAAAIiI/72Yl10J521w/s640/w7.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2&gt;Problem z początku&lt;/h2&gt;Jak teraz rozwiązać problem z początku - błąd&amp;nbsp;&lt;b&gt;No route found for &quot;GET /&quot;&lt;/b&gt;?&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-OGa2JCegk40/VW23F4IFv6I/AAAAAAAAIh0/SgF9NAMHPVQ/s1600/w3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://1.bp.blogspot.com/-OGa2JCegk40/VW23F4IFv6I/AAAAAAAAIh0/SgF9NAMHPVQ/s640/w3.jpg&quot; width=&quot;616&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Błąd ten otrzymujemy po wejściu na główną ścieżkę naszej aplikacji, czyli:&lt;br /&gt;[code]http://symfony.localhost/[/code]&lt;br /&gt;Otóż dokonamy małych zmian w routingu akcji &quot;index&quot;.&lt;br /&gt;Otwórzmy plik z kontrolerem:&lt;br /&gt;[code]/src/AppBundle/Controllers/DefaultController.php[/code]&lt;br /&gt;i dla akcji &quot;index&quot; zamieńmy ścieżkę routingu z:&lt;br /&gt;[code]&lt;br /&gt;/**&lt;br /&gt;* @Route(&quot;/app/example&quot;, name=&quot;homepage&quot;)&lt;br /&gt;*/[/code]&lt;br /&gt;na:&lt;br /&gt;[code]&lt;br /&gt;/**&lt;br /&gt;* @Route(&quot;/&quot;, name=&quot;homepage&quot;)&lt;br /&gt;*/[/code]&lt;br /&gt;Zapiszmy plik i wejdźmy ponownie na:&lt;br /&gt;[code]http://symfony.localhost/[/code]&lt;br /&gt;Jak widzimy - problem rozwiązany i akcja &quot;index&quot; wyświetliła nam się domyślnie bez podawania żadnej dodatkowej ścieżki.&lt;br /&gt;Wejście tutaj poprzez środowisko developerskie da nam ponadto kilka ciekawych informacji w pasku debuggera dołączanego na dole strony:&lt;br /&gt;&lt;br /&gt;[code]http://symfony.localhost/app_dev.php[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-xr3Q2bkgttU/VW24MpLj82I/AAAAAAAAIiQ/2tCo9V-P1vM/s1600/w8.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;386&quot; src=&quot;http://1.bp.blogspot.com/-xr3Q2bkgttU/VW24MpLj82I/AAAAAAAAIiQ/2tCo9V-P1vM/s640/w8.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widzimy, mamy podane tutaj w jakim aktualnie kontrolerze się znajdujemy i w jakiej akcji, a także całą masę innych informacji i parametrów.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-0ymJWnrdqqk/VW24QoWkFDI/AAAAAAAAIiY/uphdQwhehE4/s1600/w9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;210&quot; src=&quot;http://1.bp.blogspot.com/-0ymJWnrdqqk/VW24QoWkFDI/AAAAAAAAIiY/uphdQwhehE4/s640/w9.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Z debuggera tego korzystać będziemy często podczas naszej pracy, podobnie jak ze skryptu &quot;console&quot; i czyszczenia katalogu cache, radzę się więc już na to mentalnie przygotować ;)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Podsumowanie&lt;/h2&gt;No i to tyle tytułem wstępu, umiemy już uruchomić Symfony i wiemy jak to wszystko mniej więcej działa. W kolejnych artykułach zaczniemy już normalną pracę z Symfony i poznamy ten framework krok po kroku. Mam nadzieję, że artykuł okazał się pomocny, gdyż szczerze mówiąc instalacja i pierwsze uruchomienie może być naprawdę problematyczne dla osoby, która z Symfony ma styczność po raz pierwszy. Dokumentacja dostępna na stronie projektu pomija kilka kluczowych rzeczy, w związku z czym początkujący użytkownik może mieć problemy już na samym starcie, mimo iż robi wszystko tak jak zostało to opisane w dokumentacji. Tutaj opisałem to absolutnie krok po kroku i pokazałem rozwiązanie, którego w takiej formie nie znajdziecie w dokumentacji. Do następnego!</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/821936260844612134/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/php-symfony2-instalacja-i-pierwsze-uruchomienie.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/821936260844612134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/821936260844612134'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/php-symfony2-instalacja-i-pierwsze-uruchomienie.html' title='[PHP][Symfony2] Instalacja i pierwsze uruchomienie Symfony2 krok po kroku'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-cIiR9TsX2uA/VWD0zTR_qhI/AAAAAAAAH-Y/3jsAbSP5rMA/s72-c/icoPHP_symfony.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-1915472901869042583</id><published>2015-06-01T22:40:00.000+02:00</published><updated>2015-06-02T16:57:54.775+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Doctrine"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><title type='text'>[PHP][Doctrine2] Instalacja i wstęp do Doctrine2 ORM</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-jSXaYv8hOiQ/VWD0v_gahiI/AAAAAAAAH98/tbm6eSLjQd4/s1600/icoPHP_doctrine.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-jSXaYv8hOiQ/VWD0v_gahiI/AAAAAAAAH98/tbm6eSLjQd4/s1600/icoPHP_doctrine.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Doctrine jest systemem ORM dla relacyjnych baz danych, napisanym w PHP. ORM (Object-relational Mapping), czyli po polsku Mapowanie Obiektowo-relacyjne jest to ogólnie rzecz biorąc technika zamiany danych opisanych za pomocą obiektów w ich relacyjne modele w bazie danych. W systemach ORM pracujemy nie na rekordach z bazy, lecz na obiektach, gdyż każdy rekord reprezentowany jest jako pełnoprawny obiekt. Doctrine jest właśnie jednym z najpopularniejszych rozwiązań, które oferują takie mapowanie dla PHP. Korzystając z bibliotek Doctrine każda tabela w bazie danych prezentowana jest jako jedna wielka klasa, gdzie poszczególne rekordy (wiersze) są jej obiektami. Na obiektach takich pracujemy dokładnie tak samo jak na zwykłych obiektach, utworzonych w tradycyjny sposób. W artykule tym zainstalujemy sobie Doctrine na własnym serwerze i nauczymy się podstaw pracy z nim.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;Instalacja&lt;/h2&gt;Instalację Doctrine zaczynamy od pobrania najnowszej wersji za pomocą Composera (&lt;a href=&quot;http://www.phpeverywhere.blogspot.com/2015/05/phpcomposer-instalacja-i-podstawy.html&quot; target=&quot;_blank&quot;&gt;tutorial dla Composera znajdziesz tutaj&lt;/a&gt;). Strona oficjalna z najnowszą wersją Doctrine znajduje się tutaj: &lt;a href=&quot;http://www.doctrine-project.org/projects/orm.html&quot; target=&quot;_blank&quot;&gt;http://www.doctrine-project.org/projects/orm.html&amp;nbsp;&lt;/a&gt;&lt;br /&gt;Wchodzimy na nią, sprawdzamy numerek najnowszej wersji i sporządzamy odpowiedni plik &quot;composer.json&quot;. W tym artykule pobierzemy wersję 2.4.7, więc zawartość pliku composer.json wyglądać będzie tak:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;doctrine/orm&quot;: &quot;2.4.7&quot;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;Zapisujemy plik, np. w katalogu:&lt;br /&gt;[code]C:/www/doctrine [/code]&lt;br /&gt;i w terminalu (będąc w w/w wymienionym katalogu) pobieramy paczkę za pomocą biblioteki Composer:&lt;br /&gt;[code]$ composer install[/code]&lt;br /&gt;Pobierze nam to do folderu &quot;/vendor&quot; najnowszą wersję wraz ze wszystkimi wymaganymi zależnościami. Od tej chwili jesteśmy już prawie gotowi do pracy z Doctrine, zanim to jednak zrobimy przyjrzyjmy się krótkiemu opisowi jak wygląda praca z techniką ORM.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-PB6aj4LjMYQ/VWy_qMcPdAI/AAAAAAAAIg8/eOo6dQ2fzEg/s1600/c1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;444&quot; src=&quot;http://1.bp.blogspot.com/-PB6aj4LjMYQ/VWy_qMcPdAI/AAAAAAAAIg8/eOo6dQ2fzEg/s640/c1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Model ORM&lt;/h2&gt;Jak wiemy, dane w bazie danych przechowywane są w formie rekordów, czyli wierszy, przy czym kolumny w tych wierszach reprezentują pola rekordu. Pobierając takie dane z bazy zazwyczaj otrzymujemy natomiast tablicę reprezentującą dany wiersz, w której to tablicy poszczególne pola to klucze/indeksy tej tablicy. Przykładowo, pobierając z tabeli o nazwie &quot;customers&quot; pola o nazwach &quot;customer_id&quot;, &quot;first_name&quot; i &quot;last_name&quot; otrzymujemy tablicę (rekord) postaci:&lt;br /&gt;[code]&lt;br /&gt;$row[&#39;customer_id&#39;];&lt;br /&gt;$row[&#39;first_name&#39;];&lt;br /&gt;$row[&#39;last_name&#39;];[/code]&lt;br /&gt;W modelu ORM będzie to wyglądało nieco inaczej. Nie otrzymamy wiersza jako tablicy, lecz jako obiekt, którego właściwości będą odpowiadać polom kolumn w wierszu:&lt;br /&gt;[code]&lt;br /&gt;class Customer {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; protected $customer_id,&lt;br /&gt;&amp;nbsp; protected $first_name;&lt;br /&gt;&amp;nbsp; protected $last_name; &lt;br /&gt;&amp;nbsp; [...]&lt;br /&gt;}&lt;br /&gt;$customer-&amp;gt;new Customer();&lt;br /&gt;[/code]&lt;br /&gt;Do właściwości takich będziemy mieli dostęp za pomocą utworzonych metod getXXX(), jak np.:&lt;br /&gt;[code]&lt;br /&gt;$customer-&amp;gt;getId();&lt;br /&gt;$customer-&amp;gt;getFirstName();&lt;br /&gt;$customer-&amp;gt;getLastName();&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Również tworzenie nowego rekordu w bazie nie będzie już polegało na wysłaniu do niej zapytania typu INSERT, lecz na zwyczajnym utworzeniu nowego obiektu:&lt;br /&gt;[code]$customer = new Customer();[/code]&lt;br /&gt;a następnie na wysłaniu obiektu do systemu ORM, który już odpowiednio przetworzy wszystko tak, aby nasz obiekt zamienić na odpowiedni rekord i umieścić go w bazie.&lt;br /&gt;Analogicznie - aktualizowanie wartości pól rekordu nie będzie też już polegało na zapytaniu UPDATE, lecz na wywoływaniu odpowiednich metod obiektu, jak np.:&lt;br /&gt;[code]&lt;br /&gt;$customer-&amp;gt;setFirstName($first_name);&lt;br /&gt;$customer-&amp;gt;setLastName($last_name);[/code]&lt;br /&gt;Podczas pracy w modelu ORM zapomnimy całkowicie o bazie danych - wszystkie, ale to WSZYSTKIE operacje na rekordach będą odbywały się jak na zwykłych obiektach. Sposób taki więc powoduje, iż nasz kod staje się jedną wielką, zintegrowaną strukturą, w której nie musimy nagle wybijać z metodami operującymi na bazie i burzącymi pełną obiektowość kodu. Podejście takie ma całą listę zalet i chyba tylko jeden minus, którym jest konieczność ręcznego przygotowania schematu bazy i konieczność aktualizacji takiego modelu po każdorazowej modyfikacji struktury tabel. Nie jest to jednak trudne i nauczymy się tutaj tego krok po kroku. Tak na marginesie - Doctrine oferuje coś w rodzaju inżynierii wstecznej, czyli mechanizm który może na podstawie analizy struktury bazy przygotować taki model automatycznie, jednakże po pierwsze nie zawsze zadziała to tak jak jakbyśmy tego oczekiwali, a po drugie - lepiej nauczyć się przygotowywania schematu manualnie, gdyż wiedza ta będzie konieczna, jeśli chcemy pracować na poważnie.&lt;br /&gt;&lt;br /&gt;Wiemy już na czym mniej więcej polega zasada działania, pora więc na praktykę, ale żeby stworzyć swój pierwszy projekt, musimy najpierw nauczyć się kilku podstawowych pojęć z jakich będziemy korzystać i z jakich korzysta Doctrine.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Entity&lt;/h2&gt;Na rodzimy język możemy to przetłumaczyć jako &quot;byt, jednostka&quot;. Terminem Entity nazywamy w Doctrine każdy obiekt mapowany na bazę.&lt;br /&gt;Każdy taki obiekt to oddzielny byt. Główną i podstawową klasą, która zarządza naszymi bytami jest w Doctrine EntityManager. Aby zrozumieć to obrazowo, spójrzmy na przykład: mając tabelę o nazwie &quot;users&quot; składającą się z pól:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;id&lt;/b&gt; (int, primary index)&lt;/li&gt;&lt;li&gt;&lt;b&gt;login&lt;/b&gt; (varchar 50)&lt;/li&gt;&lt;li&gt;&lt;b&gt;password&lt;/b&gt; (varchar 80)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;i chcąc ją zmapować jako obiekt, musimy utworzyć dla niej klasę:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// Entity&lt;br /&gt;class User {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; protected $id;&lt;br /&gt;&amp;nbsp; protected $login;&lt;br /&gt;&amp;nbsp; protected $password;&lt;br /&gt;}&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;To co powyżej to właśnie nasz &quot;Entity&quot;, czyli obiekt mapowany na bazę danych.&lt;br /&gt;Widzimy tutaj, że został on opisany za pomocą definicji klasy zwykłym kodem PHP, ale w Doctrine możemy użyć do opisu także XML i YAML-a.&lt;br /&gt;&lt;br /&gt;W XML-u nasz Entity opisany będzie tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;doctrine-mapping&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;entity name=&quot;User&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;field name=&quot;id&quot; type=&quot;integer&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;field name=&quot;login&quot; length=&quot;50&quot; name=&quot;login&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;field name=&quot;password&quot; length=&quot;80&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;/doctrine-mapping&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;A w YAML-u tak:&lt;br /&gt;[code]&lt;br /&gt;User:&lt;br /&gt;&amp;nbsp; type: entity&lt;br /&gt;&amp;nbsp; fields:&lt;br /&gt;&amp;nbsp; &amp;nbsp; id:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; type: integer&lt;br /&gt;&amp;nbsp; &amp;nbsp; login:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; length: 50&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; name: login&lt;br /&gt;&amp;nbsp; &amp;nbsp; password:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; length: 80[/code]&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;br /&gt;W PHP podałem powyżej jedynie obrazowy przykład, właściwy opis bytu wyglądałby tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/** @Entity */&lt;br /&gt;class User {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; /** @Column(type=&quot;integer&quot;) */&lt;br /&gt;&amp;nbsp; protected $id;&lt;br /&gt;&amp;nbsp; /** @Column(length=50, name=&quot;login&quot;) */&lt;br /&gt;&amp;nbsp; protected $login;&lt;br /&gt;&amp;nbsp; /** @Column(length=80) */&lt;br /&gt;&amp;nbsp; protected $password;&lt;br /&gt;}&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Te dodatkowe pola z opisami właściwości danej kolumny wyglądające na zwykłe komentarze blokowe to adnotacje docblock i są one odczytywane i przetwarzane przez Doctrine.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Właściwości mapowanych kolumn&lt;/h2&gt;Właściwości opisujących dane pole jest oczywiście więcej:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;type&lt;/b&gt; - typ kolumny, np. &quot;integer&quot;, domyślnie: &amp;nbsp;string.&lt;/li&gt;&lt;li&gt;&lt;b&gt;name&lt;/b&gt; - nazwa kolumny w bazie, domyślnie: nazwa taka sama jak deklaracja - UWAGA: W przypadku nazwy będącem słowem kluczowym ujmujemy w cytat: `name`&lt;/li&gt;&lt;li&gt;&lt;b&gt;length&lt;/b&gt; - jeśli pole jest typu string to określa jego długość, domyślnie: 255&lt;/li&gt;&lt;li&gt;&lt;b&gt;unique &lt;/b&gt;- określa, czy pole posiada unikalny klucz, domyślnie: false&lt;/li&gt;&lt;li&gt;&lt;b&gt;nullable&lt;/b&gt; - czy kolumna może przyjąć NULL, domyślnie: false&lt;/li&gt;&lt;li&gt;&lt;b&gt;precision&lt;/b&gt; - precyzja dla liczb dziesiętnych, czyli maksymalna liczba wszystkich cyfr dziesiętnych, domyślnie: 0&lt;/li&gt;&lt;li&gt;&lt;b&gt;scale&lt;/b&gt; - precyzja dla liczb dziesiętnych, ale tylko dla wartości po przecinku, domyślnie: 0, nie może być większa niż określona w &quot;precision&quot;&lt;/li&gt;&lt;li&gt;&lt;b&gt;columnDefinition&lt;/b&gt; - własna definicja wykonywana podczas tworzenia kolumny, np. &quot;CHAR(3) NOT NULL&quot;&lt;/li&gt;&lt;li&gt;&lt;b&gt;options&lt;/b&gt; - dodatkowe opcje podawane na zasadzie &quot;klucz-wartość&quot;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Jeśli nie określamy typu pola ręcznie to przyjmowane jest, że jest ono typu string, czyli standardowy VARCHAR w bazie.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Mapowane typy kolumn&amp;nbsp;&lt;/h2&gt;Typy kolumn dostępne w Doctrine to:&lt;br /&gt;(podaję nazwę typu dla PHP i odpowiednik w bazie SQL)&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;string &lt;/b&gt;- mapuje VARCHAR w SQL na string w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;integer&lt;/b&gt; - mapuje INT w SQL na integer w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;smallint&lt;/b&gt; - mapuje SMALLINT w SQL na integer w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;bigint &lt;/b&gt;- mapuje BIGLLINT w SQL na integer w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;boolean &lt;/b&gt;- mapuje TINYINT/boolean w SQL na boolean w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;decimal&lt;/b&gt; - mapuje DECIMAL w SQL na string w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;date&lt;/b&gt; - mapuje DATETIME w SQL na obiekt DateTime w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;time &lt;/b&gt;- mapuje TIME w SQL na obiekt DateTime w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;datetime &lt;/b&gt;- mapuje DATETIME/TIMESTAMP w SQL na obiekt DateTime w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;datetimetz&lt;/b&gt; - mapuje DATETIME/TIMESTAMP w SQL na obiekt DateTime ze strefą czasową w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;text&lt;/b&gt; - mapuje CLOB w SQL na string w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;object &lt;/b&gt;- mapuje CLOB w SQL na obiekt w PHP, z użyciem serialize() i unserialize()&lt;/li&gt;&lt;li&gt;&lt;b&gt;array&lt;/b&gt; - mapuje CLOB w SQL na tablicę w PHP, z użyciem serialize() i unserialize()&lt;/li&gt;&lt;li&gt;&lt;b&gt;simple_array&lt;/b&gt; - mapuje CLOB w SQL na tablicę w PHP, z użyciem implode() i explode(), rozdzialając przecinkiem (,)&lt;/li&gt;&lt;li&gt;&lt;b&gt;json_array&lt;/b&gt; - mapuje CLOB w SQL na tablicę w PHP, z użyciem json_encode() i json_decode()&lt;/li&gt;&lt;li&gt;&lt;b&gt;float&lt;/b&gt; - mapuje FLOAT w SQL na double w PHP (wymagana kropka jako separator części po przecinku)&lt;/li&gt;&lt;li&gt;&lt;b&gt;guid &lt;/b&gt;- mapuje GUID/UUID w SQL na string w PHP&lt;/li&gt;&lt;li&gt;&lt;b&gt;blob&lt;/b&gt; - mapuje BLOB w SQL na resource w PHP&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Identyfikator&lt;/h2&gt;Określa on klucz podstawowy dla tabeli w bazie danych. Jego zdefiniowanie jest wymagane.&lt;br /&gt;Klucz podstawowy denifiujemy następująco:&lt;br /&gt;&lt;br /&gt;PHP:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/** @Entity */&lt;br /&gt;class User {&lt;br /&gt;&amp;nbsp; /**&lt;br /&gt;&amp;nbsp; &amp;nbsp;* @Id @Column(type=&quot;integer&quot;)&lt;br /&gt;&amp;nbsp; &amp;nbsp;* @GeneratedValue(strategy=&quot;AUTO&quot;)&lt;br /&gt;&amp;nbsp; &amp;nbsp;*/&lt;br /&gt;&amp;nbsp; protected $id;&lt;br /&gt;&amp;nbsp; //[...]&lt;br /&gt;}&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;XML:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;doctrine-mapping&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;entity name=&quot;User&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;id name=&quot;id&quot; type=&quot;integer&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;generator strategy=&quot;AUTO&quot; /&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/id&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!-- [...]--&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;lt;/entity&amp;gt;&lt;br /&gt;&amp;lt;/doctrine-mapping&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;YAML:&lt;br /&gt;[code]&lt;br /&gt;User:&lt;br /&gt;&amp;nbsp; type: entity&lt;br /&gt;&amp;nbsp; id:&lt;br /&gt;&amp;nbsp; &amp;nbsp; id:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; type: integer&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; generator:&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; strategy: AUTO&lt;br /&gt;&amp;nbsp; fields:&lt;br /&gt;&amp;nbsp; &amp;nbsp; # [...][/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Podczas definicji identyfikatora możemy określić sposób w jaki wartość ma być inkrementowana, do czego służy wyżej widoczny parametr GENERATOR STRATEGY.&lt;br /&gt;Możliwe do ustawienia wartości to: auto (domyślnie), sequence, identity i none. Więcej o nich napiszę w pozostałych artykułach.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Próba ognia&lt;/h2&gt;Opiszę teraz dokładnie krok po kroku, co zrobić, żeby wszystko nam zadziałało, gdyż trzeba tutaj wykonać kilka manewrów, podczas których niedoświadczeni z Doctrine mogliby coś pominąć. Zwłaszcza, że w oficjalnym poradniku jest to wszystko opisane trochę nie po kolei. Na początek musimy stworzyć sobie jeden folder i trochę usprawnić swoją instalację Doctrine - a użyjemy do tego Composera.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Krok 1 - tworzymy katalog na definicje Entities&lt;/h2&gt;Stwórzmy folder o nazwie:&lt;br /&gt;[code]c:/www/doctrine/src/Model[/code]&lt;br /&gt;W folderze tym zapiszemy pliki z deklaracjami naszych Entities, które wykorzysta Doctrine.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Krok 2 - modyfikujemy composer.json i aktualizujemy autoloader&lt;/h2&gt;Następnie zmodyfikujmy lekko plik:&lt;br /&gt;[code]C:/www/doctrine/composer.json[/code]&lt;br /&gt;zmieniając jego zawartość na:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;doctrine/orm&quot;: &quot;2.4.7&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;symfony/yaml&quot;: &quot;*&quot;&lt;br /&gt;&amp;nbsp; },&lt;br /&gt;&amp;nbsp; &quot;autoload&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;psr-0&quot;: {&quot;&quot;: &quot;src/Model/&quot;}&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;gdzie w miejsce wersji Doctrine podajmy tą, którą pobieraliśmy na początku.&lt;br /&gt;Powyższy wpis spowoduje, że doinstalujemy sobie obsługę plików YAML, a także zmodyfikujemy lekko autoloader Composera, tak aby uwzględniał nam pliki z katalogu &quot;/src/Model&quot;, czyli katalogu, w którym zapiszemy pliki z deklaracjami Entities. Bez tego manewru napotkalibyśmy w kolejnych krokach na błąd mówiący o braku definicji klasy.&lt;br /&gt;&lt;br /&gt;Mając tak zmodyfikowany &quot;composer.json&quot; wchodzimy teraz do konsoli/terminala i z poziomu katalogu:&lt;br /&gt;[code]C:/www/doctrine/[/code]&lt;br /&gt;wpisujemy:&lt;br /&gt;[code]$ composer update[/code]&lt;br /&gt;Doinstaluje nam to pakiet YAML i zaktualizuje autoloader.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-sOtRnN_Q1hg/VWy_gG0BiAI/AAAAAAAAIg0/qbnDvV3IiPE/s1600/c3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;274&quot; src=&quot;http://4.bp.blogspot.com/-sOtRnN_Q1hg/VWy_gG0BiAI/AAAAAAAAIg0/qbnDvV3IiPE/s640/c3.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Krok 3 - tworzymy definicję prostego obiektu Entity&lt;/h2&gt;Stwórzmy teraz sobie prosty obiekt mapujący tabelę &quot;users&quot;.&lt;br /&gt;Utwórzmy zatem plik:&lt;br /&gt;[code]C:/www/doctrine/src/Model/User.php[/code]&lt;br /&gt;i jako jego zawartość wklejmy:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// /src/Model/User.php&lt;br /&gt;/**&lt;br /&gt;&amp;nbsp;* @Entity @Table(name=&quot;users&quot;)&lt;br /&gt;&amp;nbsp;**/&lt;br /&gt;class User {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; /**&lt;br /&gt;&amp;nbsp; * @Id @Column(type=&quot;integer&quot;)&lt;br /&gt;&amp;nbsp; * @GeneratedValue(strategy=&quot;AUTO&quot;)&lt;br /&gt;&amp;nbsp; */&lt;br /&gt;&amp;nbsp; protected $id;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; /** @Column(length=50, name=&quot;login&quot;) */&lt;br /&gt;&amp;nbsp; protected $login;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; /** @Column(length=80) */&lt;br /&gt;&amp;nbsp; protected $password;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function getId()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return $this-&amp;gt;id;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function getLogin()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return $this-&amp;gt;login;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function setLogin($login)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp;$this-&amp;gt;login = $login;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function getPassword()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return $this-&amp;gt;password;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function setPassword($password)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp;$this-&amp;gt;password = $password;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;Będzie to definicja obiektu, który będziemy mapować na tabelę &quot;users&quot;.&lt;br /&gt;Definiujemy tutaj 3 pola: id, login i password oraz metody getXXX() i setXXX() dla tych pól.&lt;br /&gt;Zauważmy, że dla pola $id nie definiujemy metody setId(). Mając tak przygotowaną konfigurację prostego bytu lecimy dalej.&lt;br /&gt;Zauważmy też, iż definiujemy nazwę tabeli jako &quot;users&quot; mimo iż nazwa klasy to User.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Krok 4 - bootstrap.php&lt;/h2&gt;Tworzymy teraz plik:&lt;br /&gt;[code]C:/www/doctrine/bootstrap.php[/code]&lt;br /&gt;i wpisujemy mu taką zawartość:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// bootstrap.php&lt;br /&gt;// Dołączamy autoloader Composera&lt;br /&gt;require_once &quot;/vendor/autoload.php&quot;;&lt;br /&gt;&lt;br /&gt;// Określamy przestrzenie nazw z jakich skorzystamy&lt;br /&gt;use Doctrine\ORM\Tools\Setup;&lt;br /&gt;use Doctrine\ORM\EntityManager;&lt;br /&gt;&lt;br /&gt;// określamy ścieżkę do plików z Entities&lt;br /&gt;$paths = array(__DIR__.&#39;/src/Model&#39;);&lt;br /&gt;&lt;br /&gt;// informujemy, że pracujemy w środowisku developerskim, a nie na produkcji&lt;br /&gt;$isDevMode = true;&lt;br /&gt;&lt;br /&gt;// konfigurujemy dostęp do bazy&lt;br /&gt;$dbParams = array(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;driver&#39; &amp;nbsp; =&amp;gt; &#39;pdo_mysql&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;user&#39; &amp;nbsp; &amp;nbsp; =&amp;gt; &#39;root&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;password&#39; =&amp;gt; &#39;&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;dbname&#39; &amp;nbsp; =&amp;gt; &#39;doctrine_test&#39;,&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;// konfigurujemy Doctrine&lt;br /&gt;$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);&lt;br /&gt;$entityManager = EntityManager::create($dbParams, $config);&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Krok 5 - index.php&lt;/h2&gt;Tworzymy teraz plik:&lt;br /&gt;[code]C:/www/doctrine/index.php[/code]&lt;br /&gt;i includujemy w nim plik bootrstrapa:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;require_once(__DIR__.&#39;/bootstrap.php&#39;);&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Czemu taki układ? Po to, żebyśmy przyzwyczaili się do używania plików bootstrap i to w nich trzymali kod. Plik bootstrap tak w ogóle powinniśmy umieścić w innym miejscu, ale na potrzeby próby z Doctrine nie jest to teraz ważne. Napiszę o tym kiedyś artykuł, na razie niech to po prostu pozostanie w takiej formie.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Krok 6 - generujemy tabelę&lt;/h2&gt;Doctrine jeśli może juz zauważyliśmy, do katalogu /vendor/bin pobrał nam kilka użytecznych narzędzi. Będziemy z nimi pracować później, podczas normalnej pracy.&lt;br /&gt;Wykorzystamy je także teraz, ale najpierw musimy utworzyć plik:&lt;br /&gt;[code]C:/www/doctrine/cli-config.php[/code]&lt;br /&gt;w którym wpisujemy dwie poniższe linijki:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// cli-config.php&lt;br /&gt;require_once &quot;bootstrap.php&quot;;&lt;br /&gt;return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);[/code]&lt;br /&gt;&lt;br /&gt;Tworzymy teraz bazę danych do jakiej parametry podaliśmy w pliku &quot;bootstrap.php&quot; i NIE TWORZYMY w niej żadnych tabel.&lt;br /&gt;Następnie z poziomu naszego katalogu wpisujemy w terminalu:&lt;br /&gt;[code]$ &quot;vendor/bin/doctrine&quot; orm:schema-tool:create[/code]&lt;br /&gt;Uruchomi nam to narzędzie z pakietu Doctrine służące do operacji na bazie danych, w tym przypadku wygeneruje nam ono tabelę opartą na naszym Entity opisanym w pliku &quot;User.php&quot;.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-bRJMH9CcclE/VWy_al_C-EI/AAAAAAAAIgs/Hdc2tUOeEjE/s1600/c2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;274&quot; src=&quot;http://4.bp.blogspot.com/-bRJMH9CcclE/VWy_al_C-EI/AAAAAAAAIgs/Hdc2tUOeEjE/s640/c2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Narzędzia tego będziemy zresztą używać później w celu aktualizacji struktury bazy podczas edycji naszego obiektu.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Krok 7 - dodajemy rekord za pomocą ORM&lt;/h2&gt;Jeśli wykonaliśmy już wszystkie poprzednie kroki, jesteśmy gotowi do pierwszej operacji za pomocą Doctrine.&lt;br /&gt;Wróćmy do pliku &quot;bootrstrap.php&quot; i dopiszmy na jego końcu to co poniżej:&lt;br /&gt;[code]&lt;br /&gt;// tworzymy nowy obiekt&lt;br /&gt;$user = new User();&lt;br /&gt;$user-&amp;gt;setLogin(&#39;janusz&#39;);&lt;br /&gt;$user-&amp;gt;setPassword(&#39;12345&#39;);&lt;br /&gt;&lt;br /&gt;$entityManager-&amp;gt;persist($user); // mówimy Doctrine, że tworzymy nowy obiekt&lt;br /&gt;$entityManager-&amp;gt;flush(); // wykonujemy zapis do bazy&lt;br /&gt;&lt;br /&gt;echo &quot;Dodano usera o id: &quot; . $user-&amp;gt;getId() . &quot;\n&quot;;[/code]&lt;br /&gt;Jak widać tworzymy tutaj nowy obiekt, ustawiamy mu dwie właściwości - login oraz password, a następnie zachowujemy go w bazie.&lt;br /&gt;Metoda $entityManager-&amp;gt;persist() odpowiada w Doctrine za umieszczenie rekordu w bazie, ale jeszcze nie wykonywania zapytania do niej.&lt;br /&gt;Do bazy nasz obiekt leci dopiero w momencie wykonania metody $entityManager-&amp;gt;flush(). Skąd taka konstrukcja? Otóż tutaj mamy jedynie prosty kod odpowiadający za dodanie raptem 1 rekordu, natomiast w całej aplikacji tego kodu może być bardzo dużo. W przypadku takim wykonanie metody flush() dopiero na samym końcu spowoduje, że wszystkie zapytania jakie zebrał w całym kodzie Doctrine zostaną objęte jedną transakcją i dopiero wykonane, co zwiększy wydajność i zmniejszy czas połączenia z serwerem bazy.&lt;br /&gt;&lt;br /&gt;Dołączmy zatem powyższy kod do bootstrapa:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// bootstrap.php&lt;br /&gt;// Dołączamy autoloader Composera&lt;br /&gt;require_once &quot;/vendor/autoload.php&quot;;&lt;br /&gt;&lt;br /&gt;// Określamy przestrzenie nazw z jakich skorzystamy&lt;br /&gt;use Doctrine\ORM\Tools\Setup;&lt;br /&gt;use Doctrine\ORM\EntityManager;&lt;br /&gt;&lt;br /&gt;// określamy ścieżkę do plików z Entities&lt;br /&gt;$paths = array(__DIR__.&#39;/src/Model&#39;);&lt;br /&gt;&lt;br /&gt;// informujemy, że pracujemy w środowisku developerskim, a nie na produkcji&lt;br /&gt;$isDevMode = true;&lt;br /&gt;&lt;br /&gt;// konfigurujemy dostęp do bazy&lt;br /&gt;$dbParams = array(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;driver&#39; &amp;nbsp; =&amp;gt; &#39;pdo_mysql&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;user&#39; &amp;nbsp; &amp;nbsp; =&amp;gt; &#39;root&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;password&#39; =&amp;gt; &#39;&#39;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &#39;dbname&#39; &amp;nbsp; =&amp;gt; &#39;doctrine_test&#39;,&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;// konfigurujemy Doctrine&lt;br /&gt;$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);&lt;br /&gt;$entityManager = EntityManager::create($dbParams, $config);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// tworzymy nowy obiekt&lt;br /&gt;$user = new User();&lt;br /&gt;$user-&amp;gt;setLogin(&#39;janusz&#39;);&lt;br /&gt;$user-&amp;gt;setPassword(&#39;12345&#39;);&lt;br /&gt;&lt;br /&gt;$entityManager-&amp;gt;persist($user); // mówimy Doctrine, że tworzymy nowy obiekt&lt;br /&gt;$entityManager-&amp;gt;flush(); // wykonujemy zapis do bazy&lt;br /&gt;&lt;br /&gt;echo &quot;Dodano usera o id: &quot; . $user-&amp;gt;getId() . &quot;\n&quot;;&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Następnie wejdźmy na:&lt;br /&gt;[code]http://localhost/doctrine/index.php[/code]&lt;br /&gt;&lt;br /&gt;Jeśli wszystko się udało to właśnie dodaliśmy swój pierwszy obiekt do bazy za pomocą Doctrine&#39;a:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-psk6CKYCuQw/VWy_Vtnys4I/AAAAAAAAIgk/bOpG0vSwe-0/s1600/w1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;214&quot; src=&quot;http://3.bp.blogspot.com/-psk6CKYCuQw/VWy_Vtnys4I/AAAAAAAAIgk/bOpG0vSwe-0/s640/w1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać, mimo kilku niezbędnych kroków jakie wykonać trzeba podczas rozpoczęcia pracy z Doctrine całość nie jest bardzo skomplikowana.&lt;br /&gt;Schodki zaczną się jednak później, gdyż Doctrine to naprawdę potężna i złożona biblioteka, której opanowanie zajmie trochę czasu. Mam jednak nadzieję, że w kolejnych artykułach omówimy sobie i przeanalizujemy wszystko dokładnie krok po kroku. Na chwilę obecną znamy podstawy i umiemy już dołączyć Doctrine do projektu, więc myślę, że tyle tytułem wstępu powinno na teraz wystarczyć.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/1915472901869042583/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/phpdoctrine2-instalacja-i-wstep-do.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1915472901869042583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1915472901869042583'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/06/phpdoctrine2-instalacja-i-wstep-do.html' title='[PHP][Doctrine2] Instalacja i wstęp do Doctrine2 ORM'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-jSXaYv8hOiQ/VWD0v_gahiI/AAAAAAAAH98/tbm6eSLjQd4/s72-c/icoPHP_doctrine.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-4301483683097307750</id><published>2015-05-31T23:22:00.002+02:00</published><updated>2015-05-31T23:22:10.889+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><category scheme="http://www.blogger.com/atom/ns#" term="Smarty"/><title type='text'>[PHP][Smarty] Instalacja i wstęp do Smarty</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-7emvoefECDw/VWD0ynfG-1I/AAAAAAAAH-Q/lw1r5qaH9so/s1600/icoPHP_smarty.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-7emvoefECDw/VWD0ynfG-1I/AAAAAAAAH-Q/lw1r5qaH9so/s1600/icoPHP_smarty.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Smarty to chyba najpopularniejszy system szablonów jaki istnieje do PHP. Rozwijany przez lata doczekał się już jakiś czas temu swojej 3 wersji. Smarty pozwala na całkowite rozdzielenie warstwy prezentacyjnej aplikacji od jej warstwy logiki. Rozbudowywany przez lata dorobił się naprawdę ogromu funkcji możliwości. W artykule tym zobaczymy w jaki sposób zainstalować silnik Smarty w swojej aplikacji oraz jak w podstawowy sposób z niego korzystać. Taka podstawowa wiedza pozwoli na zapoznanie się z systemem i umożliwi dalszą naukę tego co Smarty oferuje, a oferuje naprawdę bardzo wiele. Dzięki Smarty całkowicie oddzielimy warstwę prezentacji naszej aplikacji i zgodnie ze wzorcem MVC w pełni odseparujemy ją od reszty aplikacji. Na początek może krótkie wprowadzenie do tego czym jest i jak powinien być rozumiany wzorzec MVC. Nazwa tego wzorca to skrót od Model-View-Controller, a więc Model-Prezentacja-Kontroler. Jest to ogólnie przyjęty wzorzec projektowania aplikacji, który rozdziela ją na 3 niezależne, ale współpracujące ze sobą warstwy. Warstwa modelu odpowiada za wszystkie dane jakie przetwarza aplikacja, zarządza dostępem do bazy i zajmuje się przetwarzaniem wszystkich elementów z którymi pracuje aplikacja. Warstwa prezentacyjna odpowiada za wyświetlanie przetwarzanych przez warstwę modelu danych użytkownikowi i za interfejs komunikacji z nim. Warstwa kontrolera natomiast steruje tym wszystkim i zarządza aplikacją określając sposób w jaki przetwarzane w modelu dane przekazać użytkownikowi w warstwie prezentacji. Wzorzec bardzo praktyczny, efektywny i traktowany już obecnie jako standard w projektowaniu aplikacji. Smarty pracować bedzie w drugiej z omówionych warstw - a więc prezentacyjnej.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;Instalacja&lt;/h2&gt;Instalacja Smarty sprowadza się do pobrania bibliotek składających się na silnik oraz dołączeniu ich do własnej aplikacji. Najnowszą wersję pakietu pobierzemy zawsze z oficjalnej strony: &lt;a href=&quot;http://www.smarty.net/&quot; target=&quot;_blank&quot;&gt;http://www.smarty.net/.&lt;/a&gt; W dziale download znajdziemy link do repozytorium na GitHUB-ie, które następnie pobierzemy sobie na dysk. Pobierzmy zatem Smarty w wersji spakowanej zipem: &lt;a href=&quot;https://github.com/smarty-php/smarty/archive/master.zip&quot; target=&quot;_blank&quot;&gt;https://github.com/smarty-php/smarty/archive/master.zip&lt;/a&gt;&lt;br /&gt;Pod tym linkiem znajduje się zawsze najnowsza, stabilna wersja biblioteki Smarty.&lt;br /&gt;Możemy też odwiedzić repozytorium bezpośrednio: &lt;a href=&quot;https://github.com/smarty-php/smarty&quot; target=&quot;_blank&quot;&gt;https://github.com/smarty-php/smarty&lt;/a&gt;&lt;br /&gt;Jeśli natomiast chcemy pobrać bibliotekę za pomocą GIT-a, to link do sklonowania repozytorium wygląda tak:&lt;br /&gt;[code]git clone https://github.com/smarty-php/smarty.git[/code]&lt;br /&gt;&lt;br /&gt;Smarty możemy także pobrać za pomocą Composera - pisałem o tym w &lt;a href=&quot;http://www.phpeverywhere.blogspot.com/2015/05/phpcomposer-instalacja-i-podstawy.html&quot; target=&quot;_blank&quot;&gt;tym artykule&lt;/a&gt;, przy okazji omówienia podstaw obsługi Composera. Aby zainstalować z poziomu Composera, tworzymy plik &quot;composer.json&quot; w folderze, gdzie chcemy pobrać Smarty o treści:&lt;br /&gt;[code]&lt;br /&gt;&quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;smarty/smarty&quot;: &quot;~3.1&quot;&lt;br /&gt;}[/code]&lt;br /&gt;Następnie uruchamiamy Composera i instalujemy:&lt;br /&gt;[code]$ composer install[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Zaczynamy&lt;/h2&gt;Niezależnie, którego sposobu użyliśmy, trafiły do nas te same pliki.&lt;br /&gt;Rozpakujmy pobrane archiwum (jeśli pobraliśmy plik .zip) i skopiujmy zawarty w archiwum katalog:&lt;br /&gt;[code]/libs[/code]&lt;br /&gt;do katalogu z naszym projektem, np.&lt;br /&gt;[code]C:/www/smarty/libs[/code]&lt;br /&gt;(będę się tu posługiwał takim przykładem, gdzie &quot;C:/www&quot; to Document Root webserwera)&lt;br /&gt;W katalogu &quot;/libs&quot; znajdują się wszystkie potrzebne dla nas biblioteki.&lt;br /&gt;&lt;br /&gt;Jeśli chcemy zobaczyć Smarty w działaniu to skopiujmy również katalog &quot;/demo&quot; i zobaczmy:&lt;br /&gt;[code]http://localhost/smarty/demo/[/code]&lt;br /&gt;&lt;br /&gt;Teraz, aby móc zacząć pracę ze Smarty musimy utworzyć trzy podkatalogi w katalogu z naszym projektem:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;C:/www/smarty/&lt;b&gt;templates&lt;/b&gt;&lt;/li&gt;&lt;li&gt;C:/www/smarty/&lt;b&gt;templates_c&lt;/b&gt;&lt;/li&gt;&lt;li&gt;C:/www/smarty/&lt;b&gt;cache&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Muszą mieć one uprawnienia do zapisu przez PHP, co na Windowsach nie wymagać będzie żadnych zabiegów, ale już na Linuxach trzeba tym katalogom ustawić:&lt;br /&gt;[code]chmod 775[/code]&lt;br /&gt;&lt;br /&gt;W folderach:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;/templates &lt;/b&gt;- trzymać będziemy nasze szablony w postaci plików .tpl&lt;/li&gt;&lt;li&gt;&lt;b&gt;/templates_c&lt;/b&gt; - tutaj trzymane będą skompilowane do kodu PHP wersje szablonów&lt;/li&gt;&lt;li&gt;&lt;b&gt;/cache&lt;/b&gt; - trzymany tu będzie finalnie wygenerowany i skompilowany przez Smarty widok&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Jak widać po samej strukturze folderów - Smarty kompiluje szablony do wersji z normalnym kodem PHP. Dzięki temu biblioteka działa szybciej, gdyż nie musi za każdym razem parsować od nowa tego samego szablonu, a jedynie podstawić zmienne do wersji skompilowanej.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Pierwszy projekt&lt;/h2&gt;Stworzymy sobie teraz pierwszy projekt z użyciem Smarty i zobaczymy jak to mniej więcej działa.&lt;br /&gt;Utwórzmy plik:&lt;br /&gt;[code]C:/www/smarty/index.php[/code]&lt;br /&gt;tak, aby mieć do niego dostęp z poziomu:&lt;br /&gt;[code]http://localhost/smarty/index.php[/code]&lt;br /&gt;i dołączmy do niego bibliotekę Smarty:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/* index.php */&lt;br /&gt;&lt;br /&gt;require &#39;/libs/Smarty.class.php&#39;;&lt;br /&gt;$smarty = new Smarty;&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Będzie to nasz główny plik z kodem PHP.&lt;br /&gt;Następnie utwórzmy prosty plik z szablonem strony:&lt;br /&gt;[code]C:/www/smarty/templates/index.tpl[/code]&lt;br /&gt;I jako zawartość wklejmy mu prosty kod HTML:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;Smarty&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;h1&amp;gt;Testujemy Smarty&amp;lt;/h1&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;[/code]&lt;br /&gt;(pamiętajmy o rozszerzeniu - plik mówi mieć końcówkę .tpl, a nie .php)&lt;br /&gt;&lt;br /&gt;Mamy już dwa bazowe pliki, których będziemy tutaj używać, zobaczmy teraz na jakiej zasadzie działa Smarty.&lt;br /&gt;&lt;h4&gt;Po stronie kodu - index.php&lt;/h4&gt;W pliku &quot;index.php&quot; znajdować się będzie cały kod z jakiego składać się będzie nasza prosta, przykładowa aplikacja. Kod ten nie będzie wyświetlać żadnych danych, będzie jedynie je generować i przetwarzać. Wszelkie dane jakie będą miały być wyświetlone na ekranie zostaną z poziomu tego pliku wysłane do silnika Smarty, który następnie przetworzy nasz szablon (znajdujący się w pliku .tpl) i podstawi do niego wygenerowane przez naszą aplikację dane, a następnie taki szablon - uzupełniony o nasze dane wyświetlli na ekranie. Skąd jednak Smarty ma wiedzieć co i gdzie ma wyświetlić? Musimy mu o tym powiedzieć, a zrobimy to za pomocą metody:&lt;br /&gt;[code]$smarty-&amp;gt;assign(&#39;nazwa&#39;, $zmienna);[/code]&lt;br /&gt;Metoda assign() przypisuje zmienne do szablonu i mówi silnikowi Smarty, aby w miejscu w szablonie, które zostanie oznaczone znacznikiem &lt;b&gt;nazwa&lt;/b&gt; wstawić wartość zmiennej &lt;b&gt;$zmienna&lt;/b&gt;.&lt;br /&gt;&lt;h4&gt;Po stronie szablonu - /templates/index.tpl&lt;/h4&gt;W pliku &quot;index.tpl&quot; nie znajdzie sie ani jedna linijka kodu PHP. Zamiast tego, w miejscach, gdzie mają wyświetlić się dane generowane przez PHP wstawimy odpowiednie znaczniki z nazwami.&lt;br /&gt;Znacznik taki będzie miał w szablonie postać:&lt;br /&gt;[code]{$nazwa_znacznika}[/code]&lt;br /&gt;Jak więc widzimy, znacznik to nazwa ze znakiem dolara objęta w nawiasy klamrowe.&lt;br /&gt;Nazwę tę definiujemy podczas przypisania zmiennej w pliku &quot;index.php&quot; metodą $smarty-&amp;gt;assign().&lt;br /&gt;&lt;br /&gt;I tak na przykład:&lt;br /&gt;[code]$smarty-&amp;gt;assign(&#39;site_title&#39;, $title);[/code]&lt;br /&gt;czyli przypisanie wykonane w kodzie w pliku &quot;index.php&quot;, spowoduje, że w pliku &quot;index.tpl&quot;, w miejscu gdzie wystąpi znacznik:&lt;br /&gt;[code]{$site_title}[/code]&lt;br /&gt;wyświetlona zostanie wartość zmiennej $title.&lt;br /&gt;&lt;br /&gt;Zobaczmy to na prostym przykładzie:&lt;br /&gt;Plik &quot;index.php&quot;:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/* index.php */&lt;br /&gt;// dołączamy bibliotekę Smarty&lt;br /&gt;require &#39;/libs/Smarty.class.php&#39;;&lt;br /&gt;$smarty = new Smarty;&lt;br /&gt;&lt;br /&gt;// tworzymy zmienne&lt;br /&gt;$title = &#39;Smarty test&#39;;&lt;br /&gt;$time = date(&#39;H:i:s&#39;);&lt;br /&gt;$text = &#39;Hello World!&#39;;&lt;br /&gt;$footer = &#39;a to stopka&#39;;&lt;br /&gt;&lt;br /&gt;// przypisujemy zmienne do szablonu&lt;br /&gt;$smarty-&amp;gt;assign(&#39;site_title&#39;, $title);&lt;br /&gt;$smarty-&amp;gt;assign(&#39;time&#39;, $time);&lt;br /&gt;$smarty-&amp;gt;assign(&#39;text&#39;, $text);&lt;br /&gt;&lt;br /&gt;$smarty-&amp;gt;display(&#39;index.tpl&#39;);&lt;br /&gt;// renderujemy widok z szablonu index.tpl&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Teraz w pliku &quot;/templates/index.tpl&quot;:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;{$site_title}&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;h2&amp;gt;{$text}/h2&amp;gt;&lt;br /&gt;Obecna godzina to: {$time}&lt;br /&gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;{$footer}&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Zapisujemy pliki i wchodzimy na:&lt;br /&gt;[code]http://localhost/smarty/index.php[/code]&lt;br /&gt;&lt;br /&gt;Wyświeti nam się:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-ssWcEfG7YCY/VWt22RXbJWI/AAAAAAAAIgQ/UhzOyJN7UGc/s1600/s1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;422&quot; src=&quot;http://2.bp.blogspot.com/-ssWcEfG7YCY/VWt22RXbJWI/AAAAAAAAIgQ/UhzOyJN7UGc/s640/s1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Zaglądając w źródło zobaczymy, że jest to dokładnie nasz szablon wypełniony odpowiednimi zmiennymi:&lt;br /&gt;[code]&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;title&amp;gt;Smarty test&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;h2&amp;gt;Hello World!&amp;lt;/h2&amp;gt;&lt;br /&gt;Obecna godzina to: 22:52:10&lt;br /&gt;&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;a tutaj stopka&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;I to tyle tytułem podstawowego wprowadzenia do Smarty.&lt;br /&gt;Wiemy już jak mniej więcej to działa, więc w kolejnych artykułach zajmiemy się dalszymi kwestiami i już normalną pracą ze Smarty.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/4301483683097307750/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/phpsmarty-instalacja-i-wstep-do-smarty.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/4301483683097307750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/4301483683097307750'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/phpsmarty-instalacja-i-wstep-do-smarty.html' title='[PHP][Smarty] Instalacja i wstęp do Smarty'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-7emvoefECDw/VWD0ynfG-1I/AAAAAAAAH-Q/lw1r5qaH9so/s72-c/icoPHP_smarty.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-1325544631049773391</id><published>2015-05-31T19:36:00.001+02:00</published><updated>2015-05-31T19:50:37.248+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Composer"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><title type='text'>[PHP][Composer] Instalacja i podstawy używania Composera</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-OijnHb0_SwU/VWD0v2nly6I/AAAAAAAAH90/ZbLhR0Sja7g/s1600/icoPHP_composer.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-OijnHb0_SwU/VWD0v2nly6I/AAAAAAAAH90/ZbLhR0Sja7g/s1600/icoPHP_composer.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Composer to popularna aplikacja do obsługi zależności pomiędzy bibliotekami w zadanych projektach. Na czym to polega? Otóż pracując nad swoim projektem bardzo często wykorzystujemy jakieś biblioteki i komponenty osób trzecich. Przykładowo - pisząc aplikację korzystającą z ORM Doctrine do obsługi bazy nasza aplikacja jest zależna od tej właśnie biblioteki i wymaga jej do poprawnej pracy. Bibliotekę oczywiście możemy na stałe dołaczyć do naszego projektu, ale jest to rozwiązanie nieeleganckie. Z pomocą przychodzi właśnie Composer - wystarczy, że spreparujemy odpowiedni plik z informacją dla Composera, w której opiszemy od jakich zewnętrznych bibliotek zależny jest nasz projekt i jakich wymaga do poprawnego działania. Composer następnie podczas instalacji naszej aplikacji odczyta nasz plik z opisem zależności, pobierze je i umieści w naszym projekcie. Takie zewnetrzne biblioteki zazwyczaj lądują w katalogu /vendor. Co najlepsze - Composer pobierze także zależności dla bibliotek, od jakich zależna jest nasza aplikacja - bo trzeba zauważyć, że może się zdarzyć, że korzystamy z zewnętrznej biblioteki, która do swojego działania wymaga jeszcze innej zewnętrznej biblioteki. Composer wszystko to &amp;nbsp;automatycznie uwzgledni.&lt;br /&gt;&lt;br /&gt;Z Composera korzysta wiele dużych projektów, np. instalując framework Symfony instalujemy go właśnie za pomocą Composera. Jego instalacja w systemie jest prosta i sprowadza się do kilku kroków. Opiszę poniżej sposób instalacji w systemach z rodziny Windows. W Windowsie możemy to zrobić na dwa sposoby - pobierając instalator, który zrobi wszystko za nas, lub manualnie - za pomocą terminala. Opiszę drugi sposób, żeby pokazać jak Composer wygląda &quot;od środka&quot;.&lt;br /&gt;Jeśli jednak chcemy to zrobić to automatycznie, to podaję link do instalatora: &lt;a href=&quot;https://getcomposer.org/Composer-Setup.exe&quot; target=&quot;_blank&quot;&gt;https://getcomposer.org/Composer-Setup.exe&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Oficjalna strona Composera to:&lt;/b&gt; &lt;a href=&quot;https://getcomposer.org/&quot; target=&quot;_blank&quot;&gt;https://getcomposer.org/&lt;/a&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;Instalacja manualna&lt;/h2&gt;Zainstallujemy Composera manualnie. Pozwoli nam to zobaczyć czym tak naprawdę jest Composer.&lt;br /&gt;Do zainstalowania wymagane jest PHP w wersji conajmniej 5.3.2 więc zakładam, że takową lub wyższą wersję już posiadamy. Pierwszym krokiem jest wejście w terminal, utworzenie folderu w którym Composera chcemy zainstalować i z poziomu tego folderu wykonanie komendy:&lt;br /&gt;[code]$ php -r &quot;readfile(&#39;https://getcomposer.org/installer&#39;);&quot; | php[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-k1VtqjHGPaE/VWtCIOBXxSI/AAAAAAAAIfY/ouzWu5XZPYI/s1600/c1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;438&quot; src=&quot;http://4.bp.blogspot.com/-k1VtqjHGPaE/VWtCIOBXxSI/AAAAAAAAIfY/ouzWu5XZPYI/s640/c1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Pobierze nam to Composera do katalogu, w którym się znajdujemy.&lt;br /&gt;Po instalacji dopisujemy ścieżkę do folderu z Composerem do zmiennej PATH:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-37o9QLJQzLE/VWtCN0TH3SI/AAAAAAAAIfg/nMZmoEKTDWk/s1600/w1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;500&quot; src=&quot;http://2.bp.blogspot.com/-37o9QLJQzLE/VWtCN0TH3SI/AAAAAAAAIfg/nMZmoEKTDWk/s640/w1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Dopisujemy tutaj na końcu po średniku ścieżkę do katalogu z Composerem, zatwierdzamy i ponownie uruchamiamy terminal (terminal odczytuje zmienną PATH tylko raz podczas uruchomienia).&lt;br /&gt;Następnie w katalogu z Composerem tworzymy plik:&lt;br /&gt;[code]composer.bat[/code]&lt;br /&gt;i wpisujemy do niego:&lt;br /&gt;[code]echo @php &quot;%~dp0composer.phar&quot; %*&amp;gt;composer.bat[/code]&lt;br /&gt;Mając już dodaną ścieżkę i pobranego Composera sprawdźmy, czy wszystko działa poprawnie, wpisujac w terminalu:&lt;br /&gt;[code]$ composer -V[/code]&lt;br /&gt;Powinna nam się wyświetlić informacja o aktualnie zainstalowanej wersji Composera:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-JAhQGun9dUo/VWtCR_Ft4EI/AAAAAAAAIfo/ChxEwkLQCeY/s1600/c2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;438&quot; src=&quot;http://2.bp.blogspot.com/-JAhQGun9dUo/VWtCR_Ft4EI/AAAAAAAAIfo/ChxEwkLQCeY/s640/c2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widzimy w katalogu - Composer to jeden plik o nazwie:&lt;br /&gt;[code]composer.phar[/code]&lt;br /&gt;Czym jest PHAR? Otóż PHAR jest to spakowane archiwum z aplikacją napisaną w PHP. Możemy tworzyć takie archiwa sami pakując nasze aplikacje do tego typu archiwum, ale o tym w innym artykule. Taki plik jest normalnie uruchamiany i wykonywany przez interpreter PHP za pomocą komendy:&lt;br /&gt;[code]$ php achiwum_z_aplikacją.phar[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Konfiguracja - composer.json&lt;/h2&gt;Wróćmy jednak do naszego Composera. Mamy już zainstalowaną aplikację, pora teraz na wytłumaczenie kilku spraw odnośnie używania Composera. Po pierwsze - tak jak to zostało wspomniane na wstępie - dla Composera musi zostać przygotowany specjalny plik, który określi mu listę zależności jakie należy pobrać i doinstalować. Plik taki przygotowujemy w formacie JSON i umieszczamy w katalogu z aplikacją, dla której chcemy pobrać zależne biblioteki. Nazwa takiego pliku to zawsze:&lt;br /&gt;[code]composer.json[/code]&lt;br /&gt;a jego zawartość wygląda tak:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;dostawca/nazwa_aplikacji&quot;: &quot;wersja_aplikacji&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;&lt;br /&gt;Przykładowo, jeśli chcemy zawrzeć tutaj np. pakiet Smarty, który chcemy dołączyć do naszej aplikacji - podać możemy:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;smarty/smarty&quot;: &quot;3.1.19&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;co oznaczać będzie dokładnie to: moja aplikacja wymaga do działania biblioteki &quot;smarty&quot; od dostawcy o nazwie &quot;smarty&quot; w wersji &quot;3.1.19&quot;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Instalacja zależności - composer install&lt;/h2&gt;Sprawdźmy teraz to w praktyce. Utwórzmy katalog o nazwie &quot;smarty&quot; i wejdźmy do niego w terminalu.&lt;br /&gt;W katalogu tym umieśćmy plik &quot;composer.json&quot; o treści:&lt;br /&gt;[code]&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;require&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;smarty/smarty&quot;: &quot;~3.1&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;}[/code]&lt;br /&gt;(przed cyfrą 3 znajduje się znak tyldy jeśli jest to mało widoczne)&lt;br /&gt;Następnie wykonajmy polecenie:&lt;br /&gt;[code]$ composer install[/code]&lt;br /&gt;które pobierze i zainstaluje nam tutaj pakiet Smarty w najnowszej dostępnej wersji z gałęzi 3.1.x:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-p3ikxDpAJV8/VWtCcmEgaZI/AAAAAAAAIfw/uCIXs5BRDlk/s1600/c3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;402&quot; src=&quot;http://3.bp.blogspot.com/-p3ikxDpAJV8/VWtCcmEgaZI/AAAAAAAAIfw/uCIXs5BRDlk/s640/c3.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Możemy też przekopiować plik &quot;composer.phar&quot; do tego katalogu i wykonać go poleceniem:&lt;br /&gt;[code]$ php composer.phar install[/code]&lt;br /&gt;&lt;br /&gt;Zobaczmy teraz w naszym folderze - jeśli wszystko poszło dobrze to Smarty zostało zainstalowane do katalogu /vendor:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-mm2G2NWFBLQ/VWtCi3EOPYI/AAAAAAAAIf4/W8AHfUDCzIM/s1600/w2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;114&quot; src=&quot;http://4.bp.blogspot.com/-mm2G2NWFBLQ/VWtCi3EOPYI/AAAAAAAAIf4/W8AHfUDCzIM/s640/w2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Przy okazji, jak widzimy - utworzył się nam tam też plik:&lt;br /&gt;[code]autoload.php[/code]&lt;br /&gt;o treści mniej więcej takiej:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;&lt;br /&gt;// autoload.php @generated by Composer&lt;br /&gt;&lt;br /&gt;require_once __DIR__ . &#39;/composer&#39; . &#39;/autoload_real.php&#39;;&lt;br /&gt;&lt;br /&gt;return ComposerAutoloaderInit9ff9d8a01182b790e18358de1f571cba::getLoader();[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Autoładowanie klas - autoload.php&lt;/h2&gt;Composer jak widzimy automatycznie tworzy plik autoładujący dołączane biblioteki! Nie musimy więc martwić się o odpowiednie dołączanie pobieranych bibliotek, wystarczy teraz, że w naszym projekcie podamy jedynie ścieżkę do autoloadera stworzonego przez Composera:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;require __DIR__ . &#39;/vendor/autoload.php&#39;;&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;a całą resztę - związaną z załadowaniem odpowiednich klas wykona już za nas on sam, a konrektnie plik autoload.php przez niego wygenerowany. Jest to bardzo fajna i przydatna funkcjonalność Composera. Oczywiście nic nie stoi na przeszkodzie, aby korzystać z własnego autoloadera, Composer niczego tutaj na nas nie wymusza, a jedynie oferuje funkcjonalność z której jeśli chcemy to możemy skorzystać.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Wersjonowanie&lt;/h2&gt;Pobierając pakiet Smarty podaliśmy w pliku &quot;composer.json&quot; następującą nazwę wymaganej wersji:&lt;br /&gt;[code]~3.1[/code]&lt;br /&gt;(z tyldą na początku)&lt;br /&gt;&lt;br /&gt;W Composerze możemy określić nazwę wymaganej wersji wg kilku odpowiednich wytycznych. Służy do tego odpowiednia składnia, która wygląda następująco:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;1.0.0&lt;/b&gt; - określa, że wymagana jest DOKŁADNIE wersja 1.0.0&lt;/li&gt;&lt;li&gt;&lt;b&gt;&amp;gt;=1.0 &lt;/b&gt;- określa, że wymagana jest wersja conajmniej 1.0, w przypadku istnienia wersji nowszej od 1.0 Composer pobierze najnowszą dostępną wersję&lt;/li&gt;&lt;li&gt;&lt;b&gt;&amp;gt;=1.0 &amp;lt; 2.1&lt;/b&gt; - określa, że wymagana jest wersja conajmniej 1.0, ale mniejsza niż 2.1&lt;/li&gt;&lt;li&gt;&lt;b&gt;1.0 - 3.0 &lt;/b&gt;- określa, że interesuje nas wersja z przedziału od 1.0 do 3.0&lt;/li&gt;&lt;li&gt;&lt;b&gt;1.0.*&lt;/b&gt; - określa, że interesuje nas wersja z przedziału od 1.0.x do 1.1.0&lt;/li&gt;&lt;li&gt;&lt;b&gt;~1.3&lt;/b&gt; - określa, że interesuje nas wersja z przedziału 1.3, ale mniejsza od następnego końcowego numerka, czyli 1.4, np. 1.3.1, 1.3.5, 1.3.9,&lt;/li&gt;&lt;li&gt;&lt;b&gt;^1.3&lt;/b&gt; - określa, że intersuje nas wersja większa lub równa 1.3, ale mniejsza od następnego początkowego numerka, czyli 2.0, np. 1.3, 1.8, 1.9.9&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Composer zasze pobiera najnowszą aktualnie dostępną wersję z zadanego przedziału, lub konkretnie tą jedną wymaganą, jeśli zamiast przedziału podajemy dokładny numer wersji.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Blokada wersji - composer.lock&lt;/h2&gt;W katalogu do którego pobieraliśmy Smarty jak może już zauważyliśmy utworzył się jeszcze jeden plik - &quot;composer.lock&quot;.&lt;br /&gt;Warto wiedzieć do czego on słuzy. Otóż w pliku tym Composer zapisuje informacje o aktualnie pobranych tutaj zależnościach (w naszym przypadku - Smarty) i ich dokładnych wersjach.&lt;br /&gt;Wyobraźmy sobie teraz, że hostujemy nasz projekt jako repozytorium na GitHUB-ie, do którego ma dostęp cała masa innych programistów. Programista taki klonuje sobie nasze repozytorium, instaluje do niego wymagane zależności dzięki plikowi composer.js, który mówi mu jakie zależności pobrać należy i nagle okazuje się, że otrzymuje do pracy lekko odmienną wersję. Dlaczego?&lt;br /&gt;&lt;br /&gt;Ponieważ np. w pliku &quot;composer.json&quot; określiliśmy, iż nasza aplikacja wymaga do pracy danej biblioteki w wersji conajmniej 1.1 i taka też najnowsza wersja była dostępna w momencie commitowania repozytorium. Godzinę później natomiast dostawca naszej zależności wypuszcza wersję 1.2, która od tej pory staje się najnowszą dostępną wersją. Programista jaki teraz pobierze nasze repozytorium i instalując zależności przez Composera otrzyma już nie wersję 1.1, a wersję 1.2. I do prewencji przed takim czymś służy właśnie plik &quot;composer.lock&quot;.&lt;br /&gt;&lt;br /&gt;Określa on, jaka jest aktualna wersja zależności na której obecnie pracujemy. Jeśli teraz w pliku &quot;composer.lock&quot; mamy zapisaną informację, iż w momencie wysyłania repozytorium pracujemy z wersją 1.1 zależnej biblioteki, to programista klonujący nasze repozytorium otrzyma od Composera właśnie taką wersję, a my będziemy mieli pewność, że osoba, która teraz pracuje z naszym repozytorium pracuje na DOKŁADNIE takiej samej wersji plików jak my. Dlatego pamiętajmy o tym, aby podczas commita zawsze wysyłać do repozytorium również plik &quot;composer.lock&quot;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Aktualizacja zależności - composer update&lt;/h2&gt;Aktualizacji do nowszej wersji danej zależności (o ile taka wyszła) dokonujemy za pomocą:&lt;br /&gt;[code]$ composer update[/code]&lt;br /&gt;W przypadku nowszych wersji, niż ta którą posiadamy wyświetli się nam po prostu komunikat &quot;Nothing to update&quot;:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-pzDc603u1P0/VWtCyRe-tVI/AAAAAAAAIgA/nMkXBZxnuNU/s1600/c4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;402&quot; src=&quot;http://1.bp.blogspot.com/-pzDc603u1P0/VWtCyRe-tVI/AAAAAAAAIgA/nMkXBZxnuNU/s640/c4.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jeśli natomiast pojawila się nowsza wersja (np. Smarty w naszym przypadku) to Composer ją pobierze i zaktualizuje nam bibliotekę do nowszej wersji. Jeśli natomiast korzystamy z kilku zależności, a chcemy zaktualizować tylko jedną, lub kilka określonych podajemy je po spacji za komendą update, np.:&lt;br /&gt;[code]$ composer update smarty/smarty inna/inna jeszcze_inna/jeszcze_inna[/code]&lt;br /&gt;&lt;br /&gt;Jak widzimy, Composer to bardzo fajne i pomocne narzędzie. Za takim stwierdzeniem świadczyć powinien choćby fakt, iż wszystkie większe projekty korzystają z jego dobrodziejstw. Zapoznanie się z nim jest więc czasem wręcz konieczne. Mam nadzieję, że dzięki temu wpisowi umiecie już w podstawowy korzystać z Composera. W następnym artykule opiszę w jaki sposób utworzyć i udostępnić swoją własną paczkę, tak aby można ją było pobrać poprzez wpis w &quot;composer.json&quot;.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/1325544631049773391/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/phpcomposer-instalacja-i-podstawy.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1325544631049773391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1325544631049773391'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/phpcomposer-instalacja-i-podstawy.html' title='[PHP][Composer] Instalacja i podstawy używania Composera'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-OijnHb0_SwU/VWD0v2nly6I/AAAAAAAAH90/ZbLhR0Sja7g/s72-c/icoPHP_composer.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-3673455057687492124</id><published>2015-05-31T19:12:00.000+02:00</published><updated>2015-05-31T19:12:48.160+02:00</updated><title type='text'>[PHP] Kiedy cudzysłów, a kiedy apostrof</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-6cFcflleS2I/VWD0psfbeNI/AAAAAAAAH8k/xPXHXjhqDPo/s1600/icoPHP_BASIC.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-6cFcflleS2I/VWD0psfbeNI/AAAAAAAAH8k/xPXHXjhqDPo/s1600/icoPHP_BASIC.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;...czyli różnica pomiędzy cudzysłowem, a apostrofem.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;W PHP, jak i we właściwie każdym języku wszelkie zmienne typu string obejmować musimy w cudzysłowy, lub apostrofy. Mamy tutaj dowolność, jeśli chodzi o wybór - obie formy są poprawne, byleby znak otwierający zgadzał się ze znakiem kończącym. Na pierwszy rzut oka używanie cudzysłowów albo apostrofów nie różni się od siebie działaniem. Różnica jednak jest, o czym wiele osób - szczególnie początkujących nie ma pojęcia. Różnica jest w sposobie interpretacji zawartości objętej cudzysłowem/apostrofem jak i co za tym idzie - w szybkości przetwarzania kodu przez interpreter. Pisząc kod zawsze powinniśmy starać się o to, aby był on jak najprostszy i jak najszybciej kompilowany przez interpreter. Te malutkie z pozoru różnice w czasie wykonywania kodu urastają do trochę większych, gdy serwer musi obsłużyć takich wykonań tysiące i ma ku temu ograniczone zasoby. Trzeba o tym pamiętać. Wróćmy zatem do tematu o jakim jest ten tekst.&lt;br /&gt;&lt;br /&gt;Popatrzmy na przykład poniżej. Z pozoru obie linijki kodu nie różnią się niczym i wykonają się tak samo, ale jak to mówią - pozory mylą.&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$zmienna1 = &quot;jakiś tekst&quot;;&lt;br /&gt;$zmienna2 = &#39;jakiś tekst&#39;;&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Dla człowieka niby tak samo, a jednak dla interpretera PHP zupełnie inaczej. Na czym więc polega różnica w obu zapisach (poza faktem wizualnym oczywiście)? Otóż polega ona na tym w jaki sposób PHP traktuje taki ciąg znaków. Aby bardziej zobrazować sobie to na przykładzie, popatrzmy na poniższe:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$kolor = &#39;czerwony&#39;;&lt;br /&gt;$str1 = &quot;Mój ulubiony kolor to: $kolor&quot;;&lt;br /&gt;$str2 = &#39;Mój ulubiony kolor to: $kolor&#39;;&lt;br /&gt;echo $str1 . &#39;&amp;lt;br /&amp;gt;&#39;;&lt;br /&gt;echo $str2;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;Wynik:&lt;br /&gt;Mój ulubiony kolor to: czerwony&lt;br /&gt;Mój ulubiony kolor to: $kolor&lt;br /&gt;*/&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Jak widać wyświetlenie zmiennej $str1 i $str2 daje zupełnie inne wyniki. Powodem jest fakt, iż ciągi objęte w cudzysłowy ( &quot; ) są przez PHP interpretowane, natomiast ciągi objęte w apostrofy ( &#39; ) już nie. Ciąg objęty w cudzysłowy musi być zatem przez PHP przeparsowany i przetworzony w celu m.in. podstawienia wartości ewentualnie występujących w nim zmiennych, co za tym idzie - jest to jakieś dodatkowe zadanie dla procesora. Ciąg natomiast objęty w apostrofy jest z marszu traktowany jako zwykły, najzwyklejszy tekst i nie jest w żaden sposób przetwarzany, co za tym idzie - jest &quot;obrabiany&quot; przez PHP o wiele szybciej. Różnicę zauważymy też m.in. w przetwarzaniu znaków specjalnych, jak np. znak końca linii:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$str1 = &quot;To jest pierwsza linia.\nTo jest druga linia.&quot;;&lt;br /&gt;$str2 = &#39;To jest pierwsza linia.\nTo jest druga linia.&#39;;&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Wyświetlenie teraz zmiennej $str1 pokaże nam:&lt;br /&gt;[code]&lt;br /&gt;To jest pierwsza linia.&lt;br /&gt;To jest druga linia.[/code]&lt;br /&gt;&lt;br /&gt;Natomiast wyświetlenie drugiej zmiennej - $str2 pokaże:&lt;br /&gt;[code]To jest pierwsza linia.\nTo jest druga linia.[/code]&lt;br /&gt;W drugim przypadku znak &quot;\n&quot; nie zostanie w żaden sposób przetworzony na znak końca linii i potraktowany &quot;na surowo&quot;.&lt;br /&gt;Trzeba mieć też świadomość, że ciąg objęty w cudzysłowy jest przetwarzany przez PHP nawet wtedy, gdy nie ma w nim żadnych zmiennych, ani żadnych znaków specjalnych (trzeba przecież przeparsować wszystko, aby sprawdzić czy takowe nie występują). Jest to obciążenie dla interpretera i powinno się tego unikać. Pamiętajmy zatem więc, żeby zawsze wszędzie tam, gdzie nie ma konieczności używania cudzysłowów (a czasem taka potrzeba jest) używać zwykłych apostrofów.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/3673455057687492124/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-kiedy-cudzyslow-kiedy-apostrof.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3673455057687492124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3673455057687492124'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-kiedy-cudzyslow-kiedy-apostrof.html' title='[PHP] Kiedy cudzysłów, a kiedy apostrof'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-6cFcflleS2I/VWD0psfbeNI/AAAAAAAAH8k/xPXHXjhqDPo/s72-c/icoPHP_BASIC.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-124958770973507776</id><published>2015-05-31T02:19:00.001+02:00</published><updated>2015-05-31T02:21:14.423+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="CSS3"/><category scheme="http://www.blogger.com/atom/ns#" term="HTML5_CSS3"/><title type='text'>[CSS3] Zaokrąglanie narożników</title><content type='html'>&lt;style&gt;.csssample_rounded_1 { border-radius: 25px; background: #8AC007; color: #fff; padding: 20px;  width: 300px; height: 250px;     }  .csssample_rounded_2 { border-radius: 5px; background: none; border: 5px solid #8AC007; color: #000; padding: 20px;  width: 300px; height: 250px;     }  .csssample_rounded_3 { border-radius: 50px; background-image:url(&#39;http://1.bp.blogspot.com/-4dabtqdUXYo/VWZr1iOaFFI/AAAAAAAAIR8/bDjsSYMlc_A/s640/monica.jpg&#39;); background-repeat: no-repeat; background-position: left top; border:1px solid #000; color: #000; padding: 20px;  width: 300px; height: 250px;     }  .csssample_rounded_4 { border-radius: 30px; background-image:url(&#39;http://1.bp.blogspot.com/-XgmcxcbsIa4/VWZrmayIn2I/AAAAAAAAIR0/HADps5dqmEo/s640/angelina.jpg&#39;); background-repeat: no-repeat; background-position: left top; border: 5px dotted #8AC007; color: #fff; padding: 20px;  width: 300px; height: 250px;     }  .csssample_rounded_5 { border-radius: 25px 0 0 0; background: #8AC007; color: #fff; padding: 20px;  width: 300px; height: 250px;     }  .csssample_rounded_6  { border-radius: 0 25px 0 0; background: #6b9503; color: #fff; padding: 20px;  width: 300px; height: 250px;     } .csssample_rounded_7 { border-radius: 0 0 0 25px; background: #6b9503; color: #fff; padding: 20px;  width: 300px; height: 250px;     } .csssample_rounded_8 { border-radius: 0 0 25px 0; background: #8AC007; color: #fff; padding: 20px;  width: 300px; height: 250px;     } &lt;/style&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-8XbbBiXCeXU/VWpRIG5dNtI/AAAAAAAAIfE/xeVsuiInMZk/s1600/icoCSS.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-8XbbBiXCeXU/VWpRIG5dNtI/AAAAAAAAIfE/xeVsuiInMZk/s1600/icoCSS.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;CSS3 pozwala na tworzenie zaokrąglonych elementów. To co kiedyś trzeba było robić za pomocą specjalnie przyciętych obrazków, teraz można zrobić za pomocą stylu CSS. Wszystkie przeglądarki obsługują tą własność poprawnie, więc w tym przypadku nie trzeba posiłkować się prefixami przeglądarek, co zawsze wydłuża definicję styli. W tym krótkim wpisie nauczymy się robić zaokgrąglone obramowania dla elementów. Zaokrąglone krawędzie można zaaplikować praktycznie do każdego blokowego elementu HTML. Własność CSS jaka będzie nas interesować w celu zaokrąglenia narożnika elementu to:&lt;br /&gt;&lt;br /&gt;[code]border-radius: wartość [px];[/code]&lt;br /&gt;&lt;br /&gt;Możemy zaokrąglić wszystkie 4 narożniki, lub tylko któryś z nich, bądż też każdy z nich za pomocą innej wartości. Na początek określmy jedną wartość dla wszystkich rogów. Popatrzmy na prykłady z różnymi kombinacjami. Im więcej pikseli podamy w zaokrągleniu tym bardziej owalny będzie narożnik. Wszystkie poniższe zaokrąglenia generowane są za pomocą CSS.&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;0&quot; style=&quot;width: 100%;&quot;&gt;  &lt;tbody&gt;&lt;tr&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal; text-align: start;&quot;&gt;border-radius: 25px&lt;/span&gt;&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal; text-align: start;&quot;&gt;border-radius: 5px&lt;/span&gt;&lt;/th&gt;      &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_1&quot;&gt;div {&lt;br /&gt;border-radius: 25px;&lt;br /&gt;background: #8AC007;&lt;br /&gt;color: #fff;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px; &lt;br /&gt;}&lt;/div&gt;&lt;/td&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_2&quot;&gt;div {&lt;br /&gt;border-radius: 5px;&lt;br /&gt;background: none;&lt;br /&gt;border: 5px solid #8AC007;&lt;br /&gt;color: #000;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px; &lt;br /&gt;}&lt;/div&gt;&lt;/td&gt;       &lt;/tr&gt;&lt;tr&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;border-radius: 50px&lt;/span&gt;&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;border-radius: 30px&lt;/span&gt;&lt;/th&gt;      &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_3&quot;&gt;&lt;/div&gt;&lt;br /&gt;div {&lt;br /&gt;border-radius: 50px;&lt;br /&gt;background-image:url(&#39;monica.jpg&#39;);&lt;br /&gt;background-repeat: no-repeat;&lt;br /&gt;background-position: left top;&lt;br /&gt;border:1px solid #000;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px;&lt;br /&gt;}&lt;/td&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_4&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;div {&lt;br /&gt;border-radius: 30px;&lt;br /&gt;background-image:url(&#39;angelina.jpg&#39;);&lt;br /&gt;background-repeat: no-repeat;&lt;br /&gt;background-position: left top;&lt;br /&gt;border: 5px dotted #8AC007;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px; &lt;br /&gt;}&lt;/td&gt;       &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A teraz zobaczmy jak określić każdy narożnik z osobna. Można to zrobić za pomocą podania wartości dla wszystkich 4 narożników we własności border-radius, lub wykorzystać własności przeznaczone dla każdego narożnika pojedyńczo, czyli:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;border-top-left-radius&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;- lewy górny róg&lt;/li&gt;&lt;li&gt;border-top-right-radius&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;- prawy górny róg&lt;/li&gt;&lt;li&gt;border-bottom-right-radius -&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;dolny prawy róg&lt;/li&gt;&lt;li&gt;border-bottom-left-radius - dolny lewy róg&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;W przypadku podawania 4 różnych wartości w border-radius, zaczynamy od lewego górnego rogu, następnie każda kolejna wartość odpowiada następnemu rogowi zgodnie z ruchem wskazówek zegara. Przykłady poniżej:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;0&quot; style=&quot;width: 100%;&quot;&gt;  &lt;tbody&gt;&lt;tr&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal; text-align: start;&quot;&gt;border-radius: 25px 0 0 0&lt;/span&gt;&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal; text-align: start;&quot;&gt;border-radius: 0 25px 0 0&lt;/span&gt;&lt;/th&gt;      &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_5&quot;&gt;div &amp;nbsp;{&lt;br /&gt;border-radius: 25px 0 0 0;&lt;br /&gt;background: #8AC007;&lt;br /&gt;color: #fff;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px; &amp;nbsp; &lt;br /&gt;}&lt;/div&gt;&lt;/td&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_6&quot;&gt;div&amp;nbsp;&amp;nbsp;{&lt;br /&gt;border-radius: 0 25px 0 0;&lt;br /&gt;background: #6b9503;&lt;br /&gt;color: #fff;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px; &amp;nbsp; &lt;br /&gt;}&lt;/div&gt;&lt;/td&gt;       &lt;/tr&gt;&lt;tr&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal; text-align: start;&quot;&gt;border-radius: 0 0 0 25px&lt;/span&gt;&lt;/th&gt;    &lt;th scope=&quot;col&quot;&gt;&lt;span style=&quot;font-weight: normal; text-align: start;&quot;&gt;border-radius: 0 0 25px 0&lt;/span&gt;&lt;/th&gt;      &lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_7&quot;&gt;div&amp;nbsp;&amp;nbsp;{&lt;br /&gt;border-radius: 0 0 0 25px;&lt;br /&gt;background: #6b9503;&lt;br /&gt;color: #fff;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px; &amp;nbsp; &lt;br /&gt;}&lt;/div&gt;&lt;/td&gt;    &lt;td&gt;&lt;div class=&quot;csssample_rounded_8&quot;&gt;div&amp;nbsp;&amp;nbsp;{&lt;br /&gt;border-radius: 0 0 25px 0;&lt;br /&gt;background: #8AC007;&lt;br /&gt;color: #fff;&lt;br /&gt;padding: 20px;&lt;br /&gt;width: 300px;&lt;br /&gt;height: 250px; &amp;nbsp; &lt;br /&gt;}&lt;/div&gt;&lt;/td&gt;       &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/124958770973507776/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/css3-zaokraglanie-naroznikow.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/124958770973507776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/124958770973507776'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/css3-zaokraglanie-naroznikow.html' title='[CSS3] Zaokrąglanie narożników'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-8XbbBiXCeXU/VWpRIG5dNtI/AAAAAAAAIfE/xeVsuiInMZk/s72-c/icoCSS.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-9082655585334498120</id><published>2015-05-29T23:54:00.003+02:00</published><updated>2015-05-30T00:21:39.697+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SOAP"/><category scheme="http://www.blogger.com/atom/ns#" term="XML_JSON_SOAP"/><title type='text'>[SOAP] Podstawy protokołu SOAP i tworzenie prostej usługi sieciowej</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-vo_omY1jsMM/VWD00pmV62I/AAAAAAAAH-s/4QfjzyqQ-Wg/s1600/icoSOAP.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-vo_omY1jsMM/VWD00pmV62I/AAAAAAAAH-s/4QfjzyqQ-Wg/s1600/icoSOAP.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;SOAP (Simple Object Access Protocol) to protokół wymiany informacji pomiędzy różnymi hostami i aplikacjami sieciowymi. Jest niezależny od platformy i języka, gdyż wszelka wymiana danych odbywa się za pomocą powszechnie używanego języka XML. SOAP jest standardem komunikacji pomiędzy potencjalnie nie związanymi ze sobą usługami sieciowymi. Serwer udostępniający usługę sieciową (Web Service) może np. działać pod kontrolą ASP.NET, natomiast aplikacja kliencka może być napisana w PHP, bądż w każdym innym dowolnym języku. Cała wymiana danych odbywa się bowiem poprzez niezależny od platformy język XML. Jak działa SOAP? Otóż wyobraźmy sobie serwer, który może udostępniać daną usługę, np. podającą aktualną datę na serwerze. Serwer zatem posiada u siebie jakąś funkcję, która takową datę pobiera i może ją udostępnić na zewnątrz. Mając informację o tym jaki jest adres serwera i jak konkretnie taka funkcja się nazywa, aplikacja kliencka może wysłać do serwera żądanie z prośbą o wykonanie tej funkcji na serwerze i zwrócenia wygenerowanych przez nią danych do klienta. Zarówno żądanie od klienta jak i odpowiedź od serwera wysyłane są za pomocą specjalnie spreparowanego XML-a, nie ma więc znaczenia jaka aplikacja prosi o wykonanie żądania i nie ma też znaczenia jaka aplikacja to żądanie wykona, byleby zwróciła wynik za pomocą języka XML. Serwer SOAP może posiadać oczywiście więcej takich zdefiowanych funkcji i poza podaniem godziny na serwerze może np. posiadać funkcje zwracające na żądanie inne typy danych.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;WSDL&lt;/h2&gt;Funkcje takie jednak muszą się jakoś nazywać - np. getDate(), getTime(), getSomething() itd.&lt;br /&gt;Klient, który nie wie w jaki sposób poprosić serwer o dane informacje takich informacji nie otrzyma, gdyż najzwyczajniej w świecie nie będzie wiedział jakie funkcje taki serwer oferuje, jakie są ich nazwy i jakie dane zwracają. &amp;nbsp;Z pomocą przychodzi tutaj specjalny język stworzony właśnie do opisu oferowanych przez daną usługę sieciową, czyli serwer funkcji wraz z opisem rodzaju zwracanych i przyjmowanych przez nie danych. Język ten nazywa się WSDL (Web Services Description Language) i służy klientowi jako źródło informacji o tym co może zaoferować mu dana usługa sieciowa. Jest to tak naprawdę również XML, tyle że o ściśle określonej strukturze. W interesie serwera (usługi sieciowej) jest przygotowanie takiego dokumentu WSDL, bo po co komu udostępnianie jakiś funkcji, skoro nikt nie może z nich skorzystać, gdyż zwyczajnie o nich nie wie.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Komunikacja po HTTP&lt;/h2&gt;Informacje pomiędzy serwerem i klientem zazwyczaj przesyłane są po protokole HTTP. Ma to o tyle ciekawą zaletę, że protokół ten prawie nigdy nie jest zablokowany przez zapory sieciowe, co za tym idzie - mamy prawie, że pewność, że przesyłane dane nie utkną gdzieś po drodze na jakimś firewallu, który zablokowałby je, gdyby były wysłane po jakimś dziwnym, niestandardowym porcie.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Zastosowania&lt;/h2&gt;Większość szanujących się dużych usługodawców udostępnia swoje usługi za pomocą protokołu SOAP. Robi tak np. Google ze swoim API, robi tak także nasze rodzime (przynajmniej kiedyś) Allegro, które udostępnia swoje API poprzez SOAP, dzięki któremu możemy tworzyć aplikacje pobierające np. informacje o naszych aukcjach, czy kontrahentach. Zastosowanie SOAP-a jest więc powszechne na świecie i warto byłoby posiadać choćby podstawową wiedzę na temat korzystania z tego protokołu. Nic również nie stoi na przeszkodzie, aby utworzyć swoją własną usługę sieciową za pomocą protokołu SOAP co nawet tutaj uczynimy i zobaczymy, że nie jest to wcale takie trudne jak może się wydawać.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Schemat działania&lt;/h2&gt;&lt;br /&gt;Na samym początku klient prosi usługę sieciową o przedstawienie wszystkich funkcji jakie ona udostępnia do wykonania i jakie dane one zwracają. Serwer odbiera prośbę i odsyła klientowi dokument WSDL zawierający spis wszystkich takich funkcji wraz z ich nazwami, przyjmowanymi parametrami oraz rodzajem wartości jakie zwracają w wyniku.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/--Xpm1Sryl4k/VWjeLu8mZcI/AAAAAAAAIco/f8m67MZKOR4/s1600/soap1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/--Xpm1Sryl4k/VWjeLu8mZcI/AAAAAAAAIco/f8m67MZKOR4/s1600/soap1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;W tym momencie klient wie już, że na serwerze dostępna jest funkcja o nazwie np. getTime(), która pobiera aktualny czas na serwerze i zwraca wynik w formacie podanym jako parametr. Zwracana wartość jest zwracana jako ciąg znaków o czym klient zostaje poinformowany za pomocą WSDL.&lt;br /&gt;&lt;br /&gt;Funkcja na serwerze może mniej więcej wyglądać tak:&lt;br /&gt;[code]&lt;br /&gt;function getTime($time_format)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; return date($time_format);&lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Klient wiedząc już teraz, że istnieje taka funkcja, że ma nazwę &#39;getTime&#39; i że zwraca ona dane jako string, oraz że przyjmuje parametr również w spostaci stringu określający format podania czasu, może poprosić serwer o wykonanie tej funkcji podając jej nazwę i parametr, a następnie odebrać od serwera wynik jej działania, oczekując w odpowiedzi ciągu tekstowego zawierającego godzinę na serwerze:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-e3k0mzYNtz4/VWjeEywa1EI/AAAAAAAAIcg/wMsXVN6wVdY/s1600/soap2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-e3k0mzYNtz4/VWjeEywa1EI/AAAAAAAAIcg/wMsXVN6wVdY/s1600/soap2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak wiec widzimy, cała procedura polega na wysłaniu do serwera prośby o wykonanie danej funkcji, wykonaniu tej funkcji przez serwer, pobrania i odesłaniu wyniku przez serwer, a następnie odebraniu tego wyniku przez klienta. Z tak odebranymi danymi klient następnie może już robić co chce.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Przykładowa usługa sieciowa&lt;/h2&gt;Możemy przetestować działanie jednego z dostępnych publicznie webservice&#39;ów w praktyce, aby zobaczyć jak to wygląda.&lt;br /&gt;Wejdżmy np. na stronę: &lt;b&gt;&lt;a href=&quot;http://www.ripedev.com/webservices/localtime.asmx&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.ripedev.com/webservices/localtime.asmx&lt;/a&gt; &amp;nbsp;&lt;/b&gt;&lt;br /&gt;Usługa tutaj posiada jedną funkcję: LocalTimeByZipCode(), która po podaniu jako parametr kodu pocztowego zwraca czas lokalny w jego lokalizacji.&lt;br /&gt;&lt;br /&gt;Jednocześnie możemy przyjrzeć się plikowi WSDL jaki posiada taka usługa:&lt;br /&gt;Do definicji WSDL zawsze dostajemy się poprzez wywołanie:&lt;br /&gt;[code]http://adres_serwera.com/?WSDL[/code]&lt;br /&gt;W tym przypadku wejdżmy na:&lt;br /&gt;&lt;a href=&quot;http://www.ripedev.com/webservices/localtime.asmx?WSDL&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;http://www.ripedev.com/webservices/localtime.asmx?WSDL&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;Zobaczymy jak wygląda taka definicja WSDL &quot;od środka&quot;. Jak widzimy jest do dokument XML, dość obszerny tak swoją drogą jak na tylko jedną funkcję, ale bez obaw - takich dokumentów nie tworzymy ręcznie, są one generowanie przez serwer SOAP. Tutaj mała uwaga - pisząc &#39;dokument WSDL&#39; nie mam na myśli fizycznego pliku, gdyż dokument ten jest niejako generowany w locie, nie istnieje on tak naprawdę fizycznie na serwerze.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tworzymy własny serwer SOAP do testów&lt;/h2&gt;Stworzymy teraz swój własny serwer z prostą usługą sieciową, a następnie się z nią połączymy.&lt;br /&gt;Pozwoli to nam zobaczyć jak to wszystko działa od środka. W PHP istnieje kilka implementacji protokołu SOAP, my wybierzemy implementację o nazwie:&lt;br /&gt;[code]nuSOAP[/code]&lt;br /&gt;Jest to prosta w obsłudze biblioteka, która pozwoli nam na bezproblemową pracę z usługami sieciowymi. Instalacja jest prosta, sprowadza się do pobrania biblioteki i zapisania jej w folderze z naszym projektem.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Bibliotekę pobieramy stąd:&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://sourceforge.net/projects/nusoap/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://sourceforge.net/projects/nusoap/&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Pobierzmy plik, rozpakujmy i zawartosć, czyli folder &#39;lib/&#39; skopiujmy np. do:&lt;br /&gt;[code]/ścieżka/do/naszego/katalogu/z/www/soap[/code]&lt;br /&gt;tak abyśmy mieli dostęp do projektu, który zaraz stworzymy z adresu:&lt;br /&gt;[code]http://localhost/soap[/code]&lt;br /&gt;&lt;br /&gt;Utwórzmy teraz plik &#39;index.php&#39; w naszym folderze &#39;/soap&#39; i zaincludujmy w nim pobraną bibliotekę:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/* index.php */&lt;br /&gt;require_once(&quot;lib/nusoap.php&quot;);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Jesteśmy już gotowi do pracy z biblioteką nuSOAP.&lt;br /&gt;Jako przykładową funkcję w naszej usłudze stworzymy sobie taką jaką omawialiśmy na przykładzie pobrania czasu z serwera. Nazwiemy ją tak samo - getTime(), a samą usługę sieciową nazwiemy &#39;mySOAP&#39;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Utworzenie usługi&lt;/h4&gt;Pracę rozpoczynamy od utworzenia obiektu klasy &#39;soap_server&#39;:&lt;br /&gt;[code]$server = new soap_server();[/code]&lt;br /&gt;Następnie wstępnie konfigurujemy naszą definicję WSDL, robimy to za pomocą:&lt;br /&gt;[code]$server-&amp;gt;configureWSDL(nazwa_naszej_usługi, $namespace)[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;nazwa_naszej_uslugi - nazwa pod jaką będzie widoczna nasza usługa&lt;/li&gt;&lt;li&gt;$namespace - przestrzeń nazw dla dokumentu XML, podamy tutaj na razie 127.0.0.1&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Użyjemy zatem kodu:&lt;br /&gt;[code]&lt;br /&gt;$namespace = &#39;127.0.0.1&#39;;&lt;br /&gt;$server-&amp;gt;configureWSDL(&#39;mySOAP&#39;, $namespace);&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Następnie określamy używaną przestrzeń nazw za pomocą:&lt;br /&gt;[code]$server-&amp;gt;wsdl-&amp;gt;schemaTargetNamespace = $namespace;[/code]&lt;br /&gt;&lt;br /&gt;Wstępna konfiguracja jest już za nami, mamy więc taki oto kod:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/* index.php */&lt;br /&gt;require_once(&quot;lib/nusoap.php&quot;);&lt;br /&gt;// załączamy bibliotekę nuSOAP&lt;br /&gt;&lt;br /&gt;$server = new soap_server(); // tworzymy nowy obiekt serwera SOAP&lt;br /&gt;$namespace = &#39;127.0.0.1&#39;; // definiujemy przestrzeń nazw dla XML&lt;br /&gt;&lt;br /&gt;$server-&amp;gt;configureWSDL(&#39;mySOAP&#39;, $namespace); &amp;nbsp;// konfigurujemy nową usługę&lt;br /&gt;$server-&amp;gt;wsdl-&amp;gt;schemaTargetNamespace = $namespace; // przypisujemy namespace do struktury tworzonego schematu WSDL&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Stworzymy sobie teraz opisy metod/funkcji jakie udostępniać będzie nasza usługa.&lt;br /&gt;Na początek stworzymy jedną metodę o nazwie:&lt;br /&gt;[code]getTime()[/code]&lt;br /&gt;przyjmującą jeden parametr określający format pobieranego czasu&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Rejestracja metod/funkcji&lt;/h4&gt;Tutaj musimy się na chwile zatrzymać.&lt;br /&gt;Każdą udostępnianą metodę/funkcję w nuSOAP musimy najpierw zarejestrować. Rejestracja taka polega na podaniu informacji o danej metodzie takich jak jej nazwa, przyjmowane i zwracane parametry, czy opis. Informacje te są wykorzystywane podczas generowania dokumentu WSDL, a także przez sam serwer podczas wywowyłania ich zdalnie. Metody rejestrujemy za pomocą:&lt;br /&gt;[code]$server-&amp;gt;register($method, $input, $output, $namespace, $soap_action, $style, $use, $documentation, $encoding_style);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;$method - nazwa naszej metody, lub klasa.nazwa_metody&lt;/li&gt;&lt;li&gt;$input - tablica z argumentami jakie przyjmuje metoda, &lt;i&gt;array(&#39;NAZWA_ARGUMENTU&quot; =&amp;gt; &#39;TYP_ARGUMENTU&#39;)&lt;/i&gt;&lt;/li&gt;&lt;li&gt;$output - tablica z wartościami jakie zwraca metoda, &lt;i&gt;array(&#39;return&quot; =&amp;gt; &#39;TYP_ZWRACANEJ_WARTOŚCI&#39;)&lt;/i&gt;&lt;/li&gt;&lt;li&gt;$namespace - przestrzeń nazw dla XML&lt;/li&gt;&lt;li&gt;$soap_action - akcja dla metody lub false&amp;nbsp;&lt;/li&gt;&lt;li&gt;$style - rpc|document, rodzaj generowania odpowiedzi &amp;nbsp;&lt;/li&gt;&lt;li&gt;$use - encode|literal - tryb kodowania znaków &amp;nbsp;&lt;/li&gt;&lt;li&gt;$documentation - opis naszej metody do pliku WSDL &amp;nbsp;[opcjonalnie]&lt;/li&gt;&lt;li&gt;$encoding_style - zewnętrzny styl dla encodowania [opcjonalnie]&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Zarejestrujmy teraz naszą metodę o nazwie &#39;getTime()&#39;.&lt;br /&gt;Jak pamiętamy przyjmuje ona jeden parametr typu string, zwraca wartość również typu string - będziemy musieli określić to w metodzie rejestrującej:&lt;br /&gt;[code]&lt;br /&gt;$server-&amp;gt;register(&quot;getTime&quot; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,array(&#39;time_format&#39;=&amp;gt;&#39;xsd:string&#39;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,array(&#39;return&#39;=&amp;gt;&#39;xsd:string&#39;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,$namespace&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,false&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;rpc&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;encoded&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;To jest nasza testowa metoda zwracająca czas na serwerze&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; );&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Metodę mamy już zarejestrowaną, pora na jej definicję.&lt;br /&gt;Zrobimy to tak jak zwykle, definiując zwykłą funkcję, z małą różnicą na końcu:&lt;br /&gt;[code]&lt;br /&gt;function getTime($time_format)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $result = date($time_format); &lt;br /&gt;&amp;nbsp; return new soapval(&#39;return&#39;, &#39;xsd:string&#39;, $result);&lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Ta mała różnica to zwracana wartość.&lt;br /&gt;Jak widzimy w funkcji zarejestrowanej dla SOAP nie możemy zwrócić danych tak jak zazwyczaj, czyli poprzez:&lt;br /&gt;[code]return $result;[/code]&lt;br /&gt;&lt;br /&gt;Musimy tutaj za każdym razem wykorzystać obiekt klasy &#39;soapval&#39;, wg następującej składni:&lt;br /&gt;[code]return new soapval(nazwa_zwracanej_wartości, rodzaj_zwracanej_wartości, $wartość);[/code]&lt;br /&gt;&lt;br /&gt;Zauważmy, że jako nazwa zwracanej wartości podajemy tutaj &#39;return&#39;, co też określiliśmy podcza rejestracji metody w:&lt;br /&gt;[code]array(&#39;return&#39;=&amp;gt;&#39;xsd:string&#39;)[/code]&lt;br /&gt;&lt;br /&gt;Wyjaśnienia wymaga także zapis:&lt;br /&gt;[code]xsd:string[/code]&lt;br /&gt;W schemacie XSD w taki sposób właśnie podawać musimy typ zwracanej wartości.&lt;br /&gt;Podstawowe typy danych to:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;xsd:string&lt;/li&gt;&lt;li&gt;xsd:int&lt;/li&gt;&lt;li&gt;xsd:float&lt;/li&gt;&lt;li&gt;xsd:double&lt;/li&gt;&lt;li&gt;xsd:boolean&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Pełną listę znajdziesz tutaj:&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://www.w3schools.com/schema/schema_dtypes_string.asp&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.w3schools.com/schema/schema_dtypes_string.asp&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Nasz kod w tym momencie wygląda więc tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/* index.php */&lt;br /&gt;require_once(&quot;lib/nusoap.php&quot;);&lt;br /&gt;// załączamy bibliotekę nuSOAP&lt;br /&gt;&lt;br /&gt;$server = new soap_server(); // tworzymy nowy obiekt serwera SOAP&lt;br /&gt;$namespace = &#39;127.0.0.1&#39;; // definiujemy przestrzeń nazw dla XML&lt;br /&gt;&lt;br /&gt;$server-&amp;gt;configureWSDL(&#39;mySOAP&#39;, $namespace); &amp;nbsp;// konfigurujemy nową usługę&lt;br /&gt;$server-&amp;gt;wsdl-&amp;gt;schemaTargetNamespace = $namespace; // przypisujemy namespace do struktury tworzonego schematu WSDL&lt;br /&gt;&lt;br /&gt;// rejestrujemy metodę&lt;br /&gt;$server-&amp;gt;register(&quot;getTime&quot; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,array(&#39;time_format&#39;=&amp;gt;&#39;xsd:string&#39;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,array(&#39;return&#39;=&amp;gt;&#39;xsd:string&#39;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,$namespace&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,false&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;rpc&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;encoded&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;To jest nasza testowa metoda zwracająca czas na serwerze&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; );&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;// definiujemy metodę &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;function getTime($time_format)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $result = date($time_format); &lt;br /&gt;&amp;nbsp; return new soapval(&#39;return&#39;, &#39;xsd:string&#39;, $result);&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Teraz musimy jeszcze w jakiś sposób odbierać żądania.&lt;br /&gt;Posłuży do tego poniższy kod:&lt;br /&gt;[code]&lt;br /&gt;$postdata = file_get_contents(&quot;php://input&quot;);&lt;br /&gt;$postdata = isset($postdata) ? $postdata : &#39;&#39;;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Na sam koniec startujemy usługę, podając jako parametr ew. odebrane żądanie:&lt;br /&gt;[code]$server-&amp;gt;service($postdata);[/code]&lt;br /&gt;&lt;br /&gt;Nasz kod finalnie wygląda tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/* index.php */&lt;br /&gt;require_once(&quot;lib/nusoap.php&quot;);&lt;br /&gt;// załączamy bibliotekę nuSOAP&lt;br /&gt;&lt;br /&gt;$server = new soap_server(); // tworzymy nowy obiekt serwera SOAP&lt;br /&gt;$namespace = &#39;127.0.0.1&#39;; // definiujemy przestrzeń nazw dla XML&lt;br /&gt;&lt;br /&gt;$server-&amp;gt;configureWSDL(&#39;mySOAP&#39;, $namespace); &amp;nbsp;// konfigurujemy nową usługę&lt;br /&gt;$server-&amp;gt;wsdl-&amp;gt;schemaTargetNamespace = $namespace; // przypisujemy namespace do struktury tworzonego schematu WSDL&lt;br /&gt;&lt;br /&gt;// rejestrujemy metodę&lt;br /&gt;$server-&amp;gt;register(&quot;getTime&quot; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,array(&#39;time_format&#39;=&amp;gt;&#39;xsd:string&#39;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,array(&#39;return&#39;=&amp;gt;&#39;xsd:string&#39;)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,$namespace&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,false&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;rpc&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;encoded&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;,&#39;To jest nasza testowa metoda zwracająca czas na serwerze&#39;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; );&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;// definiujemy metodę &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;function getTime($time_format)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $result = date($time_format); &lt;br /&gt;&amp;nbsp; return new soapval(&#39;return&#39;, &#39;xsd:string&#39;, $result);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// odbieramy żądanie&lt;br /&gt;$postdata = file_get_contents(&quot;php://input&quot;);&lt;br /&gt;$postdata = isset($postdata) ? $postdata : &#39;&#39;;&lt;br /&gt;&lt;br /&gt;// startujemy usługę&lt;br /&gt;$server-&amp;gt;service($postdata);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wejdżmy teraz w adres naszej usługi:&lt;br /&gt;[code]http://localhost/soap[/code]&lt;br /&gt;Jeśli wszystko wykonaliśmy poprawnie, powinien nam się ukazać opis naszej usługi:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-bKwcAr98t4w/VWjfXgijJ-I/AAAAAAAAIc0/PBwHXhA5_Z4/s1600/soapMy.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;328&quot; src=&quot;http://3.bp.blogspot.com/-bKwcAr98t4w/VWjfXgijJ-I/AAAAAAAAIc0/PBwHXhA5_Z4/s640/soapMy.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Automatycznie generowany dokument WSDL zobaczymy wpisując adres:&lt;br /&gt;[code]http://localhost/soap?wsdl[/code]&lt;br /&gt;(nuSOAP wymaga podania WSDL małymi literami)&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-thT9Eql4AU0/VWjfc76Ic_I/AAAAAAAAIc8/TWD-Wb_e47M/s1600/soapMyWSDL.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;614&quot; src=&quot;http://3.bp.blogspot.com/-thT9Eql4AU0/VWjfc76Ic_I/AAAAAAAAIc8/TWD-Wb_e47M/s640/soapMyWSDL.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Voila!&lt;br /&gt;Stworzyliśmy swoją własną, prostą usługę sieciową.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Aplikacja kliencka&lt;/h2&gt;Teraz czas na przetestowanie naszej usługi. Zobaczymy teraz jak połaczyć się z usługą po stronie klienta.&lt;br /&gt;Stwórzmy plik &#39;client.php&#39; o następującej treści:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;/* client.php */&lt;br /&gt;require_once(&#39;lib/nusoap.php&#39;);&lt;br /&gt;// dołączamy bibliotekę&lt;br /&gt;&lt;br /&gt;$wsdl = &#39;http://localhost/soap/?wsdl&#39;; // URL do wsdl naszego serwera&lt;br /&gt;$client = new nusoap_client($wsdl, &#39;wsdl&#39;); // tworzymy obiekt klienta&lt;br /&gt;$params = array(&#39;time_format&#39; =&amp;gt; &#39;H:i:s&#39;); // definujemy parametry wywoływanej funkcji&lt;br /&gt;&lt;br /&gt;$response = $client-&amp;gt;call(&#39;getTime&#39;, $params);&lt;br /&gt;// wywołujemy zdalną funkcję&lt;br /&gt;&lt;br /&gt;echo(&#39;SERVER TIME: &#39;.&amp;nbsp;$response);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;W pierwszej kolejności załaczamy oczywiście bibliotekę nuSOAP.&lt;br /&gt;Następnie definiujemy URL do naszej usługi (z koncówką ?wsdl) i podajemy go do konstruktora obiektu klienta:&lt;br /&gt;[code]$client = new nusoap_client(url_do_definicji_wsdl, wsdl);[/code]&lt;br /&gt;gdzie w drugim parametrze podajemy &#39;wsdl&#39;, jeśli łączymy się z definicją WSDL.&lt;br /&gt;W kolejnym kroku definiujemy tablicę z argumentami z jakimi wywołamy zdalną funkcję oraz wywołujemy samą funkcję za pomocą:&lt;br /&gt;[code]$client-&amp;gt;call(nazwa_zdalnej_funkcji, parametry);[/code]&lt;br /&gt;&lt;br /&gt;Jeśli wszystko poszło po naszej myśli, to powinniśmy połączyć się z naszą usługą sieciową, uruchomić na niej zdalną funkcję i odebrać z serwera wynik jaki zwróciła:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-aci8zPjFVec/VWjfiC6v7CI/AAAAAAAAIdE/RVZzDtYMXyg/s1600/soapMyCLient.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;196&quot; src=&quot;http://2.bp.blogspot.com/-aci8zPjFVec/VWjfiC6v7CI/AAAAAAAAIdE/RVZzDtYMXyg/s640/soapMyCLient.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać, nie jest to bardzo skomplikowane.&lt;br /&gt;W kilku krokach stworzyliśmy swój własny serwer SOAP oraz nauczyliśmy się wywoływania zdalnych metod i odbierania od nich danych. Oczywiście są to absolutne podstawy i do bardziej skomplikowanej pracy nie wystarczą, ale jest to już pewna podbudowa, gdy umiemy korzystać z czegoś choćby w wersji podstawowej i wiemy &quot;z czym to się je&quot;. W następnych artykułach opiszę bardziej zaawansowane metody pracy z SOAP wraz z przykładami, a póki co - wiedza zdobyta w tym artykule niech stanowi dla nas podstawę i zachętę do dalszej nauki protokołu SOAP.&lt;br /&gt;&lt;br /&gt;Dla ciekawskich: dokumentacja webAPI oferowanego przez Allegro.pl, oczywiście za pomocą SOAP:&amp;nbsp;&lt;a href=&quot;http://allegro.pl/webapi/documentation.php&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://allegro.pl/webapi/documentation.php&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/9082655585334498120/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/soap-podstawy-protokolu-soap-i-tworzenie-prostej-uslugi-sieciowej.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/9082655585334498120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/9082655585334498120'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/soap-podstawy-protokolu-soap-i-tworzenie-prostej-uslugi-sieciowej.html' title='[SOAP] Podstawy protokołu SOAP i tworzenie prostej usługi sieciowej'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-vo_omY1jsMM/VWD00pmV62I/AAAAAAAAH-s/4QfjzyqQ-Wg/s72-c/icoSOAP.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-1609439994610160279</id><published>2015-05-29T18:35:00.000+02:00</published><updated>2015-05-29T19:48:11.561+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GIT_SVN"/><category scheme="http://www.blogger.com/atom/ns#" term="SVN"/><title type='text'>[SVN] Instalacja klienta i serwera oraz podstawy pracy z SVN</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-KncajoQ8b3U/VWD026HfTuI/AAAAAAAAH_w/1pzGeGOoJnw/s1600/icoSVN.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-KncajoQ8b3U/VWD026HfTuI/AAAAAAAAH_w/1pzGeGOoJnw/s1600/icoSVN.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;SVN to najpopularniejszy i najczęściej używany na świecie system kontroli wersji. Z wersjonowania za pomocą SVN korzystają najwięksi gracze na rynku, tacy jak Google, Wordpress i wiele innych znanych marek. Taka rekomendacja już na starcie powinna wystarczyć do uznania Subversion za system wysoce niezawodny. Projekt wersjonowany za pomocą SVN dzieli się na dwie niezależne od siebie kwestie - na repozytorium główne, przechowywane na serwerze systemu kontroli wersji oraz na jego kopie robocze, dostępne zdalnie, na których lokalnie pracują związani z repozytorium programiści. O ile pobranie gotowego repozytorium i praca na nim nie wymaga zbyt wielu zabiegów, to już postawienie serwera SVN może być nieco kłopotliwe dla osób, które robią to po raz pierwszy. Dlatego też w artykule tym omówię krok po kroku w jaki sposób uruchomić na swoim komputerze zarówno klienta jak i serwer systemu kontroli wersji Subversion. Artykuł dotyczyć będzie instalacji na systemach z rodziny Windows, linuxowcom nie trzeba tłumaczyć jak SVN-a zainstalować ;)&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Wstęp&lt;/h2&gt;Na początek zobaczmy jak wygląda dostęp do gotowego repozytorium. Do repozytorium dostaniemy się z poziomu zwykłego WWW, wejdźmy sobie na repozytorium Wordpressa:&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://svn.automattic.com/wordpress/trunk/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://svn.automattic.com/wordpress/trunk/&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-qxWRALyRJ5k/VWiWj8j16vI/AAAAAAAAIa8/o26S1FMEor8/s1600/wp.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://1.bp.blogspot.com/-qxWRALyRJ5k/VWiWj8j16vI/AAAAAAAAIa8/o26S1FMEor8/s640/wp.png&quot; width=&quot;520&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Jak widzimy, mamy od razu wylistowaną listę plików zawartych w repozytorium oraz informację, której rewizji dotyczą obecne wersje plików. W chwili pisania tego tekstu (na dzień 29.05.2015) jest to rewizja o numerze 32622. Przy każdej kolejnej zmianie w kodzie (tzw. commicie) numer rewizji jest zwiększany o jeden.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Klient&lt;/h2&gt;Po stronie klienta pracować będziemy na kopii roboczej repozytorium, nie na jego właściwej wersji. Pracować z SVN możemy w konsoli, jak i za pomocą windowsowego graficznego GUI o nazwie TortoiseSVN. W opisie tym nauczymy się jednego i drugiego. Na samym początku pobrać musimy najnowszą wersję klienta SVN ze strony:&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://sourceforge.net/projects/win32svn/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://sourceforge.net/projects/win32svn/&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;Zróbmy więc to i zainstalujmy SVN w swoim systemie.&lt;br /&gt;&lt;br /&gt;Kolejnym krokiem będzie pobranie graficznego klienta o nazwie TortoiseSVN, którego pobierzemy sobie stąd:&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://tortoisesvn.net/downloads.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://tortoisesvn.net/downloads.html&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Po instalacji, sprawdżmy, czy wszystko działa poprawnie.&lt;br /&gt;SVN powinien nam dodać ścieżkę do zmiennej PATH w systemie, np:&lt;br /&gt;[code]C:\Program Files (x86)\Subversion\bin[/code]&lt;br /&gt;Jeśli tak się nie stało - musimy ją dodać ręcznie:&lt;br /&gt;[code]Komputer &amp;gt;&amp;gt; Zaawansowane &amp;gt;&amp;gt; Zmienne środowiskowe &amp;gt;&amp;gt; PATH[/code]&lt;br /&gt;Wejdżmy teraz do konsoli i wpiszmy:&lt;br /&gt;[code]$ svn --version[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-Hp7sHBtk3OU/VWiQCsnjWGI/AAAAAAAAIac/2EI2dii4PIg/s1600/v.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;436&quot; src=&quot;http://4.bp.blogspot.com/-Hp7sHBtk3OU/VWiQCsnjWGI/AAAAAAAAIac/2EI2dii4PIg/s640/v.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widzimy wyświetliła nam się obecna zainstalowana wersja.&lt;br /&gt;&lt;br /&gt;Sprawdźmy teraz klienta Tortoise - powinien on dodać kilka elementów do powłoki systemu.&lt;br /&gt;Utwórzmy jakiś folder, np. C:/svntest i kliknijmy na nim prawym przyciskiem myszy, powinniśmy zobaczyć menu kontekstowe klienta Tortoise:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-W1ZlVGAtwsA/VWiMHQa2YQI/AAAAAAAAIX8/ITI5B8sTmqY/s1600/w1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;210&quot; src=&quot;http://2.bp.blogspot.com/-W1ZlVGAtwsA/VWiMHQa2YQI/AAAAAAAAIX8/ITI5B8sTmqY/s640/w1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Pobierzmy sobie dla testów przedstawione wcześniej repozytorium Wordpressa:&lt;br /&gt;Mając utworzony folder:&lt;br /&gt;[code]C:/svntest[/code]&lt;br /&gt;i będąc w konsoli, wejdźmy do niego i wpiszmy to co poniżej:&lt;br /&gt;[code]&lt;br /&gt;$ cd C:/svntest&lt;br /&gt;$ svn checkout http://svn.automattic.com/wordpress/trunk wordpress&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Pobierze nam to kopię lokalną repozytorium Wordpressa do katalogu:&lt;br /&gt;[code]C:/svntest/wordpress/[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-HPRivj9WBIE/VWiMNU6LjSI/AAAAAAAAIYE/2xQfE6qqYHY/s1600/c2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;286&quot; src=&quot;http://4.bp.blogspot.com/-HPRivj9WBIE/VWiMNU6LjSI/AAAAAAAAIYE/2xQfE6qqYHY/s640/c2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Zauważmy, iż w każdym repozytorium znajdzie się nam ukryty folder o nazwie &quot;.svn&quot; - pod żadnym pozorem nie modyfikujmy ręcznie plików w nim zawartych.&lt;br /&gt;&lt;br /&gt;Teraz to samo zróbmy za pomocą klienta graficznego.&lt;br /&gt;Wiemy już, że do pobrania repozytorium służy komenda &quot;checkout&quot;.&lt;br /&gt;Utwórzmy teraz folder:&lt;br /&gt;[code]C:/svntest/wordpress2[/code]&lt;br /&gt;i klijnijmy na nim prawym przyciskiem myszy wybierając opcję &quot;SVN Checkout...&quot;:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-SuEQ6Egwgz4/VWiMTS-c17I/AAAAAAAAIYM/ORdp_OfUW-M/s1600/w2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;224&quot; src=&quot;http://3.bp.blogspot.com/-SuEQ6Egwgz4/VWiMTS-c17I/AAAAAAAAIYM/ORdp_OfUW-M/s640/w2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Pojawi się okno, w którym wpiszmy adres repozytorium:&lt;br /&gt;[code]http://svn.automattic.com/wordpress/trunk[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-w2uTMnckqgw/VWiMXW15Z-I/AAAAAAAAIYU/8gdOruQgQo0/s1600/w3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;560&quot; src=&quot;http://3.bp.blogspot.com/-w2uTMnckqgw/VWiMXW15Z-I/AAAAAAAAIYU/8gdOruQgQo0/s640/w3.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać - pobrania kopii repozytorium możemy dokonać zarówno z poziomu poleceń w konsoli jak i z poziomu łatwego w użyciu klienta graficznego. To wszystko - od tej chwili możemy dowolnie pracować na pobranej kopii roboczej repozytorium.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Testowy plik&lt;/h4&gt;Dodajmy teraz jakiś plik do pobranej kopii repozytorium, niech to będzie np.:&lt;br /&gt;[code]test.txt[/code]&lt;br /&gt;Plik taki dodaliśmy jednak jedynie do naszego folderu, nie jest on jeszcze jednak uwzględniony w repozytorium, co za tym idzie nie jest śledzony przez SVN. Aby dołączyć nowy plik do repozytorium używamy polecenia &quot;add&quot;:&lt;br /&gt;&lt;br /&gt;[code]$ svn add test.txt[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-ZVEqpgjntEQ/VWiMsRDAIYI/AAAAAAAAIYc/d93A8ctc0Jc/s1600/c2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;286&quot; src=&quot;http://2.bp.blogspot.com/-ZVEqpgjntEQ/VWiMsRDAIYI/AAAAAAAAIYc/d93A8ctc0Jc/s640/c2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Aby dodać wszystkie nowe pliki używamy gwiazdki:&lt;br /&gt;[code]$ svn add *[/code]&lt;br /&gt;&lt;br /&gt;Analogicznie dla podfolderu:&lt;br /&gt;[code]$ svn add podfolder/*[/code]&lt;br /&gt;&lt;br /&gt;Od tej chwili plik ten jest już zawarty w &lt;b&gt;lokalnej, roboczej kopii&lt;/b&gt; repozytorium i śledzony przez SVN.&lt;br /&gt;To samo możemy zrobić z poziomu klienta Tortoise:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/--_XMYQY5HeI/VWiMzTN_znI/AAAAAAAAIYk/8vGheada98U/s1600/w4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;444&quot; src=&quot;http://1.bp.blogspot.com/--_XMYQY5HeI/VWiMzTN_znI/AAAAAAAAIYk/8vGheada98U/s640/w4.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jesteśmy obecnie wciąż w rewizji jaką pobraliśmy z serwera Wordpressa. Aby dodać nasz nowy plik do właściwego repozytorium, a więc zatwierdzić zmiany jakich dokonaliśmy - musimy te zmiany &quot;zacommitować&quot;. Tym samym &lt;b&gt;numer rewizji zwiększy się o jeden&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Służy do tego polecenie:&lt;br /&gt;[code]$ svn commit -m &quot;Komentarz do rewizji&quot;[/code]&lt;br /&gt;&lt;br /&gt;lub to samo w kliencie graficznym:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-br2khtiEmtI/VWiM4rDXiSI/AAAAAAAAIYs/oZK0qnMQHsc/s1600/w5.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;356&quot; src=&quot;http://2.bp.blogspot.com/-br2khtiEmtI/VWiM4rDXiSI/AAAAAAAAIYs/oZK0qnMQHsc/s640/w5.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Niestety żadnych zmian w tym momencie nie zatwierdzimy, gdyż nie mamy odpowiednich uprawnień do repozytorium Wordpressa. Różnica pomiędzy SVN i GIT-em jest taka, że w Gicie wszelkie zmiany commitujemy do kopii roboczej znajdujacej się lokalnie na naszym komputerze i dopiero potem wysyłamy na serwer, w SVN natomiast commitujemy je bezpośrednio do repozytorium źródłowego. Aby więc przetestować to wszystko w praktyce, potrzebujemy serwera, do którego będziemy mieć pełny dostęp, co też uczynimy poniżej.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Serwer&lt;/h2&gt;Postawmy teraz własny serwer, aby w pełni przetestować pracę z SVN, taką jak zatwierdzanie zmian, czy łączenie kopii roboczej z głównym repozytorium (z Wordpressem tego nie zrobimy, nie posiadamy uprawnień - możemy jedynie pobrać kopię roboczą repozytorium). O ile sprawa z klientem była prosta, o tyle postawienie własnego serwera SVN nie będzie już takie proste.&lt;br /&gt;Co należy wiedzieć, to to, że serwer SVN postawić możemy na dwa sposoby - za pomocą oddzielnej aplikacji (dostępnej tylko na systemy unixowe), lub za pomocą odpowiedniego modułu do serwera Apache. Wykorzystamy tą drugą opcję, zatem koniecznym jest, abyśmy posiadali działającego lokalnie Apacha - bez tego nie zrobimy nic. Instalacji Apacha nie będę tutaj opisywał i zakładam, że takowy serwer już u nas działa.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;1. Pobranie modułów SVN&lt;/h4&gt;Co musimy teraz zrobić? Musimy pobrać odpowiednie do naszej wersji serwera dodatkowe moduły.&lt;br /&gt;Będą to dwa pliki:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;mod_authz_svn.so&lt;/li&gt;&lt;li&gt;mod_dav_svn.so&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Pliki te są dostępne w folderze z zainstalowanym Subversion/bin.&lt;br /&gt;Niestety skopiowanie ich stąd w niektorych przypadkach spowodować może, że nasz serwer nie będzie w stanie wystartować. Powód? Istnieje kilka wersji Apacha, z czego najgłówniejszym podziałem jest podział na wersje 2.2x i 2.4x. Dodatkowo możemy posiadać wersję 32, albo 64 bitową. W przypadku niezgodności wersji możemy mieć problem z uruchomieniem serwera z powyższymi modułami, pobrać musimy zatem wersję odpowiednią dla NASZEJ wersji serwera.&lt;br /&gt;Odpowiednią wersję znajdziemy na stronie:&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;https://www.apachehaus.com/cgi-bin/download.plx&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;https://www.apachehaus.com/cgi-bin/download.plx&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;w odpowiednich sekcjach:&lt;br /&gt;[code]Modules for Apache 2.2.x i Modules for Apache 2.4.x[/code]&lt;br /&gt;Paczka ma nazwę:&lt;br /&gt;[code]Mod Subversion x.x.x. for Apache 2.x.x[/code]&lt;br /&gt;&lt;br /&gt;Ja osobiście posiadam 64-bitową wersję Apache&#39;a z numerkiem 2.4.9, pobieram więc odpowiednią dla mnie wersję: &lt;br /&gt;&lt;b&gt;mod_svn-1.8.11-ap24-vc9-x64.zip&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;2. Instalacja modułów SVN&lt;/h4&gt;Po pobraniu odpowiedniego archiwum, rozpakowujemy je:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-IUFIGDaWIMs/VWiM_itvDJI/AAAAAAAAIY0/r3pAeCyPFhU/s1600/w6.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;202&quot; src=&quot;http://3.bp.blogspot.com/-IUFIGDaWIMs/VWiM_itvDJI/AAAAAAAAIY0/r3pAeCyPFhU/s640/w6.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Pliki z folderu &quot;modules/&quot;:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;mod_authz_svn.so&lt;/li&gt;&lt;li&gt;mod_dav_svn.so&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;kopiujemy do:&lt;br /&gt;[code]/ścieżka/do/apache/modules/[/code]&lt;br /&gt;&lt;br /&gt;natomiast pliki z folderu &quot;bin/&quot; do:&lt;br /&gt;[code]/ścieżka/do/apache/bin/[/code]&lt;br /&gt;&lt;br /&gt;No dobrze, pliki już mamy, teraz czeka nas edycja pliku konfiguracyjnego Apache&#39;a, ale najpierw przygotujmy sobie katalog, w którym nasz serwer będzie trzymał repozytoria, dla testów utwórzmy folder:&lt;br /&gt;[code]C:/svnserver[/code]&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;3. Konfiguracja Apache&#39;a&lt;/h4&gt;Wróćmy teraz do katalogu z Apachem i otwórzmy (w trybie administracyjnym) do edycji plik:&lt;br /&gt;[code]/ścieżka/do/apache/conf/httpd.conf[/code]&lt;br /&gt;&lt;br /&gt;Mając już otwarty plik z konfiguracją po pierwsze musimy włączyć dodane dopiero co moduły.&lt;br /&gt;Szukamy sekcji z modułami, która wygląda mniej więcej tak:&lt;br /&gt;[code]&lt;br /&gt;# Example:&lt;br /&gt;# LoadModule foo_module modules/mod_foo.so&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;LoadModule access_compat_module modules/mod_access_compat.so&lt;br /&gt;LoadModule actions_module modules/mod_actions.so&lt;br /&gt;LoadModule alias_module modules/mod_alias.so&lt;br /&gt;LoadModule allowmethods_module modules/mod_allowmethods.so&lt;br /&gt;LoadModule asis_module modules/mod_asis.so&lt;br /&gt;LoadModule auth_basic_module modules/mod_auth_basic.so&lt;br /&gt;#LoadModule auth_digest_module modules/mod_auth_digest.so&lt;br /&gt;#LoadModule authn_anon_module modules/mod_authn_anon.so&lt;br /&gt;LoadModule authn_core_module modules/mod_authn_core.so&lt;br /&gt;#LoadModule authn_dbd_module modules/mod_authn_dbd.so&lt;br /&gt;#LoadModule authn_dbm_module modules/mod_authn_dbm.so&lt;br /&gt;[...]&lt;br /&gt;[/code]&lt;br /&gt;i szukamy modułu &#39;mod_dav.so&#39;:&lt;br /&gt;[code]#LoadModule dav_module modules/mod_dav.so[/code]&lt;br /&gt;&lt;br /&gt;Będzie on najprawdopodobniej zakomentowany znakiem #, usuwamy ten znak.&lt;br /&gt;Następnie dodajemy wpisy z naszymi skopiowanymi dopiero co modułami:&lt;br /&gt;[code]&lt;br /&gt;LoadModule dav_svn_module modules/mod_dav_svn.so&lt;br /&gt;LoadModule authz_svn_module modules/mod_authz_svn.so&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Zapisujemy plik &#39;httpd.conf&#39; i restarujemy Apache&#39;a.&lt;br /&gt;Jeśli moduły załadowały się poprawnie i serwer wystartował, to wracamy do dalszej konfiguracji.&lt;br /&gt;Pod koniec pliku &#39;httpd.conf&#39; dodajmy następujące:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Location /svnserver&amp;gt;&lt;br /&gt;DAV svn&lt;br /&gt;SVNPath &quot;C:/svnserver/myTestRepo&quot;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Określa to ścieżkę do naszego repozytorium (które za chwilę utworzymy).&lt;br /&gt;Ponownie zapisujemy plik i restartujemy serwer.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;4. Tworzymy repozytorium&lt;/h4&gt;Teraz czas na utworzenie testowego repozytorium:&lt;br /&gt;W terminalu zrobimy to tak:&lt;br /&gt;[code]&lt;br /&gt;$ cd C:/svnserver&lt;br /&gt;$ svnadmin create myTestRepo&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-7ojWyon0pCQ/VWiNJhD_ZzI/AAAAAAAAIY8/929hMq1VDaw/s1600/c3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;286&quot; src=&quot;http://3.bp.blogspot.com/-7ojWyon0pCQ/VWiNJhD_ZzI/AAAAAAAAIY8/929hMq1VDaw/s640/c3.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Za pomocą klienta Tortoise zrobimy to następująco:&lt;br /&gt;Wchodzimy w folder C:/svnserver, tworzymy w nim folder &#39;myTestRepo&#39;, klikamy na nim prawym przyciskiem myszy i wybieramy opcję:&lt;br /&gt;[code]TortoiseSVN -&amp;gt; Create repository here[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-xQW07Ojjkj8/VWiNh3GuE_I/AAAAAAAAIZE/1Cu4ZJA8VF0/s1600/w7.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;366&quot; src=&quot;http://4.bp.blogspot.com/-xQW07Ojjkj8/VWiNh3GuE_I/AAAAAAAAIZE/1Cu4ZJA8VF0/s640/w7.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Zostanie utworzone repozytorium, wybieramy opcję &#39;Create folder structure&#39; i [OK]:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-7VGORfkZ4RA/VWiNmKr_DMI/AAAAAAAAIZM/ReiroVvldog/s1600/w8.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;524&quot; src=&quot;http://1.bp.blogspot.com/-7VGORfkZ4RA/VWiNmKr_DMI/AAAAAAAAIZM/ReiroVvldog/s640/w8.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Nasze repozytorium zostało utworzone.&lt;br /&gt;&lt;br /&gt;Wchodzimy teraz z poziomu przeglądarki na adres:&lt;br /&gt;[code]http://localhost/svnserver[/code]&lt;br /&gt;Jeśli wszystko poszło zgodnie z planem, naszym oczom powinno się ukazać nasze świeżo &lt;strike&gt;upieczone&lt;/strike&gt; &amp;nbsp;utworzone repozytorium:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-EMj1RjXQPH8/VWiNvYTMIbI/AAAAAAAAIZU/nSwv6nHbRvc/s1600/s1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;352&quot; src=&quot;http://2.bp.blogspot.com/-EMj1RjXQPH8/VWiNvYTMIbI/AAAAAAAAIZU/nSwv6nHbRvc/s640/s1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;5. Pobieramy własne repozytorium&lt;/h4&gt;Mamy już działający serwer SVN, pobierzmy teraz kopię roboczą z własnego serwera.&lt;br /&gt;Utwórzmy katalog &#39;C:/svnclient&#39; i pobierzmy do niego kopię repozytorium z naszego serwera:&lt;br /&gt;[code]&lt;br /&gt;$ cd C:/&lt;br /&gt;$ mkdir svnclient&lt;br /&gt;$ cd svnclient&lt;br /&gt;$ svn checkout http://localhost/svnserver testRepo&lt;br /&gt;$ cd testRepo&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-ScxcHzISoGA/VWiN2KIKpmI/AAAAAAAAIZc/NzVyLblvC48/s1600/C4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;324&quot; src=&quot;http://1.bp.blogspot.com/-ScxcHzISoGA/VWiN2KIKpmI/AAAAAAAAIZc/NzVyLblvC48/s640/C4.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To samo możemy zrobić za pomocą klienta TortoiseSVN.&lt;br /&gt;Nasza kopia została pobrana do:&lt;br /&gt;[code]C:/svnclient/testRepo[/code]&lt;br /&gt;&lt;br /&gt;Mamy już kopię roboczą, na której możemy pracować, utwórzmy w niej jakiś plik, ponownie np.:&lt;br /&gt;[code]test.txt[/code]&lt;br /&gt;Dodajmy następnie ten plik do repozytorium:&lt;br /&gt;[code]$ svn add test.txt[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-Iz_8AZrxjqQ/VWiN6kuf1LI/AAAAAAAAIZk/z9Xs668XaE8/s1600/c5.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;324&quot; src=&quot;http://2.bp.blogspot.com/-Iz_8AZrxjqQ/VWiN6kuf1LI/AAAAAAAAIZk/z9Xs668XaE8/s640/c5.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I wejdźmy na nasz serwer:&lt;br /&gt;[code]http://localhost/svnserver[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-EMj1RjXQPH8/VWiNvYTMIbI/AAAAAAAAIZY/uUu7q1EreYE/s1600/s1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;352&quot; src=&quot;http://1.bp.blogspot.com/-EMj1RjXQPH8/VWiNvYTMIbI/AAAAAAAAIZY/uUu7q1EreYE/s640/s1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać nasz plik test.txt nie pojawił się w naszym źródłowym repozytorium, istnieje jedynie w naszej kopii roboczej.&lt;br /&gt;Aby wysłać zmiany na serwer, do głównego repozytorium, musimy wykonać operację &quot;commit&quot;, która zatwierdzi zmiany w kopii roboczej i stworzy nową rewizję na serwerze:&lt;br /&gt;&lt;br /&gt;Zrobimy to w konsoli:&lt;br /&gt;[code]$ svn commit -m &quot;Dodano nowy plik&quot;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-lkbuBVMXGAE/VWiN_w0MYtI/AAAAAAAAIZs/aKrhgEuy210/s1600/c6.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;324&quot; src=&quot;http://4.bp.blogspot.com/-lkbuBVMXGAE/VWiN_w0MYtI/AAAAAAAAIZs/aKrhgEuy210/s640/c6.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;lub za pomocą Tortoise:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-0ojd-WAC7E0/VWiOGRVHAbI/AAAAAAAAIZ0/rNKosaW20Ek/s1600/w9.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://4.bp.blogspot.com/-0ojd-WAC7E0/VWiOGRVHAbI/AAAAAAAAIZ0/rNKosaW20Ek/s640/w9.png&quot; width=&quot;435&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Wejdźmy ponownie na nasz serwer:&lt;br /&gt;[code]http://localhost/svnserver[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-RyLxrE1ZhDA/VWiOQ5DeGwI/AAAAAAAAIZ8/NMnXidOVk3M/s1600/s2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;312&quot; src=&quot;http://2.bp.blogspot.com/-RyLxrE1ZhDA/VWiOQ5DeGwI/AAAAAAAAIZ8/NMnXidOVk3M/s640/s2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;jak widzimy plik pojawił się w naszym głównym repozytorium, a rewizja zwiększyła się o jeden.&lt;br /&gt;&lt;br /&gt;Dokonajmy teraz jakiś zmian w pliku &#39;test.txt&#39;, pododawajmy nowe pliki i poróbmy kilka kolejnych &#39;commitów&#39;.&lt;br /&gt;Jak widać, za każdym razem numer rewizji zwiększa się.&lt;br /&gt;&lt;br /&gt;Aby teraz przejrzeć historię naszych rewizji użyjemy ładnego graficznego GUI wchodzącego w skład pakietu Tortoise.&lt;br /&gt;Klikając PPM na danym pliku i wybierając z menu:&lt;br /&gt;[code]TortoiseSVN -&amp;gt; RevisionGraph[/code]&lt;br /&gt;dostajemy do dyspozycji narzędzie pokazujące nam historię naszego pliku, narazie jest ona uboga, ale zobaczmy:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-ygPYdQllVeo/VWiOhwU4exI/AAAAAAAAIaM/psyPj1N7XnM/s1600/w10.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;424&quot; src=&quot;http://2.bp.blogspot.com/-ygPYdQllVeo/VWiOhwU4exI/AAAAAAAAIaM/psyPj1N7XnM/s640/w10.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Oczywiście w SVN w każdej chwili możemy przywrócić stan pliku z przed danej rewizji.&lt;br /&gt;W tym przecież tkwi potęga systemów wersjonowania kodu :)&lt;br /&gt;&lt;br /&gt;Innymi przydatnymi programami z pakietu Tortoise będą też:&lt;br /&gt;&lt;br /&gt;[code]TortoiseSVN -&amp;gt; ShowLog[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-ogg112PN_2k/VWijyKaTiSI/AAAAAAAAIb4/-TASEYhV2rU/s1600/log1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;332&quot; src=&quot;http://4.bp.blogspot.com/-ogg112PN_2k/VWijyKaTiSI/AAAAAAAAIb4/-TASEYhV2rU/s640/log1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;oraz&lt;br /&gt;&lt;br /&gt;[code]TortoiseSVN -&amp;gt; Repository Browser[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-C72UNfl8yZI/VWij4pbQbaI/AAAAAAAAIcA/rXxmGXJR-3o/s1600/browser.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;520&quot; src=&quot;http://3.bp.blogspot.com/-C72UNfl8yZI/VWij4pbQbaI/AAAAAAAAIcA/rXxmGXJR-3o/s640/browser.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h4&gt;6. Update&lt;/h4&gt;Co jeśli repozytorium na serwerze zmieni się, a my posiadamy np. starszą jego kopię?&lt;br /&gt;Do synchronizacji służy polecenie:&lt;br /&gt;[code]$ svn update[/code]&lt;br /&gt;Zobaczmy na przykładzie:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-UvbFuVv3dfM/VWiUcdufdgI/AAAAAAAAIao/nbjPuxfwZL0/s1600/c7.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;324&quot; src=&quot;http://1.bp.blogspot.com/-UvbFuVv3dfM/VWiUcdufdgI/AAAAAAAAIao/nbjPuxfwZL0/s640/c7.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Do tego samego służy analogiczna opcja dostępna w menu kontekstowym Tortoise:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-sMuAsWixHIw/VWiOXfpVgOI/AAAAAAAAIaE/I-RIyva2lDw/s1600/w11.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;338&quot; src=&quot;http://2.bp.blogspot.com/-sMuAsWixHIw/VWiOXfpVgOI/AAAAAAAAIaE/I-RIyva2lDw/s640/w11.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;h4&gt;7. Autoryzacja&lt;/h4&gt;Pozostaje nam jeszcze kwestia zabezpieczenia naszego serwera hasłem, tak aby jedynie wybrani użytkownicy mieli dostęp do repozytorium. Zrobimy to za pomocą modułu uwierzytelniania Apache&#39;a. Na temat uwierzytelniania krok po kroku pisałem w &lt;b&gt;&lt;a href=&quot;http://phpeverywhere.blogspot.com/2015/05/apache-autoryzacja-za-pomoca-htpasswd.html&quot; target=&quot;_blank&quot;&gt;tym artykule&lt;/a&gt;&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Na początek utworzymy plik z hasłami dla uprawnionych użytkowników, zrobimy to za pomocą apachowego polecenia:&lt;br /&gt;[code]htpasswd[/code]&lt;br /&gt;które służy do generowania plików z hasłami.&lt;br /&gt;&lt;br /&gt;Utwórzmy np. hasła dla użytkowników:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;janusz&lt;/li&gt;&lt;li&gt;anna&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;W terminalu wpiszmy:&lt;br /&gt;[code]&lt;br /&gt;$ /ścieżka/do/apache/bin/htpasswd -cm C:/svn-auth janusz&lt;br /&gt;[podajemy hasło]&lt;br /&gt;&lt;br /&gt;$ /ścieżka/do/apache/bin/htpasswd -m C:/svn-auth anna&lt;br /&gt;[podajemy hasło]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-nVP0garuD_I/VWiOrcbI_2I/AAAAAAAAIaU/B3hMhlQQAC0/s1600/c8.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;324&quot; src=&quot;http://3.bp.blogspot.com/-nVP0garuD_I/VWiOrcbI_2I/AAAAAAAAIaU/B3hMhlQQAC0/s640/c8.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Utworzy nam to plik z hasłami:&lt;br /&gt;[code]C:/svn-auth[/code]&lt;br /&gt;&lt;br /&gt;dla użytkowników:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;janusz&lt;/li&gt;&lt;li&gt;anna&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Plik ten skopiujmy do:&lt;br /&gt;[code]/ścieżka/do/apache/conf/svn-auth[/code]&lt;br /&gt;&lt;br /&gt;Następnie w pliku konfiguracyjnym apacha:&lt;br /&gt;[code]/ścieżka/do/apache/conf/httpd.conf[/code]&lt;br /&gt;&lt;br /&gt;zmieńmy dodaną wcześniej linijkę:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Location /svnserver&amp;gt;&lt;br /&gt;DAV svn&lt;br /&gt;SVNPath &quot;C:/svnserver/myTestRepo&quot;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;na:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Location /svnserver&amp;gt;&lt;br /&gt;DAV svn&lt;br /&gt;SVNPath &quot;C:/svnserver/myTestRepo&quot;&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthName &quot;Login to SVN&quot;&lt;br /&gt;AuthUserFile &quot;conf/svn-auth&quot;&lt;br /&gt;Require valid-user&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Zapiszmy plik i zrestartujmy serwer.&lt;br /&gt;Od tej chwili dostęp do repozytorium dostępny jest jedynie za podaniem loginu i hasła.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Importowanie starego projektu do SVN&lt;/h2&gt;Co w przypadku jeśli mamy jakiś swój projekt i chcemy od tej chwili pracować z nim za pomocą SVN? Służy do tego polecenie &#39;import&#39;, które tworzy repozytorium dla istniejącego już projektu.&lt;br /&gt;&lt;br /&gt;Dla testów stwórzmy sobie folder:&lt;br /&gt;[code]C:/oldProject[/code]&lt;br /&gt;a w nim jakieś przykładowe pliki, np.:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;test.txt&lt;/li&gt;&lt;li&gt;test2.txt&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-NdMLPOcBzCg/VWihhoXpCZI/AAAAAAAAIbM/0eKJ6SouOt8/s1600/i0.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;232&quot; src=&quot;http://4.bp.blogspot.com/-NdMLPOcBzCg/VWihhoXpCZI/AAAAAAAAIbM/0eKJ6SouOt8/s640/i0.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Kolejnym krokiem jest utworzenie nowego pustego repozytorium na serwerze, np. tutaj:&lt;br /&gt;[code]C:/svnserver/myImportedRepo[/code]&lt;br /&gt;&lt;br /&gt;Zainicjujmy puste repozytorium o nazwie &#39;myImportedRepo&#39; w folderze &#39;C:/svnserver&#39;:&lt;br /&gt;[code]&lt;br /&gt;$ cd C:/svnserver&lt;br /&gt;$ svnadmin create myImportedRepo&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-_TkX_Vgy2TE/VWihowM34YI/AAAAAAAAIbU/4NijZHIL398/s1600/i1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;326&quot; src=&quot;http://3.bp.blogspot.com/-_TkX_Vgy2TE/VWihowM34YI/AAAAAAAAIbU/4NijZHIL398/s640/i1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Następnie dodajmy nową ścieżkę do repozytorium w konfiguracji Apache&#39;a w pliku &#39;httpd.conf&#39;:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Location /svnserver2&amp;gt;&lt;br /&gt;DAV svn&lt;br /&gt;SVNPath &quot;C:/svnserver/myImportedRepo&quot;&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Zapiszmy plik i zrestartujmy Apache&#39;a.&lt;br /&gt;Repozytorium &#39;myImportedRepo&#39; będzie dostępne pod adresem:&lt;br /&gt;[code]http://localhost/svnserver2[/code]&lt;br /&gt;&lt;br /&gt;Następnie, aby zaimportować pliki z folderu:&lt;br /&gt;[code]C:/oldProject[/code]&lt;br /&gt;do repozytorium:&lt;br /&gt;[code]C:/svnserver/myImportedRepo[/code]&lt;br /&gt;&lt;br /&gt;wpisujemy w konsoli:&lt;br /&gt;[code]&lt;br /&gt;$ cd C:/&lt;br /&gt;$ svn import -m &quot;Importujemy pliki&quot; oldProject http://localhost/svnserver2&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-jrVRP0E6NoM/VWih0EfYd4I/AAAAAAAAIbc/C-8z3P52nxA/s1600/i2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;326&quot; src=&quot;http://1.bp.blogspot.com/-jrVRP0E6NoM/VWih0EfYd4I/AAAAAAAAIbc/C-8z3P52nxA/s640/i2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Możemy to też zrobić za pomocą Tortoise:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-yBCY667dmlo/VWih6-teG6I/AAAAAAAAIbk/9jJDvZkdYdw/s1600/i4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;626&quot; src=&quot;http://2.bp.blogspot.com/-yBCY667dmlo/VWih6-teG6I/AAAAAAAAIbk/9jJDvZkdYdw/s640/i4.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I to wszystko. Nasze repozytorium zawierające śledzone od tej pory przez Subversion pliki dostępne jest teraz pod adresem:&lt;br /&gt;[code]http://localhost/svnserver2[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-upUFaeNtGoQ/VWih-6DOYGI/AAAAAAAAIbs/2SlkifnZYVU/s1600/i3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;346&quot; src=&quot;http://2.bp.blogspot.com/-upUFaeNtGoQ/VWih-6DOYGI/AAAAAAAAIbs/2SlkifnZYVU/s640/i3.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I to tyle na początek, w kolejnych artykułach opiszę dalsze aspekty pracy z Subversion.&lt;br /&gt;Na chwilę obecną wiemy już jak używać klienta i jak postawić serwer, a także znamy już podstawy pracy z SVN, co na początek powinno umożliwić nam zapoznanie się z Subversion i podstawową możliwość pracy z repozytoriami.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/1609439994610160279/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/svn-instalacja-klienta-i-serwera-oraz-podstawy.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1609439994610160279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/1609439994610160279'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/svn-instalacja-klienta-i-serwera-oraz-podstawy.html' title='[SVN] Instalacja klienta i serwera oraz podstawy pracy z SVN'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-KncajoQ8b3U/VWD026HfTuI/AAAAAAAAH_w/1pzGeGOoJnw/s72-c/icoSVN.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-3802236720239978412</id><published>2015-05-28T20:00:00.000+02:00</published><updated>2015-05-28T20:15:49.674+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GD2"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><title type='text'>[PHP][GD2] Używanie czcionek TrueType</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Standardowa czcionka używana do tworzenia tekstu za pomocą imagestring() łagodnie rzecz ujmując pozostawia wiele do życzenia, warto zatem wiedzieć, że za pomocą biblioteki GD można &quot;pisać&quot; po obrazie dowolną czcionką. Czcionek w internecie znajdziemy multum, wybór ograniczony jest tutaj jedynie wyobraźnią. Co najlepsze - dołączenie zewnętrznej czcionki nie wymaga w GD jakiś specjalnych zabiegów - wszystko sprowadza się do pobrania pliku .ttf z zadaną czcionką TrueType, umieszczeniu go na serwerze, a następnie dołączeniu go do skryptu. W tym bardzo krótkim wpisie pokażę jak za pomocą kilku linijek kodu wygenerować efekt taki jak na obrazku poniżej:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-DXYpppdmH9s/VWdWj0O0WjI/AAAAAAAAIXY/S1Acgn7WGaM/s1600/txt2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://2.bp.blogspot.com/-DXYpppdmH9s/VWdWj0O0WjI/AAAAAAAAIXY/S1Acgn7WGaM/s640/txt2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Czcionka na powyższym obrazku została dołączona za pomocą PHP, nie została dodana w żadnym programie graficznym. Nazywa się Nasty i możecie ją pobrać &lt;b&gt;&lt;a href=&quot;https://drive.google.com/file/d/0B4Mb4UIYUBbkZHdwMHlvb2pOa2M/view?usp=sharing&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;stąd&lt;/a&gt;&lt;/b&gt;. Zdjęcie na jakim wygenerowano napis &lt;b&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-XgmcxcbsIa4/VWZrmayIn2I/AAAAAAAAIR0/HADps5dqmEo/s1600/angelina.jpg&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;stąd&lt;/a&gt;&lt;/b&gt;. Opiszę teraz w skrócie jak za pomocą zewnętrznej czcionki wygenerować na obrazie napis jak wyżej. Na początek pobierzmy sobie tą czcionkę (plik .ttf) w celach testowych i zapiszmy w katalogu, gdzie pisać będziemy nasz kod. Do pisania czcionką TrueType, którą załączamy z zewnetrznego pliku .ttf służy funkcja:&lt;br /&gt;&lt;br /&gt;[code]imagettftext($image, $font_size, $angle, $x, $y, $color, $font, $text);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazu&lt;/li&gt;&lt;li&gt;&lt;b&gt;$font_size&lt;/b&gt; - rozmiar czcionki w px&lt;/li&gt;&lt;li&gt;&lt;b&gt;$angle&lt;/b&gt; - kąt obrotu czcionki w stopniach&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x&lt;/b&gt; - współrzędna X, od której zaczynamy pisanie&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y&lt;/b&gt; - współrzędna Y, od której zaczynamy pisanie&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color&lt;/b&gt; - kolor czcionki&lt;/li&gt;&lt;li&gt;&lt;b&gt;$font &lt;/b&gt;- nazwa pliku z czcionką&lt;/li&gt;&lt;li&gt;&lt;b&gt;$text &lt;/b&gt;- pisany tekst&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;Zobaczmy na przykładzie:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&quot;angelina.jpg&quot;);&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;&lt;br /&gt;$font = &#39;nasty.ttf&#39;;&lt;br /&gt;$txt = &#39;ANGELINA&#39;;&lt;br /&gt;$x = 400;&lt;br /&gt;$y = 350;&lt;br /&gt;$size = 90;&lt;br /&gt;$angle = 0;&lt;br /&gt;&lt;br /&gt;imagettftext($image, $size, $angle, $x+1, $y+1, $black, $font, $txt); // +1px w dół, +1px w prawo&lt;br /&gt;imagettftext($image, $size, $angle, $x-1, $y-1, $black, $font, $txt); // -1px w górę, -1px w lewo&lt;br /&gt;imagettftext($image, $size, $angle, $x, $y, $white, $font, $txt);&lt;br /&gt;&lt;br /&gt;header(&#39;Content-type: image/png&#39;); &lt;br /&gt;ImagePNG($image); &lt;br /&gt;imagedestroy($image); &lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;Powyższy kod wygeneruje dokładnie taki sam efekt jak na załączonym obrazku.&lt;br /&gt;Ot cała filozofia. Warto jednak zwrócić uwagę na fakt, iż tekst jest tutaj tworzony aż trzy razy. Dlaczego? Otóż właściwym tekstem jest ten o kolorze białym, tekst pisany czcionką czarną robi tutaj za obramowanie i jest przesunięty pod spodem o jeden pixel najpierw w górę, potem w dół, a także o jeden pixel na boki. Powodem zastosowania takiej konstrukcji jest to, że w bibliotece GD do pisania daną czcionką można użyć jednocześnie tylko jednego koloru, tym samym czcionka nie posiada tutaj żadnego widocznego konturu, co na niekontrastowym tle może powodować problem z widocznością. Rozwiązanie takie jak powyżej pozwala wyeliminować tą niedogodność i umożliwia nam uzyskanie czegoś w stylu efektu cienia, bądż konturu dla wyświetlanego tekstu.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/3802236720239978412/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-uzywanie-czcionek-truetype.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3802236720239978412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3802236720239978412'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-uzywanie-czcionek-truetype.html' title='[PHP][GD2] Używanie czcionek TrueType'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s72-c/icoPHP_GD.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-5943953589183166087</id><published>2015-05-28T18:30:00.002+02:00</published><updated>2015-05-31T23:26:26.097+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GD2"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><title type='text'>[PHP][GD2] Prosty gradient i operacje na kolorach pikseli</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;W bibliotece GD mamy pełną kontrolę nad każdym pikselem składającym się na wynikowy obrazek. Możemy dowolnie pobierać jego wartości i ustawiać nowe. Możliwość taka, w połączeniu z odpowiednio skonstruowanymi pętlami pozwala na bardzo wiele, m.in. na generowanie gradientów, czyli przejść pomiędzy kolorami. Funkcje do tworzenia złożonych gradientów są dość obszerne, my tutaj postaramy się nauczyć podstaw tworzenia prostych gradientów polegających na liniowym przejściu pomiędzy kolorami. Nauczymy się też operować na pikselach - pobierać oraz modyfikować ich wartości.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tworzymy gradient&lt;/h2&gt;Popatrzmy na poniższy obrazek:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-gv1c8zvUd3g/VWdBeh5v1mI/AAAAAAAAIV8/xhcfu7rITaM/s1600/g1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;272&quot; src=&quot;http://2.bp.blogspot.com/-gv1c8zvUd3g/VWdBeh5v1mI/AAAAAAAAIV8/xhcfu7rITaM/s640/g1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;To prosty gradient wygenerowany bezpośrednio w PHP za pomocą jednej prostej pętli for. Aby móc tworzyć podobne obrazki za pomocą swoich funkcji trzeba zrozumieć zasadę działania takiego mechanizmu. Najprostrzym sposobem na wygenerowanie liniowego przejścia jest pętla przechodząca pionowo lub poziomo inkrementująca się o jeden piksel wraz z każdym kolejnym przebiegiem. W każdym przebiegu jednocześnie zmniejszana lub zwiększana musi być wartość zadanego przez nas koloru. Jak wiemy - kolory definiujemy za pomocą podawania ich odpowiednich wartości liczbowych w palecie RGB. Skoro więc są to zwykłe dane liczbowe, nic nie stoi na przeszkodzie, aby wykonywać na nich dowolne operacje matematyczne. Aby zrozumieć zasadę działania, stwórzmy sobie obrazek o szerokości 600px i wysokości 256 pikseli:&lt;br /&gt;[code]&lt;br /&gt;$width = 600;&lt;br /&gt;$height = 256;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;[/code]&lt;br /&gt;następnie stwórzmy pętlę for, która będzie przebiegać pionowo po naszym obrazku:&lt;br /&gt;[code]&lt;br /&gt;for($i=0; $i &amp;lt; $height; $i++)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; // ....&lt;br /&gt;};&lt;br /&gt;[/code]&lt;br /&gt;Jak widzimy pętla przebiegać będzie po koleji po &quot;wierszach&quot; obrazka, począwszy od wiersza 0, na ostatnim wierszu (w tym przypadku 255) kończąc. Dodajmy teraz do naszej pętli następujący kod:&lt;br /&gt;[code]&lt;br /&gt;for($i=0; $i &amp;lt; $height; $i++)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $color = imagecolorallocate($image, $i, $i, $i);&lt;br /&gt;&amp;nbsp; imageline($image, 0, $i, $width, $i, $color);&lt;br /&gt;};&lt;br /&gt;[/code]&lt;br /&gt;W każdym kolejnym przebiegu definiujemy nowy kolor, którego wartość będzie rosła liniowo wraz z inkrementacją zmiennej $i. Następnie rysujemy linię po całej szerokości naszego obrazka, o współrzędnej Y pobieranej również ze zmiennej $i. W każdym wierszu naszego obrazka będzie więc rysowana pozioma linia o wartości koloru rosnącej wraz z każdym przebiegiem pętli, aż do uzyskania końcowego miejsca na obrazie (255px w pionie).&lt;br /&gt;&lt;br /&gt;Przetestujmy w praktyce:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 600;&lt;br /&gt;$height = 256;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;for($i=0; $i &amp;lt; $height; $i++)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $color = imagecolorallocate($image, $i, $i, $i);&lt;br /&gt;&amp;nbsp; imageline($image, 0, $i, $width, $i, $color);&lt;br /&gt;};&lt;br /&gt;header(&#39;Content-Type: image/png&#39;);&lt;br /&gt;imagepng($image);&lt;br /&gt;imagedestroy($image);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynikiem będzie najprostszy z możliwych gradient:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-Ar1h2J32K8U/VWdBqIBmePI/AAAAAAAAIWE/FXPyoLRoTfA/s1600/g1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;272&quot; src=&quot;http://3.bp.blogspot.com/-Ar1h2J32K8U/VWdBqIBmePI/AAAAAAAAIWE/FXPyoLRoTfA/s640/g1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Zmodfikujmy teraż nasz kod, tak aby pozwalał na wygenerowanie gradientu dla dowolnego rozmiaru obrazka - póki co mamy tu ograniczenie do 255px, bo tylko tyle maksymalnie może przyjąć wartość RGB. Musimy więc teraz w jakiś sposób obliczyć co ile pikeli mamy zwiększać wartość naszego koloru w zależności od całkowitej wysokości naszego obrazu.&lt;br /&gt;Wykonany to poniższym sposobem:&lt;br /&gt;[code]&lt;br /&gt;for($i=0; $i&amp;lt;$height; $i++) &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; $color = floor($i * 255 / $height);&lt;br /&gt;&amp;nbsp; $color = imagecolorallocate($image, $color, $color, $color);&lt;br /&gt;&amp;nbsp; imageline($img, 0, $i, $width, $i, $color);&lt;br /&gt;}; &lt;br /&gt;[/code]&lt;br /&gt;Wartość koloru obliczamy algorytmem:&lt;br /&gt;[code]współrzędnaY * 255 / całkowita_wysokość obrazka[/code]&lt;br /&gt;Funkcja floor() zakokrągla nam wynik do najbliższej, najniższej wartości całkowitej, np. floor(3.14) da nam 3.&lt;br /&gt;&lt;br /&gt;Zobaczmy teraz, czy to zadziała, np. dla obrazka o wymiarach 600x450px:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 600;&lt;br /&gt;$height = 450;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;&lt;br /&gt;for($i=0; $i&amp;lt;$height; $i++) &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; $color = floor($i * 255 / $height);&lt;br /&gt;&amp;nbsp; $color = imagecolorallocate($image, $color, $color, $color);&lt;br /&gt;&amp;nbsp; imageline($image, 0, $i, $width, $i, $color);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;imagestring($image, 5, 140, 210, &amp;nbsp;&#39;RGB($color++, $color++, $color++)&#39;, $white);&lt;br /&gt;header(&#39;Content-Type: image/png&#39;);&lt;br /&gt;imagepng($image);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-SGZQ5yoPd5k/VWdBxfLB8gI/AAAAAAAAIWM/BX17LY-KRYw/s1600/g2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;480&quot; src=&quot;http://1.bp.blogspot.com/-SGZQ5yoPd5k/VWdBxfLB8gI/AAAAAAAAIWM/BX17LY-KRYw/s640/g2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać działa. Gradient rozciągnął się na całą wysokość obrazu.&lt;br /&gt;Nasze linearne wypełnienie jest jednak trochę nudne prawda? Dodajmy mu trochę koloru.&lt;br /&gt;Jak to zrobić? Otóż w chwii obecnej zwiększamy w naszej pętli wartości wszystkich składowych RGB jednocześnie, co za tym idzie nasz gradient generuje się liniowo od koloru czarnego (RGB = 0,0,0) do koloru białego (RGB = 255, 255, 255). Zostawmy więc np. wartości koloru zielonego i niebieskiego w spokoju, a zwiększajmy jedynie wartość składowej czerwonej:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 600;&lt;br /&gt;$height = 450;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;&lt;br /&gt;for($i=0; $i&amp;lt;$height; $i++) &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; $color = floor($i * 255 / $height);&lt;br /&gt;&amp;nbsp; $color = imagecolorallocate($image, $color, 0, 0);&lt;br /&gt;&amp;nbsp; imageline($image, 0, $i, $width, $i, $color);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;imagestring($image, 5, 200, 210, &amp;nbsp;&#39;RGB($color++, 0, 0)&#39;, $white);&lt;br /&gt;header(&#39;Content-Type: image/png&#39;);&lt;br /&gt;imagepng($image);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynik:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-VbLBTs2CwJ8/VWdB4qWx0cI/AAAAAAAAIWU/K73G99lMfWU/s1600/g3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;480&quot; src=&quot;http://1.bp.blogspot.com/-VbLBTs2CwJ8/VWdB4qWx0cI/AAAAAAAAIWU/K73G99lMfWU/s640/g3.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;A teraz dla składowej zielonej:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 600;&lt;br /&gt;$height = 450;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;&lt;br /&gt;for($i=0; $i&amp;lt;$height; $i++) &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; $color = floor($i * 255 / $height);&lt;br /&gt;&amp;nbsp; $color = imagecolorallocate($image, 0, $color, 0);&lt;br /&gt;&amp;nbsp; imageline($image, 0, $i, $width, $i, $color);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;imagestring($image, 5, 200, 210, &amp;nbsp;&#39;RGB(0, $color++, 0)&#39;, $white);&lt;br /&gt;header(&#39;Content-Type: image/png&#39;);&lt;br /&gt;imagepng($image);&lt;br /&gt;imagedestroy($image);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-2h6kD-UX3oE/VWdB8EV4E7I/AAAAAAAAIWc/NSalk3qNrbA/s1600/g4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;480&quot; src=&quot;http://4.bp.blogspot.com/-2h6kD-UX3oE/VWdB8EV4E7I/AAAAAAAAIWc/NSalk3qNrbA/s640/g4.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I niebieskiej:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 600;&lt;br /&gt;$height = 450;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;&lt;br /&gt;for($i=0; $i&amp;lt;$height; $i++) &lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; $color = floor($i * 255 / $height);&lt;br /&gt;&amp;nbsp; $color = imagecolorallocate($image, 0, 0, $color);&lt;br /&gt;&amp;nbsp; imageline($image, 0, $i, $width, $i, $color);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;imagestring($image, 5, 200, 210, &amp;nbsp;&#39;RGB(0, 0, $color++)&#39;, $white);&lt;br /&gt;header(&#39;Content-Type: image/png&#39;);&lt;br /&gt;imagepng($image);&lt;br /&gt;imagedestroy($image);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-p1z4GEEyu3k/VWdB_XR8srI/AAAAAAAAIWk/pxzjSU0kCP4/s1600/g5.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;480&quot; src=&quot;http://2.bp.blogspot.com/-p1z4GEEyu3k/VWdB_XR8srI/AAAAAAAAIWk/pxzjSU0kCP4/s640/g5.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać, mamy tutaj duże pole do popisu odnośnie miksowania kolorów.&lt;br /&gt;Warto też zauważyć, że tym sposobem możemy zabawić się również z przezroczystością modyfikujac liniowo wartość kanału alpha.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageColorAt() - pobieranie wartości koloru z piksela&lt;/h2&gt;Dzięki funkcji imagecolorat() możemy pobrać wartość koloru dla dowolnego piksela w obrazie. Zwracana wartość to indeks koloru w postaci liczby integer, musimy użyć przesunięć bitowych, aby uzyskać wartości poszczególnych składowych. Użycie funkcji przedstawia się następująco:&lt;br /&gt;[code]$rgb = imagecolorat($image, $x, $y)[/code]&lt;br /&gt;gdzie&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x&lt;/b&gt; - współrzędna X piksela&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y&lt;/b&gt; - współrzędna Y piksela&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Wartość RGB pobierzemy tak:&lt;br /&gt;[code]&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;$rgb = imagecolorat($image, 10, 15);&lt;br /&gt;$pixel[&#39;r&#39;] = ($rgb &amp;gt;&amp;gt; 16) &amp;amp; 0xFF;&lt;br /&gt;$pixel[&#39;g&#39;] = ($rgb &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;$pixel[&#39;b&#39;] = $rgb &amp;amp; 0xFF;&lt;br /&gt;[/code]&lt;br /&gt;Możemy stworzyć sobie do tego prostą funkcję:&lt;br /&gt;[code]&lt;br /&gt;function getRgb($image, $x, $y)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $rgb = imagecolorat($image, $x, $y);&lt;br /&gt;&amp;nbsp; $pixel[&#39;r&#39;] = ($rgb &amp;gt;&amp;gt; 16) &amp;amp; 0xFF;&lt;br /&gt;&amp;nbsp; $pixel[&#39;g&#39;] = ($rgb &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;&amp;nbsp; $pixel[&#39;b&#39;] = $rgb &amp;amp; 0xFF;&lt;br /&gt;&amp;nbsp; return $pixel;&lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Sprawdźmy w praktyce jak to działa.&lt;br /&gt;Wczytajmy zdjęcie z Angeliną, nad którym pastwiliśmy się w &lt;a href=&quot;http://www.phpeverywhere.blogspot.com/2015/05/phpgd2-manipulacje-obrazami.html&quot; target=&quot;_blank&quot;&gt;tym artykule&lt;/a&gt; i pobierzmy wartości kilku pixeli, po czym wyświetlmy te wartości na obrazku:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;function getRgb($image, $x, $y, $show = true)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;&lt;br /&gt;&amp;nbsp; $rgb = imagecolorat($image, $x, $y);&lt;br /&gt;&amp;nbsp; $pixel[&#39;r&#39;] = ($rgb &amp;gt;&amp;gt; 16) &amp;amp; 0xFF;&lt;br /&gt;&amp;nbsp; $pixel[&#39;g&#39;] = ($rgb &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;&lt;br /&gt;&amp;nbsp; $pixel[&#39;b&#39;] = $rgb &amp;amp; 0xFF; &lt;br /&gt;&amp;nbsp; // pobieramy wartości RGB do tablicy&lt;br /&gt;&lt;br /&gt;&amp;nbsp; if($show)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; imageellipse($image, $x, $y, 10, 10, $white);&lt;br /&gt;&amp;nbsp; &amp;nbsp; // rysujemy elipsę w miejscu badanego pixela&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&amp;nbsp; &amp;nbsp; $str = &#39;R:&#39;.$pixel[&#39;r&#39;].&#39; G:&#39;.$pixel[&#39;g&#39;].&#39; B:&#39;.$pixel[&#39;b&#39;];&lt;br /&gt;&amp;nbsp; &amp;nbsp; imagestring($image, 5, $x + 5, $y + 5, &amp;nbsp;$str, $white); &lt;br /&gt;&amp;nbsp; &amp;nbsp; // wyświetlamy wartość w miejscu badanego pixela &lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&amp;nbsp; return $pixel; // zwracamy tablicę z wartościami RGB&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$image = imagecreatefromjpeg(&quot;angelina.jpg&quot;);&lt;br /&gt;$pixel_color[1] = getRgb($image, 100, 100);&lt;br /&gt;$pixel_color[2] = getRgb($image, 400, 340);&lt;br /&gt;$pixel_color[3] = getRgb($image, 130, 30);&lt;br /&gt;// pobieramy RGB pixeli&lt;br /&gt;&lt;br /&gt;header(&#39;Content-type: image/png&#39;); &lt;br /&gt;ImagePNG($image); &lt;br /&gt;imagedestroy($image); &lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynik:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-l5QwEhSOre4/VWdCFqSfgHI/AAAAAAAAIWs/HHOcH9i0GrA/s1600/px1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://2.bp.blogspot.com/-l5QwEhSOre4/VWdCFqSfgHI/AAAAAAAAIWs/HHOcH9i0GrA/s640/px1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageSetPixel() - ustawianie wartości RGB piksela&lt;/h2&gt;Analogicznie do funkcji pobierającej dane o wartości piksela mozemy zadziałać w drugą stronę - ustawić wartości pikseli. Służy do tego omawiana funkcja, której użycie wygląda tak:&lt;br /&gt;[code]imagesetpixel($image, $x, $y, $color)[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x &lt;/b&gt;- współrzędna X piksela&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y&lt;/b&gt; - współrzędna Y piksela&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color&lt;/b&gt; - kolor jaki ustawiamy&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Przykładowo, zmieńmy wartości kilku pikseli w lewym górnym rogu obrazka.&lt;br /&gt;Jest tam akurat czarne tło - zmienimy kilka pixeli na kolor biały.&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&quot;angelina.jpg&quot;);&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;&lt;br /&gt;imagesetpixel($image, 20, 10, $white);&lt;br /&gt;imagesetpixel($image, 30, 20, $white);&lt;br /&gt;imagesetpixel($image, 4, 50, $white);&lt;br /&gt;imagesetpixel($image, 50, 70, $white);&lt;br /&gt;imagesetpixel($image, 10, 17, $white);&lt;br /&gt;imagesetpixel($image, 44, 2, $white);&lt;br /&gt;imagesetpixel($image, 80, 4, $white);&lt;br /&gt;imagesetpixel($image, 65, 12, $white);&lt;br /&gt;&lt;br /&gt;header(&#39;Content-type: image/png&#39;); &lt;br /&gt;ImagePNG($image); &lt;br /&gt;imagedestroy($image); &lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Tym sposobem postawiliśmy na obrazie kilka małych &quot;kropek&quot;:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-ir5DxiA3eNA/VWdCLxk25HI/AAAAAAAAIW0/_6beDBvQBlY/s1600/px2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-ir5DxiA3eNA/VWdCLxk25HI/AAAAAAAAIW0/_6beDBvQBlY/s640/px2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Oczywiście takich modyfikacji nie wykonuje się ręcznie dla każdego piksela oddzielnie - do tego buduje się funkcje i pętle robiące to &quot;hurtowo&quot;. Zaprezentowałem tutaj jedynie prosty przykład mający na celu pokazać, że funkcja taka istnieje i jak jej używać. Przy wykorzystaniu faktu pobierania wartości dowolnych pikseli i ustawiania im własnych wartości można uzyskać naprawdę rozudowane możliwości. Zachęcam do eksperymentowania we własnym zakresie.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/5943953589183166087/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-prosty-gradient-i-operacje-na-kolorach-pikseli.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5943953589183166087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5943953589183166087'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-prosty-gradient-i-operacje-na-kolorach-pikseli.html' title='[PHP][GD2] Prosty gradient i operacje na kolorach pikseli'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s72-c/icoPHP_GD.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-6962189171884698785</id><published>2015-05-28T03:34:00.002+02:00</published><updated>2015-05-28T14:09:41.181+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GD2"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><title type='text'>[PHP][GD2] Manipulacje obrazami</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Dzięki bibliotece GD możemy manipulować dowolnymi obrazami zapisanymi w formatach JPEG, PNG, GIF i BMP. Możemy dokonywać na nich operacji takich samych jakie robiliśmy w poprzednich artykułach, a więc rysować po nich, pisać, a także łączyć je, skalować, obracać i wiele innych rzeczy. W artykule tym nauczymy się wczytywania obrazków z plików, manipulacji na nich, takich jak skalowanie, czy dodawanie do nich innej grafiki, a także zapisywania wygenerowanych i zmodyfikowanych obrazów do pliku. Warto dokładnie zapoznać się choćby z podstawowymi funkcjami służącymi do manipulacji grafiką, tak aby móc następnie wykorzystywać to w praktyce, np. podczas generowania, czy tworzenia miniaturek dla zdjęć, bądź dodawania znaków wodnych do zdjęć. Zastosowań jest multum, zatem zaczynamy. Na początek nauczymy się wczytywać grafikę z pliku. Jak wspomniałem na początku - mamy tutaj zaimplementowaną obsługę kilku formatów plików. Praca z nimi niczym się od siebie nie różni, używamy do tego jedynie odpowiednio innych funkcji.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageCreateFrom() - wczytanie obrazka z pliku&lt;/h2&gt;W poprzednich atykułach na samym początku tworzyliśmy uchwyt do pustego obrazka i dopiero potem na nim pracowaliśmy, rysując figury jak prostokąty, czy elipsy. W tym odcinku zamiast tworzyć pusty obrazek, wczytamy go z pliku JPG. Do wczytania obrazka z pliku służy kilka funkcji, w zależności od tego jaki format ma obrazek, który chcemy wczytać. I tak, np.&lt;br /&gt;[code]&lt;br /&gt;imagecreatefromjpeg($nazwa_pliku) //wczytuje obrazek z pliku JPG&lt;br /&gt;imagecreatefrompng($nazwa_pliku) //wczytuje obrazek z pliku PNG&lt;br /&gt;imagecreatefromgif($nazwa_pliku) &amp;nbsp;//wczytuje obrazek z pliku GIF&lt;br /&gt;imagecreatefrombmp($nazwa_pliku) &amp;nbsp;//wczytuje obrazek z pliku BMP&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Na początek naszej pracy pobierzmy sobie dwa poniższe zdjęcia do testów i zapiszmy sobie je w folderze, w którym pisać będziemy nasz kod. Żeby nam się przyjemnie pracowało, to na obu mamy 2 piękne panie :)&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-XgmcxcbsIa4/VWZrmayIn2I/AAAAAAAAIR0/HADps5dqmEo/s1600/angelina.jpg&quot; target=&quot;_blank&quot;&gt;zdjęcie #1: angelina.jpg&lt;/a&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-XgmcxcbsIa4/VWZrmayIn2I/AAAAAAAAIR0/HADps5dqmEo/s1600/angelina.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-XgmcxcbsIa4/VWZrmayIn2I/AAAAAAAAIR0/HADps5dqmEo/s640/angelina.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;oraz&lt;/div&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-4dabtqdUXYo/VWZr1iOaFFI/AAAAAAAAIR8/bDjsSYMlc_A/s1600/monica.jpg&quot; target=&quot;_blank&quot;&gt;zdjęcie #2: monica.jpg&lt;/a&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-4dabtqdUXYo/VWZr1iOaFFI/AAAAAAAAIR8/bDjsSYMlc_A/s1600/monica.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-4dabtqdUXYo/VWZr1iOaFFI/AAAAAAAAIR8/bDjsSYMlc_A/s640/monica.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Gdy mamy oba zdjęcia zapisane w naszym folderze, wczytajmy pierwsze zdjęcie do naszego kodu:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Tym sposobem wczytane zdjęcie znajduje się teraz w naszym uchwycie (w poprzednich artykułach mieliśmy tutaj pusty obrazek). Możemy to sprawdzić. Jak widzimy zdjęcie jest w formacie JPG, wyświetlmy je zatem jako PNG:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;// wczytujemy zdjęcie do uchwytu&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Jak widać, dokonaliśmy nieświadomie pierwszej manipulacji, mianowicie konwersji z formatu JPG na format PNG.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageCopyResized() - skalowanie obrazu&lt;/h2&gt;Do przeskalowania gotowego obrazka służy funkcja:&lt;br /&gt;[code]imagecopyresized($new_image, $source_image, $new_x, $new_y, $source_x, $source_y, $new_width, $new_height, $source_width, $source_height);[/code]&lt;br /&gt;&lt;br /&gt;Jak widać składnia jest dość długa, ale powoli wytłumaczymy sobie wszystko.&lt;br /&gt;Funkcja ta powoduje skopiowanie jednego obrazka do drugiego (jak widzimy będziemy musieli tutaj utworzyć drugi uchwyt do nowego obrazka) pobierając za parametry informacje takie jak wielkość obrazka źródłowego oraz wielkość jaką chcemy uzyskać.&lt;br /&gt;Wyjaśnijmy sobie może najpierw wszystkie argumenty funkcji po koleji:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$new_image&lt;/b&gt; - uchwyt do nowo tworzonego obrazu&lt;/li&gt;&lt;li&gt;&lt;b&gt;$source_image&lt;/b&gt; - &amp;nbsp;uchwyt do obrazu źródłowego (nasza Angelina)&lt;/li&gt;&lt;li&gt;&lt;b&gt;$new_x&lt;/b&gt; - &amp;nbsp;współrzędna X od której zaczniemy nowy obrazek&lt;/li&gt;&lt;li&gt;&lt;b&gt;$new_y&lt;/b&gt; - &amp;nbsp;współrzędna Y od której zaczniemy nowy obrazek&lt;/li&gt;&lt;li&gt;&lt;b&gt;$source_x&lt;/b&gt; - &amp;nbsp;współrzędna X od której kopiujemy stary obrazek&lt;/li&gt;&lt;li&gt;&lt;b&gt;$source_y &lt;/b&gt;- współrzędna Y od której kopiujemy stary obrazek&lt;/li&gt;&lt;li&gt;&lt;b&gt;$new_width&lt;/b&gt; - &amp;nbsp;szerokosć nowego obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$new_height &lt;/b&gt;- &amp;nbsp;wysokość nowego obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$source_width&lt;/b&gt; - szerokosć obrazka źródłowego&lt;/li&gt;&lt;li&gt;&lt;b&gt;$source_height&lt;/b&gt; - wysokość obrazka źródłowego&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Wyjaśnienia tutaj wymagają wymagane współrzędne X i Y.&lt;br /&gt;Na czym to polega? Otóż kopiowanie starego obrazka może odbyć się od zadanego miejsca. Podając tutaj (x=0, y=0) rozpoczniemy kopiowanie obrazu źródłowego od jego początku, podając jednak np. x=200, y=200 rozpoczniemy właśnie od tego miejsca.&lt;br /&gt;&lt;br /&gt;Rozmiar źródłowego obrazu możemy w każdej chwili pobrać za pomocą funkcji:&lt;br /&gt;[code]$width = imagesx($image) // szerokość[/code]&lt;br /&gt;oraz&lt;br /&gt;[code]$height = imagesy($image) // wysokosć[/code]&lt;br /&gt;&lt;br /&gt;Zobaczmy działanie na przykładzie, najpierw skopiujmy całość nie zmieniając żadnych rozmiarów i zostawiając wszystkie parametry na domyślne. Rozdzielczość zdjęcia z Angeliną to: 760x360px.&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;// wczytujemy zdjęcie do uchwytu&lt;br /&gt;&lt;br /&gt;$image_width = imagesx($image);&lt;br /&gt;$image_height = imagesy($image);&lt;br /&gt;// pobieramy rozmiar oryginalnego obrazu&lt;br /&gt;&lt;br /&gt;$new_width = 760;&lt;br /&gt;$new_height = 360;&lt;br /&gt;// definiujemy rozmiar dla nowego obrazu&lt;br /&gt;&lt;br /&gt;$new_image = imagecreatetruecolor($new_width, $new_height);&lt;br /&gt;// tworzymy uchwyt dla nowego obrazu&lt;br /&gt;&lt;br /&gt;imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $image_width, $image_height);&lt;br /&gt;// kopiujemy, narazie bez zmiany parametrów&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($new_image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($new_image);&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyty do obrazków&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wynkiem jest to, że oba zdjęcia (źródłowe i docelowe) niczym się nie różnią:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-R5DVGQ5HgCE/VWZtiRsN9tI/AAAAAAAAISQ/KMxkYQUQRiw/s1600/a1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://3.bp.blogspot.com/-R5DVGQ5HgCE/VWZtiRsN9tI/AAAAAAAAISQ/KMxkYQUQRiw/s640/a1.jpg&quot; width=&quot;615&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;A teraz zmieńmy punkt początkowy (na obrazie docelowym), od którego będziemy nakładać skopiowany z pliku źródłowego obrazek, czyli $new_x i $new_y i zobaczmy co się stanie.&lt;br /&gt;Rozpoczynamy kopiowanie od punktu x=0, y=0, ale nanosimy kopię od punktu x=200, y=120 na nowym zdjęciu:&lt;br /&gt;[code]imagecopyresized($new_image, $image, 200, 150, 0, 0, $new_width, $new_height, $image_width, $image_height);[/code]&lt;br /&gt;Wynik:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-SGqWaE_XGXU/VWZtnNi8pfI/AAAAAAAAISY/zPHEdMyfwrw/s1600/a2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://4.bp.blogspot.com/-SGqWaE_XGXU/VWZtnNi8pfI/AAAAAAAAISY/zPHEdMyfwrw/s640/a2.jpg&quot; width=&quot;615&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Teraz zmieńmy punkt początkowy, od którego kopiować będziemy obrazek źródłowy.&lt;br /&gt;[code]imagecopyresized($new_image, $image, 0, 0, 200, 120, $new_width, $new_height, $image_width, $image_height);[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-qS1os8aJ0zY/VWZt_hNAbII/AAAAAAAAISg/8UTYWUHiNpY/s1600/a3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://2.bp.blogspot.com/-qS1os8aJ0zY/VWZt_hNAbII/AAAAAAAAISg/8UTYWUHiNpY/s640/a3.jpg&quot; width=&quot;614&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I w ostatnim przykładzie zmieńmy zarówno jedno jak i drugie:&lt;br /&gt;Rozpoczynamy kopiowanie od punktu x=200, y=120 i nanosimy kopię od punktu x=100, y=150 na nowym zdjęciu:&lt;br /&gt;[code]imagecopyresized($new_image, $image, 100, 150, 200, 120, $new_width, $new_height, $image_width, $image_height);[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-VUnAS9H-wyE/VWZuG1sirUI/AAAAAAAAISo/8FloIhHDyk8/s1600/a4.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://3.bp.blogspot.com/-VUnAS9H-wyE/VWZuG1sirUI/AAAAAAAAISo/8FloIhHDyk8/s640/a4.jpg&quot; width=&quot;614&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać, zmiana punktu początkowego zarówno w jednym jak i drugim zdjęciu przynosi różne efekty. Sprawdźmy teraz co się stanie podczas skalowania zdjęcia. Standardowo na początek pozostawmy wszystkie punkty początkowe w miejscach (0,0) ale teraz zmieńmy rozdzielczość obrazu wynikowego, np. na 380x180 czyli o połowę:&lt;br /&gt;[code]imagecopyresized($new_image, $image, 0, 0, 0, 0, 380, 180, $image_width, $image_height);[/code]&lt;br /&gt;Wynikiem jest:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-ddqngsN5crk/VWZuOGxMtBI/AAAAAAAAISw/hi9yaQdzLS8/s1600/r1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://1.bp.blogspot.com/-ddqngsN5crk/VWZuOGxMtBI/AAAAAAAAISw/hi9yaQdzLS8/s640/r1.jpg&quot; width=&quot;614&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać Angelina zmniejszyła nam się o połowę, ale rozmiar obrazu to wciąż 760x360px, dlaczego? Stało się tak z prostego powodu - na samym początku zadeklarowaliśmy taką właśnie wielkość dla nowego obrazu:&lt;br /&gt;[code]$new_width = 760;&lt;br /&gt;$new_height = 360;&lt;br /&gt;$new_image = imagecreatetruecolor($new_width, $new_height);&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Natomiast w funkcji imagecopyresized parametry te wpisaliśmy ręcznie, w związku z czym obrazek zeskalował się poprawnie, ale jego bazowa wielkość pozostała bez zmian.&lt;br /&gt;Zmieńmy to więc na 380x180 i zobaczmy co sie stanie:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;// wczytujemy zdjęcie do uchwytu&lt;br /&gt;&lt;br /&gt;$image_width = imagesx($image);&lt;br /&gt;$image_height = imagesy($image);&lt;br /&gt;// pobieramy rozmiar oryginalnego obrazu&lt;br /&gt;&lt;br /&gt;$new_width = 380;&lt;br /&gt;$new_height = 180;&lt;br /&gt;// definiujemy rozmiar dla nowego obrazu&lt;br /&gt;&lt;br /&gt;$new_image = imagecreatetruecolor($new_width, $new_height);&lt;br /&gt;// tworzymy uchwyt dla nowego obrazu&lt;br /&gt;&lt;br /&gt;imagecopyresized($new_image, $image, 0, 0, 0, 0, $new_width, $new_height, $image_width, $image_height);&lt;br /&gt;// kopiujemy, skalujemy&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($new_image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($new_image);&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyty do obrazków&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-_vPdWOGi3SE/VWZuWN21ZTI/AAAAAAAAIS4/uUffDm20VhM/s1600/r2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;528&quot; src=&quot;http://4.bp.blogspot.com/-_vPdWOGi3SE/VWZuWN21ZTI/AAAAAAAAIS4/uUffDm20VhM/s640/r2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widzimy - teraz dopiero zdjęcie zmniejszyło się o połowę do rozmiaru 380x180px.&lt;br /&gt;Należy zawsze o tym pamiętać - rozmiar wynikowego obrazka będzie zawsze rozmiaru zadeklarowanego podczas tworzenia uchwytu do niego!&lt;br /&gt;&lt;br /&gt;Spróbójmy teraz czegoś innego - spróbujmy powiększyć wybrany fragment zdjęcia. Jak tego dokonać? Załóżmy, że rozmiar zdjęcia wynikowego ma być taki sam jak zdjęcia oryginalnego, ale ma się w nim znaleźć powiększony fragment oryginału. Po pierwsze całą operację musimy zacząć od zadanego miejsca na obrazku źródłowym ustawiając startowe współrzędne X i Y. Po drugie - szerokość i wysokość zdjęcia podawana w funkcji imagecopyresized musi być odpowiednio większa i po trzecie - na zdjęciu wynikowym nakładamy skopiowanie zdjęcie od punktu (0, 0). Zobaczmy jak to zadziała w praktyce. Spróbujmy powiększyć oczy, czyli obszar mniej więcej od x=220, y=110. Powiększymy wszystko o 400% - wartość o ile razy powiększamy obraz określimy sobie w zmiennych $zoom_x i $zoom_y.&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;// wczytujemy zdjęcie do uchwytu&lt;br /&gt;&lt;br /&gt;$image_width = imagesx($image);&lt;br /&gt;$image_height = imagesy($image);&lt;br /&gt;// pobieramy rozmiar oryginalnego obrazu&lt;br /&gt;&lt;br /&gt;$zoom_x = 4;&lt;br /&gt;$zoom_y = 4;&lt;br /&gt;// o ile razy powiększamy zdjęcie&lt;br /&gt;&lt;br /&gt;$new_width = $image_width * $zoom_x;&lt;br /&gt;$new_height = $image_height * $zoom_y;&lt;br /&gt;// definiujemy rozmiar dla nowego obrazu&lt;br /&gt;&lt;br /&gt;$new_image = imagecreatetruecolor(760, 360);&lt;br /&gt;// tworzymy uchwyt dla nowego obrazu, pozostawiamy rozmiar oryginału&lt;br /&gt;&lt;br /&gt;imagecopyresized($new_image, $image, 0, 0, 220, 110, $new_width, $new_height, $image_width, $image_height);&lt;br /&gt;// kopiujemy, powiększamy&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($new_image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($new_image);&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyty do obrazków&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wynik:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-eNLjv8qa9i4/VWZubpd6vAI/AAAAAAAAITA/upwuXNeOkt4/s1600/r3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://3.bp.blogspot.com/-eNLjv8qa9i4/VWZubpd6vAI/AAAAAAAAITA/upwuXNeOkt4/s640/r3.jpg&quot; width=&quot;614&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageCopyResampled()&lt;/h2&gt;Identycznie do funkcji imagecopyresized() działa bliźniacza funkcja:&lt;br /&gt;[code]imagecopyresampled()[/code]&lt;br /&gt;Z tą jednak różnicą, iż w przypadku tej drugiej wartości pixeli są interpolowane, co może poprawić nieznacznie jakość wynikowego obrazu.&lt;br /&gt;Składnia tej funkcji jest identyczna jak funkcji imagecopyresized().&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageCopy()&lt;/h2&gt;Istnieje też zwykła funkcja ImageCopy(), która różni się tym, że - jak sama nazwa wskazuje - nie dokonuje przekształceń na rozmiarze, lecz jedynie kopiuje jeden obraz na drugi. Składnia jest podobna, nie występuje w niej jedynie podawanie argumentów dotyczących rozmiaru obrazu docelowego:&lt;br /&gt;&lt;br /&gt;[code]imagecopy($new_image, $source_image, $new_x, $new_y, $source_x, $source_y, &amp;nbsp;$source_width, $source_height);[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageRotate() - rotacja zdjęcia&lt;/h2&gt;Do obracania obrazu o zadany kąt służy funkcja:&lt;br /&gt;[code]$new_image = imagerotate($image, $angle, $bg_color)[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$angle &lt;/b&gt;- kąt o jaki obracamy&lt;/li&gt;&lt;li&gt;&lt;b&gt;$bg_color&lt;/b&gt; - kolor tła&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Powróćmy zatem do pierwotnej wersji naszej Angeliny i spróbujmy obrócić ją o kąt 90 stopni:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;&lt;br /&gt;$new_image = imagerotate($image, 90, 0);&lt;br /&gt;// obracamy Angelinę o 90 stopni w lewo&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($new_image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;imagedestroy($new_image);&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyty&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynik:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-BGlsRKvzkQE/VWZukx8NVsI/AAAAAAAAITI/VDrCIcWx1tE/s1600/rot1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://4.bp.blogspot.com/-BGlsRKvzkQE/VWZukx8NVsI/AAAAAAAAITI/VDrCIcWx1tE/s640/rot1.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Uwaga -&lt;/b&gt; obracanie działa przeciwnie do ruchu wskazówek zegara, czyli w lewo, aby obrócić w prawo - podajemy minusową wartość kąta.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Rysowanie po obrazie&lt;/h2&gt;Tak samo jak w przypadku obrazu utworzonego za pomocą funkcji imagecreatetruecolor() tak i w przypadku wczytanego pliku graficznego mamy do dyspozycji wszystkie związane z generowaniem grafiki funkcje. Żeby zobaczyć jak sprawdza się to w połączeniu z gotowym zdjęciem narysujmy naszej Angelinie okulary. Zrobimy to za pomocą funkcji rysującej elipsę, czyli:&lt;br /&gt;[code]imagefilledellipse()[/code]&lt;br /&gt;rysując dwie elipsy koloru czarnego, o średnicy 70px, następnie dodając wygenerowany tekstowy podpis na samym dole zdjęcia (koloru białego).&lt;br /&gt;Punkty centralne dla elips umieścimy odpowiednio w miejscach:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Elipsa 1: $cx1 = 290, $cxy = 160;&lt;/li&gt;&lt;li&gt;Elipsa 2: $cx2 = 390, $cy2 = 160;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Dodamy też dwie linie o następujących współrzędnych:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Linia 1: x1=325, y1=160, x2=355, y2=160&lt;/li&gt;&lt;li&gt;Linia 2: x1=425, y1=160, x2=460, y2=170&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;// wczytujemy zdjęcie do uchwytu&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocatealpha($image, 0, 0, 0, 20);&lt;br /&gt;// zdefiniowaliśmy kolor czarny&lt;br /&gt;&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;// zdefiniowaliśmy kolor biały&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, 290, 160, 70, 70, $black);&lt;br /&gt;// rusujemy prawy okular&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, 390, 160, 70, 70, $black);&lt;br /&gt;// rysujemy lewy okular&lt;br /&gt;&lt;br /&gt;imageline($image, 325, 160, 355, 160, $black);&lt;br /&gt;// rysujemy linię pomiędzy okularami&lt;br /&gt;&lt;br /&gt;imageline($image, 425, 160, 460, 170, $black);&lt;br /&gt;// rysujemy linię od lewego okulara do lewego ucha&lt;br /&gt;&lt;br /&gt;imagestring($image, 5, 25,340, &quot;photoshoped by GD2 :)&quot;, $white);&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyty do obrazków&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Oto wynik ;)&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/--UWVikNJp60/VWZurcNzi4I/AAAAAAAAITQ/gg1ty3a51u4/s1600/ps1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://2.bp.blogspot.com/--UWVikNJp60/VWZurcNzi4I/AAAAAAAAITQ/gg1ty3a51u4/s640/ps1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Wszystko poza samą Angeliną zostało tutaj wygenerowane za pomocą PHP.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageFilter() - filtry&lt;/h2&gt;Posłużymy się teraz naszym drugim zdjęciem i zobaczymy co oferują filtry w GD2.&lt;br /&gt;Dzięki filtrom zaaplikować możemy do zdjęcia kilka standardowych efektów, takich jak utworzenie z niego negatywu, czy desaturacja. Przyjrzyjmy się po krótce wszystkim dostępnym możliwościom, ale najpierw wczytajmy oryginalne zdjęcie:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;monica.jpg&#39;);&lt;br /&gt;// wczytujemy zdjęcie do uchwytu&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyty do obrazków&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-4dabtqdUXYo/VWZr1iOaFFI/AAAAAAAAISA/1cxddOXPPG4/s1600/monica.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://2.bp.blogspot.com/-4dabtqdUXYo/VWZr1iOaFFI/AAAAAAAAISA/1cxddOXPPG4/s640/monica.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Filtry nakładamy za pomocą funkcji:&lt;br /&gt;[code]imagefilter($image, $filter, $arg1, $arg2, $arg3, $arg4)[/code]&lt;br /&gt;gdzie&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$filter &lt;/b&gt;- rodzaj filtra&lt;/li&gt;&lt;li&gt;&lt;b&gt;$arg1-4&lt;/b&gt; - argumenty dla odpowiednich filtrów,&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;pełny opis tutaj: &lt;a href=&quot;http://php.net/manual/en/function.imagefilter.php&quot; target=&quot;_blank&quot;&gt;http://php.net/manual/en/function.imagefilter.php&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Na chwilę obecną dostępne mamy następujące rodzaje filtrów:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_NEGATE:&lt;/b&gt; tworzy negatyw z obrazu&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_GRAYSCALE:&lt;/b&gt; konwertuje obraz na odcienie szarości&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_BRIGHTNESS:&lt;/b&gt; Zmienia jasność obrazu (definiowana w $arg1)&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_CONTRAST:&lt;/b&gt; zmienia kontrast obrazu (definiowany w $arg1)&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_COLORIZE:&lt;/b&gt; kolorozyje obraz, wartości RGB podajemy odpowiednio w $arg1, $arg2, $arg3&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_EDGEDETECT:&lt;/b&gt; uwypukla krawędzie&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_EMBOSS:&lt;/b&gt; dodaje filtr embros, który &quot;uwypukla&quot; obraz&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_GAUSSIAN_BLUR:&lt;/b&gt; dodaje rozmycie metodą Gaussa&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_SELECTIVE_BLUR: &lt;/b&gt;rozmywa obraz&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_MEAN_REMOVAL:&lt;/b&gt; tworzy coś w rodzaju szkicu&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_SMOOTH:&lt;/b&gt; wygładza obraz, wartość wygładzenia podajemy w $arg1&lt;/li&gt;&lt;li&gt;&lt;b&gt;IMG_FILTER_PIXELATE:&lt;/b&gt; dodaje pixelizację, wartości podajemy w $arg1 i $arg2&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Przyjrzyjmy się pierwszemu filtrowi, czyli zróbmy sobie negatyw:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;monica.jpg&#39;);&lt;br /&gt;// wczytujemy zdjęcie do uchwytu&lt;br /&gt;&lt;br /&gt;imagefilter($image, IMG_FILTER_NEGATE);&lt;br /&gt;// aplikujemy filtr&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazu&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynik:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-KBv3ndOfWvU/VWZvAxaXOfI/AAAAAAAAITY/EXbPjmUgX2s/s1600/f1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-KBv3ndOfWvU/VWZvAxaXOfI/AAAAAAAAITY/EXbPjmUgX2s/s640/f1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I kolejne filtry:&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_GRAYSCALE);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-oFXR2736JqM/VWZvFs9CBiI/AAAAAAAAITg/6FCGeWNjMrE/s1600/f2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://2.bp.blogspot.com/-oFXR2736JqM/VWZvFs9CBiI/AAAAAAAAITg/6FCGeWNjMrE/s640/f2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_BRIGHTNESS, 130);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-jq11BPMwIF8/VWZvJ1BTiaI/AAAAAAAAITo/O5JnUaFxDI8/s1600/f3a.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.bp.blogspot.com/-jq11BPMwIF8/VWZvJ1BTiaI/AAAAAAAAITo/O5JnUaFxDI8/s640/f3a.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_BRIGHTNESS, -150);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-yuarHXkpuog/VWZvRE1DYeI/AAAAAAAAITw/cE7rMhgXc5E/s1600/f3b.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-yuarHXkpuog/VWZvRE1DYeI/AAAAAAAAITw/cE7rMhgXc5E/s640/f3b.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_CONTRAST, -50);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-KNoOPvClUYk/VWZvWUCqslI/AAAAAAAAIT4/rS5WMfa8i-w/s1600/f4a.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-KNoOPvClUYk/VWZvWUCqslI/AAAAAAAAIT4/rS5WMfa8i-w/s640/f4a.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_CONTRAST, 50);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/--vjjasVsENM/VWZvahqfD5I/AAAAAAAAIUA/OKhNmtxQ1EI/s1600/f4b.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://4.bp.blogspot.com/--vjjasVsENM/VWZvahqfD5I/AAAAAAAAIUA/OKhNmtxQ1EI/s640/f4b.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_COLORIZE, 255, 0, 0);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-KciAnQCw7kg/VWZvff6fKII/AAAAAAAAIUI/K8nwgp7nPaI/s1600/f5a.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://4.bp.blogspot.com/-KciAnQCw7kg/VWZvff6fKII/AAAAAAAAIUI/K8nwgp7nPaI/s640/f5a.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_COLORIZE, 0, 0, 128);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-WWh4mgvo7U8/VWZvj86vsOI/AAAAAAAAIUQ/EgBsA11QHAI/s1600/f5b.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.bp.blogspot.com/-WWh4mgvo7U8/VWZvj86vsOI/AAAAAAAAIUQ/EgBsA11QHAI/s640/f5b.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_EDGEDETECT);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-U30pGuKlVZ4/VWZvok36emI/AAAAAAAAIUY/ovZHdtbRARY/s1600/f6.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.bp.blogspot.com/-U30pGuKlVZ4/VWZvok36emI/AAAAAAAAIUY/ovZHdtbRARY/s640/f6.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_EMBOSS);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-0CzmK3RXARw/VWZvs5W-y2I/AAAAAAAAIUg/51oZGZQ-okQ/s1600/f7.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-0CzmK3RXARw/VWZvs5W-y2I/AAAAAAAAIUg/51oZGZQ-okQ/s640/f7.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-t0X-KWuQe7w/VWZvwnaavvI/AAAAAAAAIUo/sYSFW6ywUBQ/s1600/f8.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.bp.blogspot.com/-t0X-KWuQe7w/VWZvwnaavvI/AAAAAAAAIUo/sYSFW6ywUBQ/s640/f8.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_SELECTIVE_BLUR);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-b_QNaQ337S4/VWZv067XndI/AAAAAAAAIUw/CmQrFndIbNM/s1600/f9.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://1.bp.blogspot.com/-b_QNaQ337S4/VWZv067XndI/AAAAAAAAIUw/CmQrFndIbNM/s640/f9.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_MEAN_REMOVAL);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-E0T2OlQ7AmQ/VWZv6AeifJI/AAAAAAAAIU4/E8IB6xDIxjc/s1600/f10.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://2.bp.blogspot.com/-E0T2OlQ7AmQ/VWZv6AeifJI/AAAAAAAAIU4/E8IB6xDIxjc/s640/f10.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_SMOOTH, 8);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-f_scm0u0jJ8/VWZv-XRDCfI/AAAAAAAAIVA/6RVF3aKHHtE/s1600/f11.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://2.bp.blogspot.com/-f_scm0u0jJ8/VWZv-XRDCfI/AAAAAAAAIVA/6RVF3aKHHtE/s640/f11.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[code]imagefilter($image, IMG_FILTER_PIXELATE, 2, 8);[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-L5RBw2vjoIY/VWZwCbuTlUI/AAAAAAAAIVI/aVoOwH3qBEc/s1600/f12.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.bp.blogspot.com/-L5RBw2vjoIY/VWZwCbuTlUI/AAAAAAAAIVI/aVoOwH3qBEc/s640/f12.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać, biblioteka GD pozwala na całkiem przyzwoite efekty.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageMerge() - łączenie obrazków.&lt;/h2&gt;Pozostała nam do omówienia jeszcze jedna bardzo często wykorzystywana w GD2 kwestia, mianowicie łączenie ze sobą obrazków. Wyobraźmy sobie, że chcemy np. dodać graficzny znak wodny do danego zdjęcia, lub nałożyć jedno zdjęcie na drugie. Jak tego dokonać? Zacznijmy może prostego nałożenia jednego obrazka na drugi. Spróbujemy nałożyć obraz z Monicą Bellucci na obraz z Angeliną Jolie.&lt;br /&gt;&lt;br /&gt;Posłuży nam do tego funkcja:&lt;br /&gt;[code]imagecopymerge($image, $image_to_add, $image_x, $image_y, $image_to_add_x, $image_to_add_y, $image_to_add_width, $image_to_add_height, $opacity);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do bazowego obrazka (Angelina) - ten obrazek będzie pod spodem&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_to_add&lt;/b&gt; - &amp;nbsp;uchwyt do obrazu który będziemy nakładać (Monica) - ten obrazek nałożymy&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_x &lt;/b&gt;- &amp;nbsp;współrzędna X bazowego obrazka (Angelina) od której nakładany na nią drugi obraz (Monica)&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_y&lt;/b&gt; - współrzędna Y bazowego obrazka (Angelina) od której nakładany na nią drugi obraz (Monica)&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_to_add_x &lt;/b&gt;- &amp;nbsp;współrzędna X nakładanego obrazu od której zaczynamy nakładanie &amp;nbsp;(Monica)&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_to_add_y&lt;/b&gt; - &amp;nbsp;współrzędna Y nakładanego obrazu od której zaczynamy nakładanie &amp;nbsp;(Monica)&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_to_add_width &lt;/b&gt;- szerokosć nakładanego obrazka (Monica)&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_to_add_height &lt;/b&gt;- wysokość nakładaneg obrazka (Monica)&lt;/li&gt;&lt;li&gt;&lt;b&gt;$opacity&lt;/b&gt; - stopień przezroczystości nakładanego obrazka&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Najepiej zobaczmy to na przykładzie:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;$image_to_add = imagecreatefromjpeg(&#39;monica.jpg&#39;);&lt;br /&gt;&lt;br /&gt;$image_x = 15;&lt;br /&gt;// współrzędna X bazowego obrazka (Angelina) od której nakładany na nią drugi obraz (Monica)&lt;br /&gt;&lt;br /&gt;$image_y = 195;&lt;br /&gt;// współrzędna Y bazowego obrazka (Angelina) od której nakładany na nią drugi obraz (Monica)&lt;br /&gt;&lt;br /&gt;$image_to_add_x = &amp;nbsp;95;&lt;br /&gt;// współrzędna X nakładanego obrazu od której zaczynamy nakładanie &amp;nbsp;(Monica)&lt;br /&gt;&lt;br /&gt;$image_to_add_y = 75;&lt;br /&gt;// współrzędna Y nakładanego obrazu od której zaczynamy nakładanie &amp;nbsp;(Monica)&lt;br /&gt;&lt;br /&gt;$image_to_add_width = 150;&lt;br /&gt;// szerokosć nakładanego obrazka (Monica)&lt;br /&gt;&lt;br /&gt;$image_to_add_height = 150;&lt;br /&gt;// wysokość nakładaneg obrazka (Monica)&lt;br /&gt;&lt;br /&gt;$opacity = 80;&lt;br /&gt;// stopień przezroczystości nakładanego obrazka&lt;br /&gt;&lt;br /&gt;imagecopymerge($image, $image_to_add, $image_x, $image_y, $image_to_add_x, $image_to_add_y, $image_to_add_width, $image_to_add_height, 100);&lt;br /&gt;// nakładamy Monicę na Angelinę&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;imagedestroy($image_to_add);&lt;br /&gt;// zwalniamy uchwyty do obrazków&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Przeanalizujmy po koleji:&lt;br /&gt;Nakładać będziemy zdjęcie z Monicą.&lt;br /&gt;Nałożymy część jej zdjęcia, która zaczyna się od współrzędnych:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image_to_add_x&lt;/b&gt; = 95px&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_to_add_y&lt;/b&gt; = 75px&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Obszar nakładany będzie miał rozmiar:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image_to_add_width&lt;/b&gt; = 150px&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_to_add_height &lt;/b&gt;= 150px&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-yAVmf67cN5A/VWZwHPHG2VI/AAAAAAAAIVQ/VO1xp_GUtjM/s1600/merge1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.bp.blogspot.com/-yAVmf67cN5A/VWZwHPHG2VI/AAAAAAAAIVQ/VO1xp_GUtjM/s640/merge1.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Następnie wybrany obszar nakładać będziemy na zdjęcie Angeliny, począwszy od współrzędnych:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image_x&lt;/b&gt; = 15px;&lt;/li&gt;&lt;li&gt;&lt;b&gt;$image_y &lt;/b&gt;= 195px;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-uOduOOiJpM0/VWZwRTg87lI/AAAAAAAAIVY/u4AWsX_v-ho/s1600/merge2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://4.bp.blogspot.com/-uOduOOiJpM0/VWZwRTg87lI/AAAAAAAAIVY/u4AWsX_v-ho/s640/merge2.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Co w efekcie da nam takie oto zdjęcie:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-vy5GCpHc_dQ/VWZwV0PYyJI/AAAAAAAAIVg/hjxi4oO7Apo/s1600/merge3.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://4.bp.blogspot.com/-vy5GCpHc_dQ/VWZwV0PYyJI/AAAAAAAAIVg/hjxi4oO7Apo/s640/merge3.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Dodając trochę więcej przeźroczystości:&lt;br /&gt;[code]$opacity = 80[/code]&lt;br /&gt;otrzymamy natomiast coś w rodzaju znaku wodnego:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-O7X_9uFUC1Y/VWZwa-07ggI/AAAAAAAAIVo/yzFPNC2LW3o/s1600/merge4.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;http://3.bp.blogspot.com/-O7X_9uFUC1Y/VWZwa-07ggI/AAAAAAAAIVo/yzFPNC2LW3o/s640/merge4.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać nie jest to takie trudne.&lt;br /&gt;Została nam jeszcze jedna kwestia:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Zapis obrazu do pliku&lt;/h2&gt;Jak do tej pory generowaliśmy obraz bezpośrednio do przeglądarki, zobaczymy teraz w jaki sposób zapisać zdjęcie do pliku, a jest to bardzo proste i ogranicza się do podania jednego dodatkowego parametru, do którejś z poniższych funkcji:&lt;br /&gt;[code]imagepng($image, &quot;nazwa_pliku&quot;);[/code]&lt;br /&gt;[code]imagejpeg($image, &quot;nazwa_pliku&quot;);[/code]&lt;br /&gt;[code]imagegif($image, &quot;nazwa_pliku&quot;);[/code]&lt;br /&gt;[code]imagebmp($image, &quot;nazwa_pliku&quot;);[/code]&lt;br /&gt;&lt;br /&gt;Podanie jako drugi parametr nazwy pliku spowoduje zapis obrazu do pliku zamiast wyświetlenia go na ekran.&lt;br /&gt;Przetestujmy:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$image = imagecreatefromjpeg(&#39;angelina.jpg&#39;);&lt;br /&gt;&lt;br /&gt;if(imagepng($image, &quot;angelina2.png&quot;))&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; echo &#39;Image saved to file.&#39;;&lt;br /&gt;}&lt;br /&gt;// generujemy i zapisujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;Jak widzimy, wszystko to nie jest takie trudne jak może wydawać się na pierwszy rzut okna.&lt;br /&gt;Zachęcam ponownie do eksperymentowania we własnym zakresie.&lt;br /&gt;W następnych artykułach zajmiemy się czcionkami TrueType, pracą nad kolorami i gradientami oraz jeszcze kilkoma ciekawymi rzeczami.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/6962189171884698785/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/phpgd2-manipulacje-obrazami.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/6962189171884698785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/6962189171884698785'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/phpgd2-manipulacje-obrazami.html' title='[PHP][GD2] Manipulacje obrazami'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s72-c/icoPHP_GD.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-5828360592528357317</id><published>2015-05-27T21:48:00.002+02:00</published><updated>2015-05-28T20:18:17.706+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GD2"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><title type='text'>[PHP][GD2] Rysujemy podstawowe kształty</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Za pomocą biblioteki GD możemy nie tylko rysować prostokąty, lecz tworzyć o wiele bardziej złożone kształty, rysować linie, czy dodawać tekst. Wszystko sprowadza się do podania odpowiednich współrzędnych dla funkcji rysujących, a następnie wygenerowania danego kształtu i wypełnienia go odpowiednim kolorem. Warto poznać kilka podstawowych funkcji, takich jak rysowanie okręgów, czy elips, lub też prowadzenia linii z punku a do punktu. W tej krótkiej części przyjrzymy się najczęściej używanym, podstawowym funkcjom służącym do rysowania na obrazku standardowych kształtów. W &lt;a href=&quot;http://phpeverywhere.blogspot.com/2015/05/php-gd2-podstawy-generowania-grafiki.html&quot; target=&quot;_blank&quot;&gt;poprzedniej części,&lt;/a&gt; w podstawach narysowaliśmy prosty prostokąt, tym razem na początek narysujmy sobie elipsę. Wróćmy jednak jeszcze na moment do rysowania wypełnionego prostokąta z poprzedniej części. Użyliśmy tam funkcji:&lt;br /&gt;[code]imagefilledrectangle()[/code]&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;Z wypełnieniem i bez - filled&lt;/h2&gt;Warto wiedzieć, że funkcja ta (jak i jej podobne) posiada także swój odpowiednik rysujący taki sam prostokąt, ale bez wypełniania go kolorem. Funkcje rysujące bez wypełniania kolorem nie zawierają w nazwie &quot;filled&quot;, czyli z ang. wypełnienie.&lt;br /&gt;I tak, za pomocą funkcji:&lt;br /&gt;[code]imagerectangle()[/code]&lt;br /&gt;narysujemy sam obrys prostokąta, popatrzmy:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagerectangle($image, 20, 20, 100, 120, $red);&lt;br /&gt;// wypełniliśmy obszar od 20-100px w poziomie i 20-120px w pionie&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynikiem jest niewypełniony prostokąt, w tym przypadku wartość koloru została wykorzystana do określenia koloru obrysu.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-Hjum9uxyRCg/VWYc0oIoV-I/AAAAAAAAIQ0/iufNj9DbGPE/s1600/gd1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-Hjum9uxyRCg/VWYc0oIoV-I/AAAAAAAAIQ0/iufNj9DbGPE/s1600/gd1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Analogicznie będzie z wszystkimi pozostałymi funkcjami jakie tutaj poznamy - wszystkie one posiadają wersję wypełniające tło i niewypełniające go.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageFilledEllipse() - rysujemy elipsę&lt;/h2&gt;Narysujmy teraz elipsę, albo nawet dwie, lub trzy. Służy do tego funkcja:&lt;br /&gt;[code]imagefilledellipse($image, $cx, $cy, $width, $height, $color);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt naszego obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$cx&lt;/b&gt; = punkt środkowy elipsy w osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$cy&lt;/b&gt; = punkt środkowy elipsy w osi Y&lt;/li&gt;&lt;li&gt;&lt;b&gt;$width&lt;/b&gt; - szerokość elipsy&lt;/li&gt;&lt;li&gt;&lt;b&gt;$height&lt;/b&gt; - wysokość elipsy&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color&lt;/b&gt; - kolor wypełnienia&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Przygotujmy dodatkowe kolory, tym razem zielony i biały i narysujmy trzy elipsy, z czego elipsa zielona będzie o kształcie koła (taka sama szerokość i wysokość), a biała nie będzie posiadac wypełnienia:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;$green = imagecolorallocate($image, 0, 255, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $green&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, 200, 200, 100, 120, $red);&lt;br /&gt;// #1 rysujemy pierwszą elipsę (czerwoną), o środku w punkcie 200x200 i szerokości 100x120px&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, 300, 80, 100, 100, $green);&lt;br /&gt;// #2 rysujemy drugą elipsę (zieloną), o środku w punkcie 300x80 i szerokości 100x100px&lt;br /&gt;&lt;br /&gt;imageellipse($image, 50, 50, 40, 40, $white);&lt;br /&gt;// #3 rysujemy trzecią elipsę (białą), bez wypełnienia o środku w punkcie 50x50 i szerokości 40x40px&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Wynik:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-soaMP0Py5es/VWYc4xNpBaI/AAAAAAAAIQ8/vnA3BwFYDeY/s1600/gd2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-soaMP0Py5es/VWYc4xNpBaI/AAAAAAAAIQ8/vnA3BwFYDeY/s1600/gd2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Jak widać rysowanie elipsy jest zbliżone do rysowania prostokąta, z tym, że tutaj podajemy punkty środkowe i szerokość/wysokość zamiast współrzędnych początkowych i końcowych.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageLine() - rysujemy linie&lt;/h2&gt;Poprowadzimy teraz linię, którą rysuje się za pomocą następującej funkcji:&lt;br /&gt;[code]imageline($image, $x1, $y1, $x2, $y2, $color);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x1&lt;/b&gt; - punkt początkowy na osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y1&lt;/b&gt;- punkt początkowy na osi Y&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x2&lt;/b&gt; - punkt końcowy na osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y2&lt;/b&gt;- punkt końcowy na osi Y&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color&lt;/b&gt; - kolor linii&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Jak widać skadnia identyczna jak podczas rysowania prostokąta.&lt;br /&gt;&lt;br /&gt;Naszą linię poprowadźmy od środka czerwonej elipsy do środka elipsy zielonej, a więc podawając jako x1 i y1 współrzędne środka czerwonej elipsy, a jako x2 i y2 współrzędne środka elipsy zielonej.&lt;br /&gt;Nasza linia będzie niebieska, a więc utworzymy kolejny kolor, tym razem niebieski.&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;// zdefiniowaliśmy kolor biały i zapisaliśmy go do zmiennej $white&lt;br /&gt;&lt;br /&gt;$green = imagecolorallocate($image, 0, 255, 0);&lt;br /&gt;// zdefiniowaliśmy kolor zielony i zapisaliśmy go do zmiennej $green&lt;br /&gt;&lt;br /&gt;$blue = imagecolorallocate($image, 0, 0, 255);&lt;br /&gt;// zdefiniowaliśmy kolor niebieski zapisaliśmy go do zmiennej $blue&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, 200, 200, 100, 120, $red);&lt;br /&gt;// #1 rysujemy pierwszą elipsę (czerwoną), o środku w punkcie 200x200 i szerokości 100x120px&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, 300, 80, 100, 100, $green);&lt;br /&gt;// #2 rysujemy drugą elipsę (zieloną), o środku w punkcie 300x80 i szerokości 100x100px&lt;br /&gt;&lt;br /&gt;imageellipse($image, 50, 50, 40, 40, $white);&lt;br /&gt;// #3 rysujemy trzecią elipsę (białą), bez wypełnienia o środku w punkcie 50x50 i szerokości 40x40px&lt;br /&gt;&lt;br /&gt;imageline($image, 200, 200, 300, 80, $blue);&lt;br /&gt;// #4 rysujemy linię ze środka elipsy czerwonej (200, 200) do środka elipsy zielonej (300, 80)&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wynik:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-th7nApflRcs/VWYc_Y2YL_I/AAAAAAAAIRE/sD7OnlG_NdA/s1600/gd3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-th7nApflRcs/VWYc_Y2YL_I/AAAAAAAAIRE/sD7OnlG_NdA/s1600/gd3.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Prawda, że proste?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageFilledPolygon() - rysujemy poligony&lt;/h2&gt;Narysujmy teraz poligon. Tutaj jest ciekawa sprawa, ponieważ w tym przypadku możemy podać dowolną ilość punktów, a robimy to za pomocą tablicy. Popatrzmy jak wygląda składnia funkcji rysującej poligon złożony z dowolnej ilości punktów:&lt;br /&gt;[code]imagefilledpolygon($image, $tablica_współrzędnych_punktów, $ilość_punktów, $kolor)[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;br /&gt;&lt;b&gt;$tablica_współrzędnych_punktów&lt;/b&gt; - tablica ze wszystkimi współrzędnymi,np.&lt;br /&gt;[code]&lt;br /&gt;array(&lt;br /&gt;10, 10, //punkt pierwszy x, y&lt;br /&gt;10,30, //punkt drugi x, y&lt;br /&gt;30,80 &amp;nbsp;//punkt trzeci x, y&lt;br /&gt;)&lt;br /&gt;[/code]&lt;br /&gt;&lt;b&gt;$ilość_punktów&lt;/b&gt; - musi odpowiadać ilości punktów podanych w tablicy&lt;br /&gt;&lt;b&gt;$kolor&lt;/b&gt; - kolor wypełnienia&lt;br /&gt;&lt;br /&gt;Zrezygnujmy z naszej linii i narysujmy tym razem poligon składający się z trzech punktów, które będą środkami naszych wszystkich trzech okręgów.&lt;br /&gt;Żeby tym razem się nie powtarzać z wartościami, współrzędne dla okręgów (i naszego poligonu) określimy sobie w zmiennych $cx1, $cx2...itd&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;// współrzędne środków okręgów:&lt;br /&gt;$cx1 = 200; // czerwony X&lt;br /&gt;$cy1 = 200; // czerwony Y&lt;br /&gt;&lt;br /&gt;$cx2 = 300; // zielony X&lt;br /&gt;$cy2 = 80; //&amp;nbsp;zielony&amp;nbsp;Y&lt;br /&gt;&lt;br /&gt;$cx3 = 50; // biały X&lt;br /&gt;$cy3 = 50; // biały Y&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// punkty dla poligonu:&lt;br /&gt;$polygon_points = array(&lt;br /&gt;$cx1, $cy1,&lt;br /&gt;$cx2, $cy2,&lt;br /&gt;$cx3, $cy3&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;// zdefiniowaliśmy kolor biały i zapisaliśmy go do zmiennej $white&lt;br /&gt;&lt;br /&gt;$green = imagecolorallocate($image, 0, 255, 0);&lt;br /&gt;// zdefiniowaliśmy kolor zielony i zapisaliśmy go do zmiennej $green&lt;br /&gt;&lt;br /&gt;$blue = imagecolorallocate($image, 0, 0, 255);&lt;br /&gt;// zdefiniowaliśmy kolor niebieski zapisaliśmy go do zmiennej $blue&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, $cx1, $cy1, 100, 120, $red);&lt;br /&gt;// #1 rysujemy pierwszą elipsę (czerwoną), o środku w punkcie 200x200 i szerokości 100x120px&lt;br /&gt;&lt;br /&gt;imagefilledellipse($image, $cx2, $cy2, 100, 100, $green);&lt;br /&gt;// #2 rysujemy drugą elipsę (zieloną), o środku w punkcie 300x80 i szerokości 100x100px&lt;br /&gt;&lt;br /&gt;imageellipse($image, $cx3, $cy3, 40, 40, $white);&lt;br /&gt;// #3 rysujemy trzecią elipsę (białą), bez wypełnienia o środku w punkcie 50x50 i szerokości 40x40px&lt;br /&gt;&lt;br /&gt;imagefilledpolygon($image, $polygon_points, 3, $blue);&lt;br /&gt;// rysujemy polygon z tzrech punktów&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Oto wynik naszego działania:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-cyNcSwZsAhE/VWYdDIEvsVI/AAAAAAAAIRM/cnQxlPG4Jsw/s1600/gd4-polygon.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-cyNcSwZsAhE/VWYdDIEvsVI/AAAAAAAAIRM/cnQxlPG4Jsw/s1600/gd4-polygon.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Prawda, że proste?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;ImageFilledArc() - rysujemy wypełnienie kołowe&lt;/h2&gt;Narysujmy teraz coś bardziej skomplikowanego - wypełnienie kątowe.&lt;br /&gt;Stworzy nam to cząstkę okręgu opartą na zadanych kącie, co jest przydatne w generowaniu wykresów kołowych.&lt;br /&gt;Funkcja do tego służąca to:&lt;br /&gt;[code]imagefilledarc($image, $cx, $cy, $width, $height, $start_angle, $end_angle, $color, $styl);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt naszego obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$cx &lt;/b&gt;= punkt środkowy elipsy w osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$cy&lt;/b&gt; = punkt środkowy elipsy w osi Y&lt;/li&gt;&lt;li&gt;&lt;b&gt;$width&lt;/b&gt; - szerokość elipsy&lt;/li&gt;&lt;li&gt;&lt;b&gt;$height&lt;/b&gt; - wysokość elipsy&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;$start_angle&lt;/b&gt; - kąt początkowy (w stopniach)&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;$end_angle&lt;/b&gt; - kąt końcowy (w stopniach)&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color &lt;/b&gt;- kolor wypełnienia&lt;/li&gt;&lt;li&gt;&lt;b&gt;$styl&lt;/b&gt; - określa sposób łączenia punktu początkowego z końcowym, możliwe parametry:&lt;br /&gt;&lt;b&gt;IMG_ARC_PIE&lt;/b&gt; - łączenie kołowe&lt;br /&gt;&lt;b&gt;IMG_ARC_CHORD&lt;/b&gt; - łączenie linią prostą&lt;br /&gt;&lt;b&gt;IMG_ARC_NOFILL&lt;/b&gt; - bez wypełnienia&lt;br /&gt;&lt;b&gt;IMG_ARC_EDGED&lt;/b&gt; - daje jedynie obrys całości.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Zrezygnujemy teraz z naszych elips i w ich miejsce narysujemy sobie nasze &quot;arców&quot;&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;// współrzędne środków okręgów:&lt;br /&gt;$cx1 = 200; // czerwony X&lt;br /&gt;$cy1 = 200; // czerwony Y&lt;br /&gt;&lt;br /&gt;$cx2 = 300; //&amp;nbsp;zielony&amp;nbsp;X&lt;br /&gt;$cy2 = 80; //&amp;nbsp;zielony&amp;nbsp;Y&lt;br /&gt;&lt;br /&gt;$cx3 = 50; // biały X&lt;br /&gt;$cy3 = 50; // biały Y&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;// zdefiniowaliśmy kolor biały i zapisaliśmy go do zmiennej $white&lt;br /&gt;&lt;br /&gt;$green = imagecolorallocate($image, 0, 255, 0);&lt;br /&gt;// zdefiniowaliśmy kolor zielony i zapisaliśmy go do zmiennej $green&lt;br /&gt;&lt;br /&gt;$blue = imagecolorallocate($image, 0, 0, 255);&lt;br /&gt;// zdefiniowaliśmy kolor niebieski zapisaliśmy go do zmiennej $blue&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagefilledarc($image, $cx1, $cy1, 100, 120, 0, 180, $red, IMG_ARC_PIE);&lt;br /&gt;// #1 rysujemy wypełnienie koła (czerwone), o środku w punkcie 200x200 i szerokości 100x120px, zaczynając od kąta 0, do kąta 180&lt;br /&gt;&lt;br /&gt;imagefilledarc($image, $cx2, $cy2, 100, 100, 0, 90, $green, IMG_ARC_CHORD);&lt;br /&gt;// #2 rysujemy wypełnienie koła (zielone), o środku w punkcie 300x80 i szerokości 100x100px, zaczynając od kąta 0, do kąta 90&lt;br /&gt;&lt;br /&gt;imagearc($image, $cx3, $cy3, 40, 40, 45, 70, $white);&lt;br /&gt;// #3 rysujemy koło (białe), bez wypełnienia, o środku w punkcie 50x50 i szerokości 40x40px, zaczynając od kąta 45, do kąta 70&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wynik:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-y6BzakYekF4/VWYdILcbZNI/AAAAAAAAIRU/2AeHZaejqJ8/s1600/gd5-arc.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-y6BzakYekF4/VWYdILcbZNI/AAAAAAAAIRU/2AeHZaejqJ8/s1600/gd5-arc.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2&gt;ImageChar() - dołączamy znak&lt;/h2&gt;Ostatnią rzeczą jaką omówimy w tym artykule jest rysowanie tekstu. Narazie wykonamy to prostą metodą, a w następnych artykułach nauczymy się wykorzystywac do tego zewnętrzne czcionki TrueType.&lt;br /&gt;Pojedyńczy znak na obrazku generujemy za pomocą funkcji:&lt;br /&gt;[code]imagechar($image, $font_size, $x, $y, $char, $color);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$font_size&lt;/b&gt; - rozmiar czcionki od 1 do 5&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x &lt;/b&gt;- współrzędna na osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y &lt;/b&gt;- współrzędna na osi Y&lt;/li&gt;&lt;li&gt;&lt;b&gt;$char&lt;/b&gt; - znak do napisania na obrazku&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color &lt;/b&gt;- kolor czcionki&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Za pomocą funkcji:&lt;br /&gt;[code]imagecharup($image, $font_size, $x, $y, $char, $color);[/code]&lt;br /&gt;dokonamy tego samego, tyle że w pionie.&lt;br /&gt;&lt;br /&gt;Przetestujmy jak to działa:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;// zdefiniowaliśmy kolor biały i zapisaliśmy go do zmiennej $white&lt;br /&gt;&lt;br /&gt;$green = imagecolorallocate($image, 0, 255, 0);&lt;br /&gt;// zdefiniowaliśmy kolor zielony i zapisaliśmy go do zmiennej $green&lt;br /&gt;&lt;br /&gt;$blue = imagecolorallocate($image, 0, 0, 255);&lt;br /&gt;// zdefiniowaliśmy kolor niebieski zapisaliśmy go do zmiennej $blue&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagechar($image, 5, 10, 10, &quot;P&quot;, $red);&lt;br /&gt;imagechar($image, 5, 50, 50, &quot;H&quot;, $green);&lt;br /&gt;imagechar($image, 5, 100, 100, &quot;P&quot;, $blue);&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynik:&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-qI-HNR-KueY/VWYdM6Fw2aI/AAAAAAAAIRc/2L86fpCYDvo/s1600/gs6-php.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-qI-HNR-KueY/VWYdM6Fw2aI/AAAAAAAAIRc/2L86fpCYDvo/s1600/gs6-php.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2&gt;ImageString() - dołączamy tekst&lt;/h2&gt;A teraz to samo, ale nie z pojedyńczym znakiem, ale z całym stringiem, służy do tego funkcja:&lt;br /&gt;[code]imagestring($image, $font_size, $x, $y, $string, $color);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$image&lt;/b&gt; - uchwyt do obrazka&lt;/li&gt;&lt;li&gt;&lt;b&gt;$font_size&lt;/b&gt; - rozmiar czcionki od 1 do 5&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x&lt;/b&gt; - współrzędna na osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y&lt;/b&gt; - współrzędna na osi Y&lt;/li&gt;&lt;li&gt;&lt;b&gt;$string&lt;/b&gt; - ciąg znaków do napisania na obrazku&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color&lt;/b&gt; - kolor czcionki&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Sprawdżmy w praktyce:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;$white = imagecolorallocate($image, 255, 255, 255);&lt;br /&gt;// zdefiniowaliśmy kolor biały i zapisaliśmy go do zmiennej $white&lt;br /&gt;&lt;br /&gt;$green = imagecolorallocate($image, 0, 255, 0);&lt;br /&gt;// zdefiniowaliśmy kolor zielony i zapisaliśmy go do zmiennej $green&lt;br /&gt;&lt;br /&gt;$blue = imagecolorallocate($image, 0, 0, 255);&lt;br /&gt;// zdefiniowaliśmy kolor niebieski zapisaliśmy go do zmiennej $blue&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagestring($image, 2, 10, 10, &quot;PHP&quot;, $red);&lt;br /&gt;imagestring($image, 3, 50, 50, &quot;EVERYWHERE&quot;, $green);&lt;br /&gt;imagestring($image, 5, 100, 100, &quot;BLOG&quot;, $blue);&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Wynik:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-xFAp3iCowCU/VWYdPf-qbjI/AAAAAAAAIRk/onjM4srPh4Q/s1600/gd7-every.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-xFAp3iCowCU/VWYdPf-qbjI/AAAAAAAAIRk/onjM4srPh4Q/s1600/gd7-every.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Jak widać korzystanie z wszystkich tych funkcji jest bardzo proste i ogranicza się do poznania ich składni. Funkcji tych jest bardzo dużo, polecam zajrzeć do manuala, który znajduje się tutaj:&lt;br /&gt;&lt;a href=&quot;http://php.net/manual/en/ref.image.php&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://php.net/manual/en/ref.image.php&lt;/a&gt;&lt;br /&gt;W następnych artykułach nauczymy się operacji na obrazkach - wczytywania obrazka z pliku, obracania go, skalowania, aplikowania filtrów i zapisywania na dysk, a także wielu innych rzeczy.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/5828360592528357317/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-rysujemy-podstawowe-ksztaty.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5828360592528357317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5828360592528357317'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-rysujemy-podstawowe-ksztaty.html' title='[PHP][GD2] Rysujemy podstawowe kształty'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s72-c/icoPHP_GD.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-5540378502607286314</id><published>2015-05-27T19:33:00.001+02:00</published><updated>2015-05-28T14:11:35.166+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GD2"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><title type='text'>[PHP][GD2] Podstawy generowania grafiki</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s1600/icoPHP_GD.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Biblioteka GD2 wbudowana w PHP to bardzo rozbudowane narzędzie, pozwalające na generowanie właściwie każdego rodzaju grafiki bitmapowej. Dzięki niej możemy generować grafikę bezpośrednio z poziomu PHP, co za tym idzie również manipulować istniejącą grafiką zapisaną w plikach takich jak JPEG, PNG, czy BMP, a więc tworzyć różnego rodzaju miniaturki, skalować i obracać zdjęcia, nakładać &quot;w locie&quot; filtry, znaki wodne, bądź napisy z zewnętrznych czcionek TrueType. Biblioteka ta nadaje się również świetnie do generowania wszelkiego rodzaju graficznych wykresów reprezentujących dane pobrane bezpośrednio z PHP. Wygenerowane grafiki możemy następnie wyświetlać bezpośrednio do przeglądarki, albo zapisywać do plików. W artykule tym nauczymy się podstawowej zasady działania biblioteki i dowiemy się w jaki sposób wykorzystywać ją w kodzie.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;1. ImageCreateTrueColor() - tworzymy pusty obrazek&lt;/h2&gt;Pierwszą podstawową rzeczą podczas pracy z GD2 jest stworzenie uchwytu do obrazka. Każda zabawa z GD2 rozpoczyna się od tego. Będziemy operować na pełnej palecie barw, więc nasz obrazek będziemy tworzyć za pomocą funkcji:&lt;br /&gt;[code]$image = imagecreatetruecolor(szerokość_obrazka, wysokość_obrazka)[/code]&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;Jak widać za jedyne argumenty pobiera ona wysokość oraz szerokość generowanego przez nas obrazu. Stwórzmy nasz pierwszy obrazek:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Obrazek nasz zapisaliśmy do zmiennej $image, na której to zmiennej będziemy następnie dokonywać wszystkich zwiazanych z nim operacji. Mamy więc pusty obrazek, który jednak narazie jest jedynie zasobem w pamięci operacyjnej serwera, nic tutaj narazie się nam jeszcze na ekranie nie wyświetli.&lt;br /&gt;Na początek dodajmy mu trochę koloru, wypełnijmy go całego np. kolorem czerwonym.&lt;br /&gt;&lt;br /&gt;Do stworzenia obrazu o zwykłej palecie barw służy natomiast funkcja:&lt;br /&gt;[code]$image = imagecreate(szerokość_obrazka, wysokość_obrazka)[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2. ImageCollorAllocate() - definiujemy kolor&lt;/h2&gt;Wartość danego koloru musimy najpierw zdefiniować za pomocą funkcji:&lt;br /&gt;[code]$color = imagecolorallocate($image, R, G, B)[/code]&lt;br /&gt;gdzie jako pierwszy parametr podajemy uchwyt do utworzonego wcześniej obrazka, a następnie kolejno wartości RGB tworzonego koloru (z zakresu 0-255).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2.5. ImageCollorAllocateAlpha() - definiujemy kolor z alphą&lt;/h2&gt;Możemy także stworzyć kolor z wartością kanału alpha, a więc z przezroczystością, używamy do tego funkcji:&lt;br /&gt;[code]$color = imagecolorallocatealpha($image, R, G, B, Alpha)[/code]&lt;br /&gt;gdzie jako dodatkowy parametr podajemy wartość kanału alpha (z zakresu 0-127)&lt;br /&gt;&lt;br /&gt;My chcemy stworzyć kolor czerwony, wywołamy więc funkcję z następującymi argumentami, przy czym zapiszemy sobie nasz kolor do zmiennej $red:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;3. ImageFill() - wypełniamy obrazek&lt;/h2&gt;Mamy już zdefiniowaną wartość koloru, czas aby wypełnić nasz obrazek tym właśnie kolorem, służy do tego funkcja:&lt;br /&gt;[code]imagefill($image, $x, $y, $color)[/code]&lt;br /&gt;gdzie jako pierwszy argument podajemy uchwyt do obrazka, następnie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$x&lt;/b&gt; - punkt początkowy w osi X od którego zaczynamy wypełnianie kolorem&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y&lt;/b&gt; - punkt początkowy w osi Y od którego zaczynamy wypełnianie kolorem&lt;/li&gt;&lt;li&gt;&lt;b&gt;$color&lt;/b&gt; - wartość koloru wypełnienia utworzona uprzednio za pomocą imagecollorallocate()&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;My chcemy wypełnić cały obrazek, a więc cały obszar o wielkości 400x300px, jako początkowe współrzędne podamy więc wartości zerowe, a kolorem jakim wypełniamy będzie nasz czerwony:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $red);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $red&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;4. ImagePNG - wyświetlamy obrazek&lt;/h2&gt;Dla sprawdzenia wyniku wyświetlmy teraz obrazek bezpośrednio w przeglądarce.&lt;br /&gt;Służy do tego kilka funkcji, w zależności od tego jakiego typu obrazek chcemy wyrzucić na ekran:&lt;br /&gt;[code]&lt;br /&gt;imagepng($image); - wyświetla nasz obrazek w formacie PNG&lt;br /&gt;imagejpeg($image); - wyświetla nasz obrazek w formacie JPEG&lt;br /&gt;imagebmp($image); - wyświetla nasz obrazek w formacie Windows BMP&lt;br /&gt;imagegif($image); - wyświetla nasz obrazek w formacie GIF&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Aby jednak wyświetlić obrazek, musimy najpierw wysłać do przeglądarki nagłówek informujący o typie naszego obrazu. Dokonujemy tego za pomocą ustawienia odpowiedniego Mime-Type:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;PNG&lt;/b&gt; - &amp;nbsp;image/png&lt;/li&gt;&lt;li&gt;&lt;b&gt;JPEG&lt;/b&gt; - image/jpeg&lt;/li&gt;&lt;li&gt;&lt;b&gt;BMP&lt;/b&gt; - &amp;nbsp;image/bmp&lt;/li&gt;&lt;li&gt;&lt;b&gt;GIF &lt;/b&gt;- image/gif&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Wyświetlmy nasz obrazek jako PNG:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $red);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $red&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;W tym momencie powinien nam się wyświetlić piękny czerwony prostokąt o wymiarach 400x300px (wymiary na obrazku dodałem oddzielnie, wy zobaczycie jedynie czerwony prostokąt):&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-RM4U-hwxC0k/VWX8HiEaUDI/AAAAAAAAIQE/GlRp5C1e0bc/s1600/gd1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-RM4U-hwxC0k/VWX8HiEaUDI/AAAAAAAAIQE/GlRp5C1e0bc/s1600/gd1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Pamiętajmy, że po wygenerowaniu grafiki zwalniamy zasób za pomocą:&lt;br /&gt;[code]imagedestroy($image);[/code]&lt;br /&gt;&lt;br /&gt;Warto też tutaj przyjrzeć się funkcji:&lt;br /&gt;[code]imagefill()[/code]&lt;br /&gt;Otóż - niezależnie jakie w tym momencie podamy koordynaty x i y, to obrazek zostanie wypełniony danym kolorem w całości.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;5. ImageFilledRectangle()&lt;/h2&gt;Aby wypełnić jedynie zadany przez nas prostokątkny obszar, musimy skorzystać z funkcji:&lt;br /&gt;[code]imagefilledrectangle($image, $x1, $y1, $x2, $y2, $red);[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$x1&lt;/b&gt; - punkt początkowy na osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y1&lt;/b&gt;- punkt początkowy na osi Y&lt;/li&gt;&lt;li&gt;&lt;b&gt;$x2&lt;/b&gt; - punkt końcowy na osi X&lt;/li&gt;&lt;li&gt;&lt;b&gt;$y2&lt;/b&gt;- punkt końcowy na osi Y&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Wypełnijmy teraz więc jedynie jakąś część obrazka:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocate($image, 255, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagefilledrectangle($image, 20, 20, 100, 120, $red);&lt;br /&gt;// wypełniliśmy obszar od 20-100px w poziomie i 20-120px w pionie&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Warto zauważyć, iż x2 i y2 nie oznaczają szerokości i wysokości wypełnienia lecz współrzędne na obrazku:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-g0hpCfSL3rg/VWX8QetDtOI/AAAAAAAAIQM/JTtoYnZGzYc/s1600/gd2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-g0hpCfSL3rg/VWX8QetDtOI/AAAAAAAAIQM/JTtoYnZGzYc/s1600/gd2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Współrzędne liczymy zawsze od lewego górnego rogu obrazka, który posiada współrzędną (0, 0).&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;6. Kanał alpha&lt;/h2&gt;Jak teraz utworzyć obrazek z kanałem alpha?&lt;br /&gt;Po pierwsze musimy zdefiniować nasz kolor z takim właśnie kanałem. Robimy to za pomocą funkcji:&lt;br /&gt;[code]$color = imagecolorallocatealpha($image, R, G, B, Alpha)[/code]&lt;br /&gt;gdzie kanał alpha może przyjąć wartości od 0(całkowicie nieprzezroczysty) do 127 (całkowicie przezroczysty)&lt;br /&gt;&lt;br /&gt;Stwórzmy więc nasz kolor czerwony, tak aby był w połowie przeźroczysty (wartość alpha - 64):&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocate($image, 0, 0, 0);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocatealpha($image, 255, 0, 0, 64);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red, tym razem z kanałem alpha&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagefilledrectangle($image, 20, 20, 100, 120, $red);&lt;br /&gt;// wypełniliśmy obszar od 20-100px w poziomie i 20-120px w pionie&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wynik:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-pQE6PfTJZ58/VWX8WKfhB5I/AAAAAAAAIQU/gxe6ENzF4V0/s1600/gd3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-pQE6PfTJZ58/VWX8WKfhB5I/AAAAAAAAIQU/gxe6ENzF4V0/s1600/gd3.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Jak widać, czerwony prostokąt troche nam przyciemniał, gdyż jest na wpół przezroczysty.&lt;br /&gt;Cały obrazek jednak jako taki jest wciąż całkowicie nieprzeźroczysty. Jak teraz sprawić, aby nasz PNG jako całość uzyskał przezroczystość? Na logikę może się wydawać, że dałoby radę zrobić to za pomocą:&lt;br /&gt;[code]$black = imagecolorallocatealpha($image, 0, 0, 0, 100);[/code]&lt;br /&gt;dla tła.&lt;br /&gt;&lt;br /&gt;To jednak nie pomoże. Zobaczmy:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-565IqxXMdo4/VWX8b3vAlWI/AAAAAAAAIQc/eXRNYtBpJsE/s1600/gd4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-565IqxXMdo4/VWX8b3vAlWI/AAAAAAAAIQc/eXRNYtBpJsE/s1600/gd4.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Obrazek nie jest przezroczysty pomimo podania w kolorze tła kanału alpha.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;7. ImageSaveAlpha()&lt;/h2&gt;Dlaczego nie udało się nam uzyskać przezroczystości dla całego obrazka?&lt;br /&gt;Ponieważ obrazek jako taki nie ma zapisanego w sobie kanału alpha, musimy to uczynić funkcją:&lt;br /&gt;[code]imagesavealpha($image, true);[/code]&lt;br /&gt;Nasz kod wyglądać więc będzie tak:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$width = 400;&lt;br /&gt;$height = 300;&lt;br /&gt;$image = imagecreatetruecolor($width, $height);&lt;br /&gt;// stworzyliśmy pusty obrazek o szerokości 400px i wysokości 300px&lt;br /&gt;&lt;br /&gt;$black = imagecolorallocatealpha($image, 0, 0, 0, 100);&lt;br /&gt;// zdefiniowaliśmy kolor czarny dla tła, z kanałem alpha = 100&lt;br /&gt;&lt;br /&gt;$red = imagecolorallocatealpha($image, 255, 0, 0, 64);&lt;br /&gt;// zdefiniowaliśmy kolor czerwony i zapisaliśmy go do zmiennej $red, z kanałem alpha = 64&lt;br /&gt;&lt;br /&gt;imagefill($image, 0, 0, $black);&lt;br /&gt;// wypełniliśmy obszar 400x300px naszego obrazka kolorem pobranym ze zmiennej $black&lt;br /&gt;&lt;br /&gt;imagefilledrectangle($image, 20, 20, 100, 120, $red);&lt;br /&gt;// wypełniliśmy obszar od 20-100px w poziomie i 20-120px w pionie&lt;br /&gt;&lt;br /&gt;header(&quot;Content-type: image/png&quot;);&lt;br /&gt;// definiujemy nagłówek z mimetype&lt;br /&gt;&lt;br /&gt;imagesavealpha($image, true);&lt;br /&gt;// zapisujemy kanał ALPHA w obrazku&lt;br /&gt;&lt;br /&gt;imagepng($image);&lt;br /&gt;// generujemy obrazek PNG&lt;br /&gt;&lt;br /&gt;imagedestroy($image);&lt;br /&gt;// zwalniamy uchwyt do obrazka&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wynik:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-eIjgCifjQcM/VWX8iIu7Q5I/AAAAAAAAIQk/W9KQFFKtBY0/s1600/gd5.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-eIjgCifjQcM/VWX8iIu7Q5I/AAAAAAAAIQk/W9KQFFKtBY0/s1600/gd5.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Jak widać, tym razem obrazek wyświetli się nam w całości jako półprzezroczysty.&lt;br /&gt;To tyle na początek, wiemy już mniej więcej jak działa bibioteka GD, w następnych artykułach poznamy następne jej funkcje i sposoby wykorzystania. W ramach ćwiczeń polecam poeksperymentowanie z udostępnionym tutaj kodem, zmieniając np. współrzędne i kolory, a następnie potestowanie wyników takich zmian.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/5540378502607286314/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-podstawy-generowania-grafiki.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5540378502607286314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5540378502607286314'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-gd2-podstawy-generowania-grafiki.html' title='[PHP][GD2] Podstawy generowania grafiki'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-ABOvALjlmoA/VWD0q3wWTvI/AAAAAAAAH88/TSwbbeSnPU4/s72-c/icoPHP_GD.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-2147216564926567225</id><published>2015-05-27T17:10:00.003+02:00</published><updated>2015-05-28T14:00:26.815+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP5"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP_zaawansowane"/><title type='text'>[PHP] Funkcje anonimowe i callback</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-QLaNhRpjR38/VWD0pbQxHQI/AAAAAAAAH8c/eR32_BuZO8I/s1600/icoPHP_ADVANCED.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-QLaNhRpjR38/VWD0pbQxHQI/AAAAAAAAH8c/eR32_BuZO8I/s1600/icoPHP_ADVANCED.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Funkcje anonimowe i związane z nimi funkcje zwrotne (tzw. callback) to bardzo praktyczny mechanizm pozwalający na tworzenie bardzo ciekawych rozwiązań. Są wykorzystywane w wielu funkcjach wbudowanych w PHP, możemy też je wykorzystywać do budowania własnych tego typu rozwiązań. Trzeba bowiem wiedzieć, że jako argumenty do danej funkcji możemy w PHP przekazywać nie tylko zwykłe typy takie jak obiekty klas, zmienne, czy tablice, ale również i funkcje. Co więcej - funkcje podane jako argument mogą operować na danych zwróconych przez funkcję wywoływaną - nazywamy je wtedy funkcjami zwrotnymi, tzw. callbackami. Oczywiście nic nie stoi na przeszkodzie, aby wszystko działało o wiele bardziej skomplikowanie - funkcja zwrotna może np. odbierać wynik, przetwarzać go, a następnie ponownie przekazywać do funkcji bazowej. W tym artykule dowiemy się w jaki sposób w PHP można deklarować tego typu funkcje oraz zobaczymy na przykładzie w jaki praktyczny sposób można to rozwiązanie wykorzystać.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;function()&lt;/h2&gt;Funkcja anonimowa może zostać zadeklarowana na dwa sposoby, na początek poznamy pierwszy sposób. Nie musi ona posiadać swojej nazwy, można ją jednak przypisać do zmiennej i używać zmiennej tak jakby była zwykłą funkcją.&lt;br /&gt;Składnia taka moze powodować zdziwienie na pierwszy rzut oka, ale po zrozumieniu mechanizmu nie będzie w niej dla nas niczego dziwnego. Zdeklarujmy więc naszą pierwszą anonimową funkcję, przypisując ją do zmiennej:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;$myFunction = function() { &lt;br /&gt;&amp;nbsp; echo &#39;This is myFunction.&amp;lt;br /&amp;gt;&#39;; &lt;br /&gt;};&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;Jak widać powyżej, funkcja taka nie posiada własnej nazwy, jest za to przypisywana do zmiennej $myFunction.&lt;br /&gt;Co za tym idzie, wywołajmy teraz taki kod:&lt;br /&gt;[code]$myFunction(); [/code]&lt;br /&gt;Dziwna konstrukcja? Na pierwszy rzut oka być może tak, bo wygląda jak połączenie zmiennej z funkcją.&lt;br /&gt;Tak też jest w istocie. Wywołanie powyższego nie spowoduje żadnego błędu i wyświetli nam wynik działania funkcji zadeklarowanej wyżej, czyli:&lt;br /&gt;[code]This is myFunction.[/code]&lt;br /&gt;&lt;br /&gt;Wyobraźmy sobie teraz, że mamy dodatkową funkcję przyjmującą jeden argument, np.:&lt;br /&gt;[code]&lt;br /&gt;function otherFunction($arg)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; // ....ciało funkcji&lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Co zostanie do niej przekazane, gdy wywołamy ją podając za argument zmienną $myFunction?&lt;br /&gt;[code]otherFunction($myFunction);[/code]&lt;br /&gt;Otóż - przekazana w argumencie zostanie nasza anonimowa funkcja.&lt;br /&gt;Funkcję przekazaną możemy następnie wywołać w ciele funkcji do której została przekazana i zrobić z nią co tylko chcemy.&lt;br /&gt;&lt;br /&gt;Funkcje anonimowe mogą naturalnie przyjmować argumenty, rozbudujmy zatem naszą anonimową funkcję o pobieranie dwóch liczbowych argumentów, następnie w wyniku wyświetlanie ich sumy:&lt;br /&gt;[code]&lt;br /&gt;$myFunction = function($a, $b) { &lt;br /&gt;&amp;nbsp; $c = $a + b;&lt;br /&gt;&amp;nbsp; echo &#39;This is myFunction:&amp;lt;br /&amp;gt;&#39; .&lt;br /&gt;&amp;nbsp; $a . &#39;+&#39; . $b . &#39;=&#39; . $c . &#39;&amp;lt;br /&amp;gt;&#39;; &lt;br /&gt;};&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wywołanie teraz:&lt;br /&gt;[code]$myFunction(5, 2);[/code]&lt;br /&gt;&lt;br /&gt;Spowoduje wywołanie funkcji i wyświetlenie nam:&lt;br /&gt;[code]This is myFunction:&lt;br /&gt;5+2=7[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;call_user_func()&lt;/h2&gt;Funkcje anonimowe (jak i zwykłe funkcje) wywoływać można za pomocą funkcji:&lt;br /&gt;[code]call_user_func(nazwa_funkcji, argument1, argument2, ....);[/code]&lt;br /&gt;&lt;br /&gt;Przykładowo:&lt;br /&gt;[code]call_user_func($myFunction, 5, 2);[/code]&lt;br /&gt;Wywoła nam funkcję anonimową przypisaną do zmiennej $myFunction z argumentami 5 i 2, co finalnie wyświetli nam wynik tak jak powyżej. W przykładzie tym podaliśmy zmienną zamiast nazwy funkcji, zwykłe wywołanie za pomocą podania jej nazwy jako stringu wyglądało by np. tak:&lt;br /&gt;[code]&lt;br /&gt;$html = &#39;&amp;lt;b&amp;gt;this is html&amp;lt;/b&amp;gt;&#39;;&lt;br /&gt;$no_tags = call_user_func(&#39;strip_tags&#39;, $html);&lt;br /&gt;echo $no_tags;&lt;br /&gt;[/code]&lt;br /&gt;Co w wyniku wywoła nam funkcję strip_tags() z argumentem $html.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;call_user_func_array()&lt;/h2&gt;Argumenty do call_user_func można podawać również w formie tablicy, ale zrobimy to już funkcją:&lt;br /&gt;[code]call_user_func_array(nazwa_funkcji, tablica_z_argumentami)[/code]&lt;br /&gt;Przykład:&lt;br /&gt;[code]&lt;br /&gt;$str = &#39;color is black&#39;;&lt;br /&gt;$a = &#39;black&#39;;&lt;br /&gt;$b = &#39;white&#39;;&lt;br /&gt;$replace = call_user_func_array(&#39;str_replace&#39;, array($a, $b, $str));&lt;br /&gt;echo $replace;&lt;br /&gt;[/code]&lt;br /&gt;Wyświetli nam:&lt;br /&gt;[code]color is white[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;call_user_func i klasy&lt;/h2&gt;Przeanalizowaliśmy prosty przykład z funkcjami, jak jednak za pomocą call_user_func() wywołać metody klasy.&lt;br /&gt;Rozwiązań jest kilka, utwórzmy najpierw przykładową klasę:&lt;br /&gt;[code]&lt;br /&gt;class MyClass&lt;br /&gt;{ &lt;br /&gt;&amp;nbsp; public function myMethod()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; echo &#39;This is myMethod from object. &amp;lt;br /&amp;gt;&#39;; &amp;nbsp; &lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public static function myStaticMethod()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; echo &#39;This is myStaticMethod. &amp;lt;br /&amp;gt;&#39;; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; } &lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Aby wywołać statyczną metodę myStaticMethod(), użyć musimy jednej z dwóch konstrukcji:&lt;br /&gt;[code]call_user_func(&#39;MyClass&#39;, &#39;myStaticMethod&#39;);[/code]&lt;br /&gt;lub bezpośrednio:&lt;br /&gt;[code]call_user_func(&#39;MyClass::myStaticMethod&#39;);[/code]&lt;br /&gt;&lt;br /&gt;W przypadku obiektu klasy i metody myMethod() zrobimy to tak:&lt;br /&gt;[code]$obj = new MyClass;&lt;br /&gt;call_user_func($obj, &#39;myMethod&#39;);[/code]&lt;br /&gt;&lt;br /&gt;Możemy też odwoływać się np. do metody rodzica w klasie bazowej.&lt;br /&gt;Utwórzmy dwie klasy, z czego druga dziedziczy po pierwszej:&lt;br /&gt;[code]&lt;br /&gt;class MyClassA&lt;br /&gt;{ &amp;nbsp; &lt;br /&gt;&amp;nbsp; public static function who()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; echo &#39;My class is: &#39; . __CLASS__ . &#39;&amp;lt;br /&amp;gt;&#39;; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class MyClassB extends MyClassA&lt;br /&gt;{ &amp;nbsp; &lt;br /&gt;&amp;nbsp; public static function who()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; echo &#39;My class is: &#39; . __CLASS__ . &#39;&amp;lt;br /&amp;gt;&#39;; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;&amp;nbsp; } &lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Aby teraz z poziomu klasy B wywołać metodę klasy bazowej A użyjemy konstrukcji:&lt;br /&gt;[code]call_user_func(array(&#39;MyClassB&#39;, &#39;parent::who&#39;));[/code]&lt;br /&gt;co wyświetli nam:&lt;br /&gt;[code]My class is: MyClassA[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;CALLBACK&lt;/h2&gt;Wiemy już w jaki sposób wywoływać funkcje anonimowe (i zwykłe), więc zobaczmy teraz jak wykorzystać tą wiedzę do stworzenia callbacka. Na początek wymyślmy sobie jakąś funkcję, która będzie przyjmować funkcję anonimową jako callback i zwracać jej wynik swojego działania. Niech będzie to przykładowo funkcja obliczający pierwiastek kwadratowy z podanej jako argument liczby.&lt;br /&gt;Funkcja obliczająca pierwiastek kwadratowy to:&lt;br /&gt;[code]sqrt()[/code]&lt;br /&gt;My jednak chcemy stworzyć bardziej rozbudowaną wersję, która nie tylko zwróci nam wynik, ale przekaże go do zdefiniowanej przez nas funkcji, którą podamy jako parametr. Na początek obmyślmy co taka funkcja zrobi z takim wynikiem - niech będzie, że po prostu go wyświetli.&lt;br /&gt;Nasza funkcja callbackowa wyglądać więc będzie tak:&lt;br /&gt;[code]&lt;br /&gt;function myCallback($input)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; echo &#39;My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;; &lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Jak widać jest to prosta funkcja - przyjmuje wynik w argumencie i wyświetla go za pomocą echo().&lt;br /&gt;Argument $input zostanie jej przekazany przez naszą funkcję bazową, w której obliczymy pierwiastek, stwórzmy więc i tą funkcję:&lt;br /&gt;[code]&lt;br /&gt;function sqrtWithCallback($number, callable $callback)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $res = sqrt($number); &lt;br /&gt;&amp;nbsp; if(is_callable($callback))&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; call_user_func($callback, $res);&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Jak widzimy funkcja przyjmuje 2 argumenty:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;$number&lt;/b&gt; - który pobiera liczbę, z której obliczać będziemy pierwiastek&lt;/li&gt;&lt;li&gt;&lt;b&gt;$callback&lt;/b&gt; - funkcję zwrotną, której przekaże obliczony pierwiastek.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Co się dzieje dalej?&lt;/b&gt;&lt;br /&gt;Pierwiastek jest obliczany i zapisywany w zmiennej $res.&lt;br /&gt;Następnie mamy warunek, który wymaga omówienia:&lt;br /&gt;Funkcja:&lt;br /&gt;[code]is_callable(nazwa_funkcji)[/code]&lt;br /&gt;sprawdza, czy podana jako argument nazwa funkcji jest w rzeczywistości funkcją, którą możemy wywołać za pomocą call_user_func(). Od strony technicznej - sprawdza, czy podana jako parametr funkcja jest typu callable/callback. Typy callback i callable oznaczają to samo, z tym że callable został wprowadzony dopiero w wersji 5.4 PHP.&lt;br /&gt;Następnie, o ile funkcja istnieje jest ona wywoływana za pomocą call_user_func() z argumentem, w którym przekazywany jest jej wynik jaki obliczyliśmy.&lt;br /&gt;&lt;br /&gt;Zobaczmy co się stanie po wywołaniu naszej funkcji:&lt;br /&gt;[code]&lt;br /&gt;$my_number = 16;&lt;br /&gt;sqrtWithCallback($my_number, &#39;myCallback&#39;);&lt;br /&gt;[/code]&lt;br /&gt;Voila! Zostanie nam wyświetlone:&lt;br /&gt;[code]My result is: 4[/code]&lt;br /&gt;&lt;br /&gt;Funkcja zwrotna (callback) odebrała od funkcji bazowej wynik jej działania, następnie przetworzyła go po swojemu, wyświetlając nam wynik. Zmieńmy naszą funkcję obliczającą pierwiastek na trochę bardziej elegancką:&lt;br /&gt;[code]&lt;br /&gt;function sqrtWithCallback($number, callable $callback)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $res = sqrt($number); &lt;br /&gt;&amp;nbsp; if(!is_callable($callback) || !call_user_func($callback, $res)) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return false;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&amp;nbsp; return $res; &lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Będzie działać tak samo, ale jednocześnie zwracac nam wynik w przypadku powodzenia, lub false w przypadku niemożliwości wywołania funkcji zwrotnej.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;CALLBACK I KLASY&lt;/h2&gt;A jakim sposobem przesłać tutaj jako callback nie funkcję, a np. metodę klasy?&lt;br /&gt;Bardzo podobnie jak w przypadku call_user_func(). Utwórzmy najpierw przykładową klasę:&lt;br /&gt;[code]&lt;br /&gt;class MyCallbacks {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public static function sqrtCallback($input)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;echo &#39;My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function sqrtCallbackObj($input)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;echo &#39;My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;}&lt;br /&gt;[/code]&lt;br /&gt;Następnie jako callback podajmy nazwę statycznej metody:&lt;br /&gt;[code]&lt;br /&gt;$my_number = 16;&lt;br /&gt;$sqrt = sqrtWithCallback($my_number, &#39;MyCallbacks::sqrtCallback&#39;);&lt;br /&gt;[/code]&lt;br /&gt;Voila! Tym razem jako callback posłużyła nam metoda statyczna klasy MyCallbacks.&lt;br /&gt;&lt;br /&gt;Analogicznie z utworzeniem obiektu klasy:&lt;br /&gt;[code]&lt;br /&gt;$obj = new MyCallbacks;&lt;br /&gt;$sqrt = sqrtWithCallback($my_number, array($obj, &#39;sqrtCallbackObj&#39;));&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;CALLBACK I FUNKCJE ANONIMOWE&lt;/h2&gt;Dochodzimy więc do senda tego artykułu, a więc możliwości połączenia funkcji anonimowych z callbackiem.&lt;br /&gt;W przykładzie powyżej podaliśmy jako callback zwykłą funkcję, zadeklarowaną normalnie, teraz zobaczmy jak podać tutaj funkcję anonimową. Można to zrobić na kilka sposobów. Na początek zadeklarujmy sobie taką anonimową funkcję:&lt;br /&gt;[code]&lt;br /&gt;$callback_func = function($input)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; echo &#39;My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;; &lt;br /&gt;};&lt;br /&gt;[/code]&lt;br /&gt;Wywołajmy teraz funkcję bazową:&lt;br /&gt;[code]&lt;br /&gt;$my_number = 16;&lt;br /&gt;sqrtWithCallback($my_number, $callback_func);&lt;br /&gt;[/code]&lt;br /&gt;Bingo! Ponownie otrzymalismy wynik z naszej funkcji zwrotnej, tym razem anonimowej, ale zadeklarowanej do zmiennej.&lt;br /&gt;&lt;br /&gt;Prawdziwa jednak siła funkcji anonimowych tkwi w możliwości ich definiowania bezpośrednio w argumencie, popatrzmy:&lt;br /&gt;[code]&lt;br /&gt;$my_number = 16;&lt;br /&gt;$sqrt = sqrtWithCallback($my_number, function($input) {&lt;br /&gt;&amp;nbsp; &amp;nbsp;echo &#39;My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;; &amp;nbsp; &lt;br /&gt;});&lt;br /&gt;[/code]&lt;br /&gt;Jak widzimy - deklarację naszej anonimowej funkcji podajemy bezpośrednio w argumencie funkcji ją przyjmującej.&lt;br /&gt;Takiego też sposobu używać będziemy najczęściej, gdyż jest najbardziej ergonomiczny.&lt;br /&gt;Warto to sobie przećwiczyć na własnych przykładach, gdyż zastosowań tego typu mechanizmu jest ogrom.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Więcej o funkcjach anonimowych i callbackach przeczytasz w manualu PHP:&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;http://php.net/manual/en/function.call-user-func.php&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://php.net/manual/en/function.call-user-func.php&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://php.net/manual/en/function.call-user-func-array.php&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://php.net/manual/en/function.call-user-func-array.php&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://php.net/manual/en/function.is-callable.php&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://php.net/manual/en/function.is-callable.php&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://php.net/manual/en/language.types.callable.php&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://php.net/manual/en/language.types.callable.php&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://php.net/manual/en/language.pseudo-types.php#language.types.callback&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://php.net/manual/en/language.pseudo-types.php#language.types.callback&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Na sam koniec jeszcze kod, który pokaże nam wszystkie sposoby działające po koleji:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// #1 - przypiszemy anonimową funkcje do zmennej $callback_func&lt;br /&gt;$callback_func = function($input)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; echo &#39;#1: My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;; &lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// #2 - &amp;nbsp;normalna funkcja&lt;br /&gt;function myCallback($input)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; echo &#39;#2: My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// #3 i #4 - metody w klasie&lt;br /&gt;class MyCallbacks {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function sqrtCallbackObj($input)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;echo &#39;#3: My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public static function sqrtCallback($input)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;echo &#39;#4: My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;;&lt;br /&gt;&amp;nbsp; } &amp;nbsp; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// nasza funkcja przekazująca wynik do callbacka&lt;br /&gt;function sqrtWithCallback($number, callable $callback)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; $res = sqrt($number); &lt;br /&gt;&amp;nbsp; if(!is_callable($callback) || !call_user_func($callback, $res)) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return false;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&amp;nbsp; return $res; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;$my_number = 16;&lt;br /&gt;&lt;br /&gt;// #1 wywołanie za pomocą zmiennej zawierającej funkcję:&lt;br /&gt;$sqrt = sqrtWithCallback($my_number, $callback);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// #2 wywołanie za pomocą podania nazwy funkcji:&lt;br /&gt;$sqrt = sqrtWithCallback($my_number, &#39;myCallback&#39;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// #3 metoda obiektu klasy MyCallbacks:&lt;br /&gt;$obj = new MyCallbacks;&lt;br /&gt;$sqrt = sqrtWithCallback($my_number,array($obj, &#39;sqrtCallbackObj&#39;));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// #4 metoda statyczna w klasie MyCallbacks:&lt;br /&gt;$sqrt = sqrtWithCallback($my_number, &#39;MyCallbacks::sqrtCallback&#39;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// #5 funkcja anonimowa z deklaracją w parametrze:&lt;br /&gt;$sqrt = sqrtWithCallback($my_number, function($input) {&lt;br /&gt;&amp;nbsp; &amp;nbsp;echo &#39;#5: My result is: &#39; . $input . &#39;&amp;lt;br /&amp;gt;&#39;; &amp;nbsp; &lt;br /&gt;});&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/2147216564926567225/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-funkcje-anonimowe-i-callback.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/2147216564926567225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/2147216564926567225'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-funkcje-anonimowe-i-callback.html' title='[PHP] Funkcje anonimowe i callback'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-QLaNhRpjR38/VWD0pbQxHQI/AAAAAAAAH8c/eR32_BuZO8I/s72-c/icoPHP_ADVANCED.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-4301031849970711205</id><published>2015-05-26T23:22:00.001+02:00</published><updated>2015-05-28T16:33:23.645+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2"/><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2_auth"/><title type='text'>[APACHE] Konfiguracja HTTPS na localhoście - zabawa z OpenSSL</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-fapetHXGMOY/VWD0g9yOtCI/AAAAAAAAH6g/66iVAOJbPIw/s1600/apache_auth.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-fapetHXGMOY/VWD0g9yOtCI/AAAAAAAAH6g/66iVAOJbPIw/s1600/apache_auth.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;W artykule tym nauczymy się jak na lokalnym serwerze stworzyć możliwości do obsługi protokołu https://. Pozwoli to nam na lokalne testowanie tych elementów naszej aplikacji, które w wersji produkcyjnej będą działać na połączeniu szyfrowanym. Do stworzenia sobie takiej funkcjonalności potrzebny będzie nam certyfikat SSL, którym konieczne będzie podpisanie naszego serwera. Certyfikaty takie kosztują i są wydawane dla konkretnej domeny przez uprawnione do tego organy, jak np. VeriSign. My oczywiście nie będziemy kupować żadnego certfikatu dla własnych lokalnych potrzeb - zamiast tego skorzystamy z darmowego pakietu OpenSSL i taki certyfikat wygenerujemy oraz podpiszemy sobie sami. Wiąże się to z pewną małą &quot;niedogodnością&quot; - mianowicie przeglądarki będą pluły nam informacją o tym, iż nasz certfikat jest niezaufany i z niepewnych źródeł ;) Wystarczy jednak to zignorować.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;OpenSSL&lt;/h2&gt;No to zaczynamy. Pierwszą sprawą jest zaopatrzenie się w darmowy pakiet OpenSSL, który pobierzemy stąd: &lt;a href=&quot;http://indy.fulgan.com/SSL/&quot;&gt;http://indy.fulgan.com/SSL/&lt;/a&gt;. Na Linuxach pakiet ten powinien być dostępny domyślnie, dla Windowsów musimy go pobrać, zróbmy więc to. Wchodzimy na w/w stronę, pobieramy najnowszą dostępną wersję odpowiednią dla naszego systemu (32/64 bity) i rozpakowujemy, np. do:&lt;br /&gt;[code]C:\OpenSSL[/code]&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;To jedna sprawa - druga to włączenie modułu SSL w samym Apache&#39;u (jest on domyślnie wyłaczony). Otwieramy do edycji plik konfiguracyjny Apache&#39;a (jako administrator):&lt;br /&gt;[code]/ścieżka/do/apache/conf/httpd.conf[/code]&lt;br /&gt;i szukamy linijki:&lt;br /&gt;[code]LoadModule ssl_module modules/mod_ssl.so[/code]&lt;br /&gt;Jeśli jest ona poprzedzona komentarzem (#) to usuwamy go.&lt;br /&gt;Zapiszmy plik i zrestartujmy Apache:&lt;br /&gt;[code]httpd -k restart[/code]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Uwaga&lt;/b&gt; - jeśli nie posiadamy modułu &quot;mod_ssl.so&quot; to bedziemy musieli go do naszego Apacha &lt;a href=&quot;http://www.modssl.org/&quot; target=&quot;_blank&quot;&gt;doinstalować&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Klucz i certyfikat&lt;/h2&gt;Wróćmy do pobranego przez nas pakietu OpenSSL.&lt;br /&gt;Czeka nas wygenerowanie nowego certyfikatu.&lt;br /&gt;Służy do tego narzędzie openssl, a jakże ;)&lt;br /&gt;Na początku stworzymy sobie folder na nasz certyfikat i klucz, np.&lt;br /&gt;[code]C:\certSSL[/code]&lt;br /&gt;Uruchomijmy zatem terminal/konsolę (UWAGA: koniecznie jako administrator), a następnie stwórzmy powyższy folder i wejdżmy do niego:&lt;br /&gt;[code]mkdir C:\certSSL&lt;br /&gt;cd C:\certSSL[/code]&lt;br /&gt;&lt;br /&gt;Wpiszmy teraz w konsoli:&lt;br /&gt;[code]openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout localhost.key -out localhost.cert[/code]&lt;br /&gt;&lt;br /&gt;Rozpocznie się procedura generowania klucza.&lt;br /&gt;Zostaniemy poproszeni o podanie danych takich jak kod naszego kraju, nazwa organizacji itd.&lt;br /&gt;Wpiszmy tam jakieś podstawowe dane - zostaną one wpisane do certyfikatu.&lt;br /&gt;Ważne jest jednak pole Common Name, określające adres strony dla jakiej wystawiamy certyfikat.&lt;br /&gt;Jeśli wystawiamy dla naszego localhosta to wpiszmy tam:&lt;br /&gt;[code]localhost[/code]&lt;br /&gt;&lt;br /&gt;Jeśli wszystko poszło dobrze to powinniśmy w folderze C:\certSSL otrzymać 3 pliki:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;.rnd&lt;/li&gt;&lt;li&gt;localhost.cert&lt;/li&gt;&lt;li&gt;localhost.key&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Plik .rnd usuwamy.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Interesują nas 2 pozostałe pliki:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;localhost.cert &lt;/b&gt;- czyli nasz certfikat&lt;/li&gt;&lt;li&gt;&lt;b&gt;localhost.key&lt;/b&gt; - nasz wygenerowany klucz prywatny&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Instalacja klucza i certyfikatu&lt;/h2&gt;Oba pliki kopiujemy do katalogu z konfiguracją Apache&#39;a:&lt;br /&gt;[code]/ścieżka/do/apache/conf/ssl[/code]&lt;br /&gt;(katalog ssl tworzymy sami)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;VHOST&lt;/h2&gt;Następnie będziemy musieli stworzyć nowego vhosta (więcej o tworzeniu vhostów napisałem w&lt;a href=&quot;http://www.phpeverywhere.blogspot.com/2015/05/apache-jak-stworzyc-i-skonfigurowac-wirtualnego-hosta.html&quot; target=&quot;_blank&quot;&gt; tym artykule&lt;/a&gt;). Wchodzimy zatem do pliku z konfiguracją vhostów, najczęściej jest to:&lt;br /&gt;[code]/ścieżka/do/apache/conf/extra/httpd-vhosts.conf[/code]&lt;br /&gt;&lt;br /&gt;i dodajemy nowego wirtualnego hosta, np:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;VirtualHost *:443&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAdmin nasz@email.com&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &quot;c:/www&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerName localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAlias localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; SSLEngine On&lt;br /&gt;&amp;nbsp; &amp;nbsp; SSLCertificateFile conf/ssl/localhost.cert&lt;br /&gt;&amp;nbsp; &amp;nbsp; SSLCertificateKeyFile conf/ssl/localhost.key&lt;br /&gt;&amp;nbsp; &amp;nbsp; ErrorLog &quot;logs/localhost-ssl-error.log&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; CustomLog &quot;logs/localhost-ssl-access.log&quot; common&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Jak widzimy w konfiguracji - połączeń po SSL nasłuchiwać będziemy na porcie 443&lt;br /&gt;DocumentRoot pozostaje bez zmian, ale możemy tutaj podać oddzielny katalog na zawartość przesyłaną po https://.&lt;br /&gt;To co najbardziej rzuca się w oczy, to:&lt;br /&gt;[code]&lt;br /&gt;SSLEngine On&lt;br /&gt;SSLCertificateFile conf/ssl/localhost.cert&lt;br /&gt;SSLCertificateKeyFile conf/ssl/localhost.key&lt;br /&gt;[/code]&lt;br /&gt;To właśnie tutaj uruchamiamy SSL dla tego vhosta oraz definiujemy ścieżki do certfyfikatu i klucza.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;httpd.conf&lt;/h2&gt;Vhosta już mamy, ale to jeszcze nie wszystko, gdyż teraz w zależności od obecnej konfiguracji naszego Apache&#39;a dalsza procedura moze być różna. Najlepiej wyszukajmy w pliku httpd.conf wszystkie wystąpienia słowa &#39;SSL&#39; i przyjrzyjmy się jakie elementy odnośnie SSL są implementowane.&lt;br /&gt;Kluczowym jest, abyśmy dodali w konfiguracji następujący wpis:&lt;br /&gt;[code]&lt;br /&gt;Listen 443&lt;br /&gt;&amp;lt;IfModule ssl_module&amp;gt;&lt;br /&gt;SSLRandomSeed startup builtin&lt;br /&gt;SSLRandomSeed connect builtin&lt;br /&gt;&amp;lt;/IfModule&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Pierwsza linijka nakazuje Apachowi nasłuchiwania na porcie 443 - bez niej nasz serwer nie przyjmie żadnego połaczenia po protokole HTTPS.&lt;br /&gt;Kolejne parametry definiują rodzaj generowanego ziarna za pomocą liczb losowych.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;https://&lt;/h2&gt;Jeśli wszystko poszło zgodnie z planem, to zrestartujmy serwer i spróbujmy dostać się do naszego localhosta za pomocą:&lt;br /&gt;&lt;br /&gt;[code]https://localhost[/code]&lt;br /&gt;&lt;br /&gt;Jeśli wszystko poszło jak należy, pominniśmy zostać na wstępie poinformowani o niepewnym pochodzeniu naszego certyfikatu, samo zaś połączenie po SSL powinno w tym momencie działać.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/4301031849970711205/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-konfiguracja-https-na.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/4301031849970711205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/4301031849970711205'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-konfiguracja-https-na.html' title='[APACHE] Konfiguracja HTTPS na localhoście - zabawa z OpenSSL'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-fapetHXGMOY/VWD0g9yOtCI/AAAAAAAAH6g/66iVAOJbPIw/s72-c/apache_auth.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-461398784422923059</id><published>2015-05-26T20:52:00.000+02:00</published><updated>2015-05-28T16:33:04.623+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2"/><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2_auth"/><title type='text'>[APACHE] Autoryzacja za pomocą .htpasswd</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-fapetHXGMOY/VWD0g9yOtCI/AAAAAAAAH6g/66iVAOJbPIw/s1600/apache_auth.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-fapetHXGMOY/VWD0g9yOtCI/AAAAAAAAH6g/66iVAOJbPIw/s1600/apache_auth.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;W Apache&#39;u możemy ograniczyć dostęp do dowolnego katalogu za pomocą ustawienia wymogu autoryzacji. Jest to bardzo przydatna opcja, dzięki której możemy ograniczyć dostęp np. do testowych wersji projektów dla swoich klientów na zasadzie konieczności podania loginu oraz hasła użytkownika. Jest to prosta autoryzacja oparta na dwóch plikach, które w tym artykule przygotujemy - pliku .htpasswd, w którym będziemy przechowywać nasze hasła, oraz pliku .htaccess, który będzie z tego pliku korzystał w celu autoryzacji użytkownika. O ile plik .htaccess utworzymy w zwykłym notatniku, to już z plikiem .htpasswd będzie więcej zachodu, gdyż tego pliku nie jesteśmy w stanie przygotować &quot;odręcznie&quot;. Wynika to z faktu, iż hasła przechowywane w tym pliku zapisywane są w formie szyfrowanej, zatem skorzystać będziemy musieli z jakiegoś narzędzia generującego nasze hasła w formie zaszyfrowanej.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;.htpasswd&lt;/h2&gt;Pierwszym i podstawowym narzędziem służacym do generowania pliku z hasłami jest udostępnione w pakiecie z serwerem Apache konsolowe narzędzie o nazwie:&lt;br /&gt;[code]htpasswd.exe[/code]&lt;br /&gt;Innym sposobem na utworzenie pliku z hasłami jest skorzystanie z któregoś z dostępnych on-line generatorów.&lt;br /&gt;Oto ich krótka lista:&lt;br /&gt;&lt;a href=&quot;http://www.htaccesstools.com/htpasswd-generator/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.htaccesstools.com/htpasswd-generator/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://www.askapache.com/online-tools/htpasswd-generator/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.askapache.com/online-tools/htpasswd-generator/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://aspirine.org/htpasswd_en.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://aspirine.org/htpasswd_en.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://www.htpasswdgenerator.net/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.htpasswdgenerator.net/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Jak wygląda taki plik z hasłami?&lt;br /&gt;Jest to zwykły plik tekstowy o postaci:&lt;br /&gt;[code]login1:hasło1&lt;br /&gt;login2:hasło2&lt;br /&gt;login3:hasło3&lt;br /&gt;...itd&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;np.:&lt;br /&gt;[code]&lt;br /&gt;marek:$apr1$mFL7znbn$cQMJYoAf5gSXw0d2GAGNx.&lt;br /&gt;anna:$apr1$ggN.pSSf$Dld5WOZkHlPP03g534R0X/&lt;br /&gt;janusz:$apr1$GCpfbZ26$omnuEq040nxzQlYkYum.j.&lt;br /&gt;...itd&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Użytkowników może być dowolna ilość, należy jednak pamiętać, aby każdy z nich określony był w oddzielnej linijce, na zasadzie:&lt;br /&gt;[code]nazwa_użytkownika1:hasło_użytkownika1&lt;br /&gt;nazwa_użytkownika2:hasło_użytkownika2&lt;br /&gt;nazwa_użytkownika3:hasło_użytkownika3[/code]&lt;br /&gt;&lt;br /&gt;Skorzystamy teraz z wbudowanego w Apache narzędzia, aby wygenerować nasz plik z hasłami.&lt;br /&gt;Na początek mała uwaga - plik z hasłami przechowujemy w folderze niedostępnym z zewnątrz.&lt;br /&gt;Stwórzmy sobie jakiś wydzielony folder, np.:&lt;br /&gt;[code]C:\top_secret[/code]&lt;br /&gt;w Windowsie&lt;br /&gt;&lt;br /&gt;lub&lt;br /&gt;[code]/home/użytkownik/top_secret[/code]&lt;br /&gt;na Linuxie&lt;br /&gt;&lt;br /&gt;i tam zapisujmy hasła.&lt;br /&gt;Ważne jest jedynie, aby folder nie był dostępny z poziomu WWW.&lt;br /&gt;&lt;br /&gt;Składnia poleceń narzędzia htpasswd.exe wygląda następująco:&lt;br /&gt;[code]htpasswd.exe -parametr &quot;/ŚCIEŻKA/DO/PLIKU/Z/HASŁAMI&quot; nazwa_użytkownika[/code]&lt;br /&gt;&lt;br /&gt;Utwórzmy więc np. użytkownika o nazwie &quot;janusz&quot; i dowolnym haśle.&lt;br /&gt;Narzędzie pracuje w terminalu, wejdźmy więc do terminalu/konsoli i wpiszmy:&lt;br /&gt;[code]htpasswd.exe -c &quot;C:\top_secret\.htpasswd&quot; janusz[/code]&lt;br /&gt;Wciśnijmy ENTER, podajmy dwukrotnie hasło i to wszystko - plik został wygenerowany.&lt;br /&gt;&lt;br /&gt;O ile wszystko wykonaliśmy poprawnie, plik C:\top_secret\.htpasswd powinień wyglądać jakoś tak:&lt;br /&gt;[code]janusz:$apr1$R0L9yuuR$5yFjvKY5zzjcimetH3l.L.[/code]&lt;br /&gt;&lt;br /&gt;Kolejnego użytkownika do tego pliku dodamy tak samo, ale pominiemy teraz parametr -c (skrót od CREATE). Dodajmy kolejnego użytkownika np. o nazwie &quot;anna&quot; i dowolnym haśle:&lt;br /&gt;[code]htpasswd.exe &quot;C:\top_secret\.htpasswd&quot; anna[/code]&lt;br /&gt;&lt;br /&gt;Nasz plik ma już dwóch użytkowników:&lt;br /&gt;[code]&lt;br /&gt;janusz:$apr1$zEw590ap$o9OvCKEbofz5v2SFE9SQJ0&lt;br /&gt;anna:$apr1$AQA3qYnC$z32ZOrJNJWExBL6Y0BKIl0&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;.htaccess&lt;/h2&gt;Teraz czas na zabawę z plikiem .htaccess.&lt;br /&gt;Załóżmy, że na naszym serwerze posiadamy katalog:&lt;br /&gt;[code]C:\WWW\top_secret_area[/code]&lt;br /&gt;który chcemy zabezpieczyć hasłem.&lt;br /&gt;&lt;br /&gt;Utwórzmy w nim plik .htaccess i wpiszmy do niego to co poniższe:&lt;br /&gt;[code]&lt;br /&gt;AuthType basic&lt;br /&gt;AuthName &quot;Top Secret Area&quot;&lt;br /&gt;AuthUserFile C:/top_secret/.htpasswd&lt;br /&gt;Require valid-user&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Zapiszmy plik.&lt;br /&gt;Teraz po koleji co tak naprawdę zrobiliśmy:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AuthType - określa sposób autoryzacji, może to być basic, lub digest, my wykorzystamy basic&lt;/li&gt;&lt;li&gt;AuthName - to nazwa wyświetlana po wejściu do chronionego zasobu, może być dowolna&lt;/li&gt;&lt;li&gt;AuthUserFile - podajemy pełną ścieżkę do pliku z hasłami&lt;/li&gt;&lt;li&gt;Require - wymieniamy po spacjach nazwy użytkowników, lub grup które mogą się logować, albo podajemy &quot;valid-user&quot;, które oznacza, że logować może się każdy użytkownik opisany w pliku z hasłami. W przypadku podawania użytkownika:&lt;br /&gt;Require user nazwa_użytkownika1 nazwa_użytkownika2 itd...&lt;br /&gt;W przypadku grup:&lt;br /&gt;Require group nazwa_grupy1 nazwa_grupy2 itd.....&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Jeśli wszystko wykonaliśmy poprawnie, to po wejściu do naszego katalogu:&lt;br /&gt;[code]http://localhost/top_secret_area[/code]&lt;br /&gt;wyświetli nam się prośba o podanie loginu i hasła w celu uzyskania dostępu do zawartości.&lt;br /&gt;Od tej chwili jedynie określeni przez nas użytkownicy mają dostęp do tego folderu.&lt;br /&gt;&lt;br /&gt;Możemy też określać nazwy grup użytkowników, którzy mogą się logować:&lt;br /&gt;W przypadku takim, tworzymy plik z grupami np.:&lt;br /&gt;[code]C:\top_secret\groups[/code]&lt;br /&gt;&lt;br /&gt;I wpisujemy w nim np.:&lt;br /&gt;[code]tajna_grupa: janusz anna[/code]&lt;br /&gt;&lt;br /&gt;Grup możemy dodać kilka, każdą w oddzielnej linijce, np.:&lt;br /&gt;[code]tajna_grupa: janusz anna&lt;br /&gt;inna_grupa: adam marek[/code]&lt;br /&gt;&lt;br /&gt;Gdy mamy już plik z definicjami grup, dołączamy go do .htaccess i określamy kto może się logować tym razem podając grupę, a nie pojedyńczych użytkowników:&lt;br /&gt;[code]&lt;br /&gt;AuthType basic&lt;br /&gt;AuthName &quot;Top Secret Area&quot;&lt;br /&gt;AuthUserFile C:/top_secret/.htpasswd&lt;br /&gt;AuthGroupFile C:/top_secret/groups&lt;br /&gt;Require group tajna_grupa&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Uwaga:&lt;/b&gt; aby móc skorzystać z modułu autoryzacji w pliku .htaccess nasz katalog musi mieć ustawioną w konfiguracji httpd.conf &amp;nbsp;dyrektywę AllowOverride na wartość &quot;all&quot; lub conajmniej na &quot;AuthConfig&quot;.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/461398784422923059/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-autoryzacja-za-pomoca-htpasswd.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/461398784422923059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/461398784422923059'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-autoryzacja-za-pomoca-htpasswd.html' title='[APACHE] Autoryzacja za pomocą .htpasswd'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-fapetHXGMOY/VWD0g9yOtCI/AAAAAAAAH6g/66iVAOJbPIw/s72-c/apache_auth.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-2928057261481344895</id><published>2015-05-26T19:05:00.002+02:00</published><updated>2015-05-28T16:32:42.228+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2"/><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2_httpd"/><title type='text'>[APACHE] Allow, Deny - konfiguracja dostępu do katalogów</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-PJ1hCo_QIXA/VWD0hTCFfLI/AAAAAAAAH6o/wgb2YCp_p0A/s1600/apache_httpd_conf.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-PJ1hCo_QIXA/VWD0hTCFfLI/AAAAAAAAH6o/wgb2YCp_p0A/s1600/apache_httpd_conf.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Podczas pracy z serwerem Apache bardzo często spotkamy się z regułami Allow i Deny, które odpowiadają za ustawianie reguł dostępu do danego katalogu z zewnątrz. Reguły te można narzucać globalnie za pomocą głównego pliku konfiguracyjnego Apache&#39;a, można także je nadpisywać w plikach .htaccess o ile na to zezwolimy. Reguły dostępu mają ściśle określoną składnię i warto się z nią zapoznać, aby móc wykorzystywać to w praktyce. Nie jest to trudne i ogranicza się w zasadzie do zrozumienia kilku podstawowych zasad. W tym krótkim artykule postaram się wyjaśnić na czym polega konfiguracja takich reguł, a także kiedy i jak należy je stosować.&lt;br /&gt;&lt;br /&gt;Na wstępie musimy mieć świadomość, iż wszystko to co Apache udostępnia &quot;na zewnątrz&quot; może zostać skonfigurowane i określone wg zadanych mu reguł. Poprawna konfiguracja ma kluczowe znaczenie dla bezpieczństwa naszego serwera, a zasada &quot;im mniej udostępniamy w świat, tym lepiej&quot; ma tutaj bardzo duże znaczenie. Złotą zasadą udostępniania aplikacji na zewnątrz jest wydzielenie odpowiedniej struktury logicznej naszego projektu i podzielenie jej na dwie sekcje: sekcję, która MUSI zostać udostępniona na zewnątrz - szablon strony, pliki CSS, skrypty .js, czy dołączane grafiki oraz na sekcję z właściwym kodem naszej aplikacji, do której po stronie klienta nie powinno być już dostępu. Warto bowiem zauważyć, że to co udostępnione jest klientowi != temu do czego dostęp ma serwer. Ograniczając udostępniane na zewnątrz zasoby, nie ograniczamy zatem naszej aplikacji, gdyż po stronie serwera ma ona wciąż dostęp do całości kodu ukrytego przed użytkownikiem. Przykładem moze być tutaj popularny framework Symfony, który na zewnątrz udostępnia jedynie folder &quot;web/&quot;, natomiast cała logika aplikacji znajduje się w folderach powyżej, nie udostępnionych przez WWW.&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;h2&gt;ORDER, DENY, ALLOW&lt;/h2&gt;To pierwsza kluczowa sprawa jaką należy zrozumieć.&lt;br /&gt;Popatrzmy na przykładową konfigurację dostępu do danego katalogu:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;Order deny,allow&lt;br /&gt;Deny from all&lt;br /&gt;Allow from 127.0.0.1&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;W pierwszej linijce mamy określoną kolejność przetwarzania reguły:&lt;br /&gt;[code]Order deny,allow[/code]&lt;br /&gt;gdzie:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;deny - oznacza dostęp zabroniony&lt;/li&gt;&lt;li&gt;allow - oznacza przyznanie dostępu&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Podana jest tutaj kolejność &quot;deny,allow&quot; - oznacza to, iż najpierw przetwarzane są reguły zabraniające dostępu, dopiero następnie reguły zezwalające na dostęp.&lt;br /&gt;Aby to zrozumieć popatrzy dalej - w drugiej linijce:&lt;br /&gt;[code]Deny from all[/code]&lt;br /&gt;zabraniamy dostępu dla wszystkich,&lt;br /&gt;&lt;br /&gt;aby po chwili w linijce trzeciej:&lt;br /&gt;[code]Allow from 127.0.0.1[/code]&lt;br /&gt;zezwolić na dostęp jedynie z adresu 127.0.0.1, czyli tylko dla nas samych.&lt;br /&gt;Określona wcześniej kolejność - deny, allow powoduje więc, że reguła &quot;allow&quot; niejako nadpisuje regułę &quot;deny.&lt;br /&gt;&lt;br /&gt;Aby to lepiej zrozumieć, zamieńmy teraz kolejność przetwarzania reguł:&lt;br /&gt;[code]&lt;br /&gt;Order allow,deny&lt;br /&gt;Deny from all&lt;br /&gt;Allow from 127.0.0.1&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Powyzsza reguła spowoduje, iż dostęp do katalogu zostanie zabroniony DLA WSZYSTKICH, nawet pomimo faktu, że najpierw podane mamy:&lt;br /&gt;[code]Deny from all[/code]&lt;br /&gt;a po nim przecież:&lt;br /&gt;[code]Allow from 127.0.0.1[/code]&lt;br /&gt;&lt;br /&gt;Nie ma więc tutaj znaczenia w jakiej kolejności podajemy reguły, znaczenie ma jedynie słowo kluczowe &quot;Order&quot; i ustawiona za pomocą niego kolejność przetwarzania. W tym drugim przypadku, czyli:&lt;br /&gt;[code]&lt;br /&gt;Order allow,deny&lt;br /&gt;Deny from all&lt;br /&gt;Allow from 127.0.0.1&lt;br /&gt;[/code]&lt;br /&gt;zadziała to więc wg następującej kolejności:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;zezwalamy na dostęp dla 127.0.0.1&lt;/li&gt;&lt;li&gt;zabraniamy dostępu dla każdego (a więc tym samym odbieramy go także dla adresu 127.0.0.1)&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Ogólnia składnia prezentuje się więc następująco:&lt;br /&gt;&lt;br /&gt;[code]Allow from adres/host[/code]&lt;br /&gt;dla ustawienia dostępu&lt;br /&gt;&lt;br /&gt;oraz:&lt;br /&gt;[code]Deny from adres/host[/code]&lt;br /&gt;dla zabronienia dostępu&lt;br /&gt;&lt;br /&gt;...gdzie w miejsce adres/host możemy podać:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;all - obowiązuje dla WSZYSTKICH adresów i hostów&lt;/li&gt;&lt;li&gt;adres IP, np. 127.0.0.1&lt;/li&gt;&lt;li&gt;wybrane adresy IP, np. 192.168.0.1 192.168.0.2 192.168.0.3 &amp;nbsp;(oddzielamy je spacją)&lt;/li&gt;&lt;li&gt;zakres adresów IP, np. 192.168.0.0/24 (jak korzystać z masek adresów opisane jest np. tutaj: &lt;a href=&quot;http://www.dslreports.com/faq/15216&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.dslreports.com/faq/15216&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;nazwę hosta lub hostów, np. localhost host2 host3... (tu trzeba zaznaczyć, że podajemy końcową nazwę hosta, np. podanie &#39;localhost&#39; zezwoli też na dostęp dla &#39;abc.localhost&#39;)&lt;/li&gt;&lt;li&gt;zmienną, env=wartość zmiennej... (o tym poniżej)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Zmienną ustawić możemy w następujący sposób:&lt;br /&gt;[code]SetEnv NAZWA_ZMIENNEJ &quot;wartość zmiennej&quot;[/code]&lt;br /&gt;&lt;br /&gt;np.&lt;br /&gt;[code]SetEnv myServerName %{SERVER_NAME}[/code]&lt;br /&gt;ustawi zmiennej myServerName wartość odpowiadającą nazwie naszego serwera&lt;br /&gt;&lt;br /&gt;Jak używać zmiennych w regułach dostępu?&lt;br /&gt;Spójrzmy na przykład:&lt;br /&gt;[code]&lt;br /&gt;SetEnvIf User-Agent ^TopSecretBrowser set_access_to_me&lt;br /&gt;Order deny,allow&lt;br /&gt;Deny from all&lt;br /&gt;Allow from set_access_to_me&lt;br /&gt;[/code]&lt;br /&gt;Powyższa reguła sprawdza, czy przeglądarka identyfikuje się ciągiem zaczynającym się od &quot;TopSecretBrowser&quot; - jeśli tak to ustawia zmienną &quot;set_access_to_me&quot;.&lt;br /&gt;Następnie:&lt;br /&gt;[code]Allow from set_access_to_me[/code]&lt;br /&gt;powoduje, iż w przypadku ustawionej zmiennej &quot;set_access_to_me&quot; zostaje nam przyznany dostęp.&lt;br /&gt;&lt;br /&gt;Mały tip: do ustawionych w Apache&#39;u zmiennych możemy odwołać się z poziomu PHP, za pomocą:&lt;br /&gt;[code]&amp;lt;?php $zmienna = getenv(NAZWA_ZMIENNEJ_APACHE); ?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&amp;lt;Directory &quot;/path/to&quot;&amp;gt;&lt;/h2&gt;W pliku httpd.conf możemy ustawić oddzielne reguły dla zadanych katalogów.&lt;br /&gt;Robimy to za pomocą dyrektywy &quot;Directory&quot;, np.:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Directory &quot;/ścieżka/do/folderu&quot;&amp;gt;&lt;br /&gt;Order deny,allow&lt;br /&gt;Deny from all&lt;br /&gt;Allow from 127.0.0.1&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;gdzie /ścieżka/do/folderu to pełna ścieżka do katalogu, np.:&lt;br /&gt;[code]/var/www/katalog[/code]&lt;br /&gt;na Linuxach&lt;br /&gt;&lt;br /&gt;lub:&lt;br /&gt;[code]C:/WWW/katalog[/code]&lt;br /&gt;na Windowsach&lt;br /&gt;&lt;br /&gt;Warto pamiętać, iż dana reguła dostępu działać będzie również na podkatalogi w katalogu, do którego ustawiamy dostęp, o ile oczywiście nie nadpiszemy tej reguły w danym podkatalogu.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;.htaccess&lt;/h2&gt;Reguły takie umieszczać można także w plikach .htaccess&lt;br /&gt;W przypadku takim - reguła obowiązywać będzie dla katalogu, w którym plik .htaccess z regułami się znajduje oraz dla jego podkatalogów (do momentu jej nadpisania przez inny .htaccess).&lt;br /&gt;Plik .htaccess nadpisze wtedy ustawienia tutaj, zamieniając je na swoje własne.&lt;br /&gt;Możliwość korzystania z pliku .htaccess w danym katalogu włączyć lub wyłączyć możemy za pomocą dyrektywy:&lt;br /&gt;[code]AllowOverride[/code]&lt;br /&gt;która może przyjąć kilka możliwych wartości:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;All - zezwala na nadpisywanie wszystkich opcji za pomocą .htaccess&lt;/li&gt;&lt;li&gt;None - nie pozwala na nadpisywanie żadnych opcji&lt;/li&gt;&lt;li&gt;FileInfo - pozwala na korzystanie w .htaccess z opcji dotyczących kontroli dokumentu, nagłówków, przekierowań, modułu rewrite itp. opcji&lt;/li&gt;&lt;li&gt;AuthConfig - pozwala na korzystanie w .htaccess z opcji dotyczących autoryzacji, jak AuthName, AuthType itp.&lt;/li&gt;&lt;li&gt;Limit - pozwala na ograniczanie dostępu w .htaccess, za pomocą poznanych właśnie Allow i Deny&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Możemy podać kilka wartości, oddzielonych spacjami, np.:&lt;br /&gt;[code]AllowOverride FileInfo Limit[/code]&lt;br /&gt;&lt;br /&gt;Przykładowo, poniższa konfiguracja zabroni nam na zmianę ustawień za pomocą pliku .htaccces w katalogu &quot;C:/WWW/katalog&quot;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Directory &quot;C:/WWW/katalog&quot;&amp;gt;&lt;br /&gt;AllowOverride none&lt;br /&gt;Order deny,allow&lt;br /&gt;Deny from all&lt;br /&gt;Allow from 127.0.0.1&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;a poniższa zezwoli na takie działania:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Directory &quot;C:/WWW/katalog&quot;&amp;gt;&lt;br /&gt;AllowOverride all&lt;br /&gt;Order deny,allow&lt;br /&gt;Deny from all&lt;br /&gt;Allow from 127.0.0.1&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;REQUIRE ALL&lt;/h2&gt;W pliku konfiguracyjnym możemy się też spotkać z następującą dyrektywą:&lt;br /&gt;[code]Require all granted[/code]&lt;br /&gt;która działa tak samo jak:&lt;br /&gt;[code]Allow from all[/code]&lt;br /&gt;&lt;br /&gt;oraz:&lt;br /&gt;[code]Require all denied[/code]&lt;br /&gt;która działa tak samo jak:&lt;br /&gt;[code]Deny from all[/code][/code]&lt;br /&gt;&lt;br /&gt;Zapis:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Directory &quot;C:/WWW/katalog&quot;&amp;gt;&lt;br /&gt;Require all granted&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;będzie równoważny z:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Directory &quot;C:/WWW/katalog&quot;&amp;gt;&lt;br /&gt;Allow from all&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Analogicznie sprawa wygląda z dyrektywą Deny.&lt;br /&gt;Zapis:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Directory &quot;C:/WWW/katalog&quot;&amp;gt;&lt;br /&gt;Require all denied&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;będzie równoważny z:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;Directory &quot;C:/WWW/katalog&quot;&amp;gt;&lt;br /&gt;Deny from all&lt;br /&gt;&amp;lt;/Directory&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;W przypadku ustawieniu braku dostępu do katalogu, serwer zwraca do klienta nagłówek z kodem 403 oraz domyślnie wyświetla użytkownikowi komunikat:&lt;br /&gt;&lt;br /&gt;&lt;h1&gt;Forbidden&lt;/h1&gt;You don&#39;t have permission to access / on this server.&lt;br /&gt;&lt;hr /&gt;&lt;address&gt;&lt;/address&gt;&lt;address&gt;&lt;/address&gt;&lt;address&gt;&lt;/address&gt;No i to tyle odnośnie podstawowej kontroli dostępu do katalogów w serwerach Apache. W następnych artykułach dowiemy się trochę więcej, a także nauczymy się korzystać z autoryzacji przy dostępie do katalogów.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/2928057261481344895/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-allow-deny-konfiguracja-dostepu-do-katalogow.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/2928057261481344895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/2928057261481344895'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-allow-deny-konfiguracja-dostepu-do-katalogow.html' title='[APACHE] Allow, Deny - konfiguracja dostępu do katalogów'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-PJ1hCo_QIXA/VWD0hTCFfLI/AAAAAAAAH6o/wgb2YCp_p0A/s72-c/apache_httpd_conf.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-5013960491570143870</id><published>2015-05-26T16:52:00.004+02:00</published><updated>2015-05-28T16:32:24.746+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2"/><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2_vhosts"/><title type='text'>[APACHE] Jak stworzyć i skonfigurować VirtualHosta?</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-hPAhhCVHKes/VWDoHy799fI/AAAAAAAAH5U/98WmkUupY9U/s1600/apache_vhosts.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-hPAhhCVHKes/VWDoHy799fI/AAAAAAAAH5U/98WmkUupY9U/s1600/apache_vhosts.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Vhosty do bardzo wygodny mechanizm do pracy z Apachem. Pomijając już nawet zastosowania typowo produkcyjne, są świetnym ułatwieniem podczas tworzenia środowisk testowych dla swoich webowych aplikacji. Zdejmują nam ograniczenie jednego katalogu głównego dla aplikacji pozwalając na tworzenie wielu różnych środowisk w obrębie jednego katalogu głównego. Przydają się też podczas testowania przekierowań modułu rewrite, a także podczas pracy z SSL, gdzie możemy wydzielić sobie oddzielną poddomenę na szyfrowaną zawartość. W tym krótkim przewodniku opiszę procedurę tworzenia takiego vhosta w oparciu o pliki konfiguracyjne Apache&#39;a na Windowsie. Na Linuxach konfiguracja jest analogiczna, ale różni się kilkoma formalnymi zabiegami.&lt;br /&gt;&lt;br /&gt;Czym jest wirtualny host? Vhost jest aliasem nakładanym na dany katalog na serwerze, do którego to katalogu przypisujemy odpowiednią subdomenę, przy czym katalog taki staje się Document Rootem dla tworzonej subdomeny.&lt;br /&gt;Przykładowo, dysponując lokalnym serwererem &quot;localhost&quot; z ustawionym Document Root na dajmy na to przykładowo:&lt;br /&gt;[code]C:\WWW\[/code]&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;możemy stworzyć w nim kilka podfolderów, np.:&lt;br /&gt;[code]&lt;br /&gt;C:\WWW\subdomena1&lt;br /&gt;C:\WWW\subdomena2&lt;br /&gt;... itd.&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;a następnie utworzyć vhosty kierujące na te katalogi:&lt;br /&gt;[code]&lt;br /&gt;http://localhost &amp;nbsp;&amp;gt;&amp;gt;&amp;gt; C:\WWW\&lt;br /&gt;http://subdomena1.localhost &amp;gt;&amp;gt;&amp;gt; C:\WWW\subdomena1\&lt;br /&gt;http://subdomena2.localhost &amp;gt;&amp;gt;&amp;gt; C:\WWW\subdomena2\&lt;br /&gt;... itd.&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;gdzie oczywiście vhostami są tutaj:&lt;br /&gt;[code]&lt;br /&gt;subdomena1.localhost&lt;br /&gt;i&lt;br /&gt;subdomena2.localhost&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Czego będziemy potrzebować, poza oczywiście zainstalowanym Apachem?&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;dostępu do katalogu systemowego, a więc uprawnień administratora&lt;/li&gt;&lt;li&gt;dowolnego edytora tekstowego, może być zwykły systemowy Notepad (od siebie polecam Notepada++ do wszelakich &quot;małych&quot; operacji na plikach tekstowych)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;1) hosts - konfiguracja DNS&lt;/h2&gt;Pierwsze co musimy zrobić do dostać się do pliku, który robi w systemie za pierwszy odpytywany DNS.&lt;br /&gt;W Windowsie plik ten znajdziemy tutaj:&lt;br /&gt;[code]C:\Windows\System32\drivers\etc\hosts[/code]&lt;br /&gt;W Linuxach:&lt;br /&gt;[code]/etc/hosts[/code]&lt;br /&gt;&lt;br /&gt;Tutaj mała uwaga: musimy otworzyć go do edycji w trybie administracyjnym, inaczej nie będziemy mieć możliwości zapisania w nim zmian. Aby tego dokonać (w systemach windowsowych), klikamy PPM na edytorze tekstowym jakiego chcemy użyć i wybieramy opcję &quot;Uruchom jako administrator&quot;.&lt;br /&gt;W unixowych systemach dokonujemy tego przez polecenie &quot;sudo&quot;.&lt;br /&gt;&lt;br /&gt;Otwieramy plik do edycji i naszym oczom pokaże się coś mniej więcej takiego:&lt;br /&gt;[code]&lt;br /&gt;# &amp;nbsp; &amp;nbsp; &amp;nbsp;102.54.94.97 &amp;nbsp; &amp;nbsp; rhino.acme.com &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# source server&lt;br /&gt;# &amp;nbsp; &amp;nbsp; &amp;nbsp; 38.25.63.10 &amp;nbsp; &amp;nbsp; x.acme.com &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# x client host&lt;br /&gt;&lt;br /&gt;# localhost name resolution is handled within DNS itself.&lt;br /&gt;#&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;127.0.0.1 &amp;nbsp; &amp;nbsp; &amp;nbsp; localhost&lt;br /&gt;#&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;::1 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; localhost&lt;br /&gt;&lt;br /&gt;127.0.0.1 &amp;nbsp; &amp;nbsp; &amp;nbsp; localhost&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Budowa pliku jest bardzo prosta:&lt;br /&gt;W oddzielnych linijkach podajemy przypisania danych hostów do adresów IP.&lt;br /&gt;&lt;br /&gt;Zapis:&lt;br /&gt;[code]127.0.0.1 &amp;nbsp;localhost[/code]&lt;br /&gt;mówi systemowi, że hosta localhost ma on w pierwszej kolejności szukać pod adresem 127.0.0.1, który jest lokalnym adresem naszej maszyny, tzw. loopback-iem. Adres 127.0.0.1 zawsze prowadzi do nas samych. W tym przypadku zatem zarazem prowadzi do naszego lokalnego serwera jeśli mamy zainstalowanego Apacha. Kolejne adresy podajemy tutaj w oddzielnych linijkach, na zasadzie:&lt;br /&gt;[code]ADRES_IP &amp;nbsp; &amp;nbsp;host[/code]&lt;br /&gt;&lt;br /&gt;Dodajmy więc kilka subdomen:&lt;br /&gt;[code]&lt;br /&gt;127.0.0.1 &amp;nbsp; subdomena1.localhost&lt;br /&gt;127.0.0.1 &amp;nbsp; subdomena2.localhost&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Mała uwaga: jeśli chcemy wejść na localhosta z &quot;www&quot; na początku, to również i to musimy uwzględnić w pliku hosts.&lt;br /&gt;Nasz plik hosts może więc przyjąć taką postać:&lt;br /&gt;[code]&lt;br /&gt;....&lt;br /&gt;# &amp;nbsp; &amp;nbsp; &amp;nbsp;102.54.94.97 &amp;nbsp; &amp;nbsp; rhino.acme.com &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# source server&lt;br /&gt;# &amp;nbsp; &amp;nbsp; &amp;nbsp; 38.25.63.10 &amp;nbsp; &amp;nbsp; x.acme.com &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# x client host&lt;br /&gt;&lt;br /&gt;# localhost name resolution is handled within DNS itself.&lt;br /&gt;#&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;127.0.0.1 &amp;nbsp; &amp;nbsp; &amp;nbsp; localhost&lt;br /&gt;#&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;::1 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; localhost&lt;br /&gt;&lt;br /&gt;127.0.0.1 &amp;nbsp; localhost&lt;br /&gt;127.0.0.1 &amp;nbsp; subdomena1.localhost&lt;br /&gt;127.0.0.1 &amp;nbsp; subdomena2.localhost&lt;br /&gt;127.0.0.1 &amp;nbsp; www.localhost&lt;br /&gt;127.0.0.1 &amp;nbsp; www.subdomena1.localhost&lt;br /&gt;127.0.0.1 &amp;nbsp; www.subdomena2.localhost&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Zapisujemy plik i kierujemy się w stronę Apacha.&lt;br /&gt;Najpierw oczywiście utwórzmy odpowiednie foldery, do których będziemy kierowali vhosty, np.:&lt;br /&gt;[code]&lt;br /&gt;C:\WWW\subdomena1&lt;br /&gt;C:\WWW\subdomena2&lt;br /&gt;[/code]&lt;br /&gt;Jest to bardzo ważne, aby katalogi istniały, gdyż w przeciwnym wypadku Apache odmówi nam dalszej współpracy, gdy nie znajdzie katalogu na jaki będzie miał kierować ruch.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;2) httpd.conf - konfiguracja Apache&#39;a&lt;/h2&gt;Teraz możliwe są dwie opcje, zależnie od konfiguracji naszego Apache&#39;a. Możemy mieć właczoną, lub wyłaczoną obsługę vhostów. Domyślnie plik z vhostami nie jest dołączany do konfiguracji Apache&#39;a - jeśli tak jest w naszym przypadku, zmienimy to:&lt;br /&gt;&lt;br /&gt;Otwieramy do edycji plik konfiguracyjny Apache&#39;a (ponownie na prawach administracyjnych!):&lt;br /&gt;[code]ścieżka/do/apache2/conf/httpd.conf[/code]&lt;br /&gt;&lt;br /&gt;i szukamy linii wyglądającej tak:&lt;br /&gt;[code]Include conf/extra/httpd-vhosts.conf[/code]&lt;br /&gt;&lt;br /&gt;Linijka ta odpowiada za dołączenie do konfiguracji pliku z definicjami vhostów.&lt;br /&gt;Jeśli przed słowem &quot;Include&quot; znajduje się znak komentarza (#) to usuwamy go i zapisujemy plik.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;3) httpd-vhosts.conf - konfiguracja wirtualnych hostów&lt;/h2&gt;Otwieramy teraz plik (ponownie z administracyjnymi uprawnieniami):&lt;br /&gt;[code]ścieżka/do/apache2/conf/extra/httpd-vhosts.conf[/code]&lt;br /&gt;&lt;br /&gt;który wyglądać będzie mniej więcej tak:&lt;br /&gt;[code]&lt;br /&gt;# Virtual Hosts&lt;br /&gt;#&lt;br /&gt;# Required modules: mod_log_config&lt;br /&gt;&lt;br /&gt;# If you want to maintain multiple domains/hostnames on your&lt;br /&gt;# machine you can setup VirtualHost containers for them. Most configurations&lt;br /&gt;# use only name-based virtual hosts so the server doesn&#39;t need to worry about&lt;br /&gt;# IP addresses. This is indicated by the asterisks in the directives below.&lt;br /&gt;#&lt;br /&gt;# Please see the documentation at&lt;br /&gt;# &amp;lt;URL:http://httpd.apache.org/docs/2.4/vhosts/&amp;gt;&lt;br /&gt;# for further details before you try to setup virtual hosts.&lt;br /&gt;#&lt;br /&gt;# You may use the command line option &#39;-S&#39; to verify your virtual host&lt;br /&gt;# configuration.&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;# VirtualHost example:&lt;br /&gt;# Almost any Apache directive may go into a VirtualHost container.&lt;br /&gt;# The first VirtualHost section is used for all requests that do not&lt;br /&gt;# match a ServerName or ServerAlias in any &amp;lt;VirtualHost&amp;gt; block.&lt;br /&gt;#&lt;br /&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAdmin webmaster@dummy-host.example.com&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &quot;c:/www&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerName localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAlias localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ErrorLog &quot;logs/localhost-error.log&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; CustomLog &quot;logs/localhost-access.log&quot; common&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Każdy blok &amp;lt;VirtualHost&amp;gt;...&amp;lt;/VirtualHost&amp;gt; to definicja oddzielnego vhosta.&lt;br /&gt;Dodajmy więc nasze vhosty, które zdefiniowaliśmy w pliku &quot;hosts&quot; jako:&lt;br /&gt;[code]&lt;br /&gt;subdomena1.localhost&lt;br /&gt;subdomena2.localhost&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Zrobimy to, dodając kolejny blok z definicją:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAdmin nasz@email.com&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &quot;c:/www/subdomena1&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerName subdomena1.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAlias subdomena1.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ErrorLog &quot;logs/subdomena1-error.log&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; CustomLog &quot;logs/subdomena1-access.log&quot; common&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;I analogiczny blok dla subdomeny2:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAdmin nasz@email.com&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &quot;c:/www/subdomena2&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerName subdomena2.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAlias subdomena2.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ErrorLog &quot;logs/subdomena2-error.log&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; CustomLog &quot;logs/subdomena2-access.log&quot; common&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Każda taka konfiguracja vhosta jak widzimy składa się z kilku podstawowych elementów:&lt;br /&gt;&lt;br /&gt;[code]&amp;lt;VirtualHost *:80&amp;gt;[/code]&lt;br /&gt;Definiuje na jakim porcie dla tego hosta ma nasłuchiwać serwer, domyślnie jest to port HTTP 80, czasami 8080.&lt;br /&gt;&lt;br /&gt;[code]ServerAdmin nasz@email.com[/code]&lt;br /&gt;Określna adres email admina serwera, możemy tutaj podać cokolwiek&lt;br /&gt;&lt;br /&gt;[code]DocumentRoot &quot;c:/www/subdomena2&quot;[/code]&lt;br /&gt;Wskazuje pełną ścieżkę do katalogu głównego na jaki prowadzić będzie adres hosta&lt;br /&gt;&lt;br /&gt;[code]ServerName subdomena2.localhost[/code]&lt;br /&gt;Definiuje nazwę hosta, musi odpowiadać wpisowi w pliku &quot;hosts&quot;&lt;br /&gt;&lt;br /&gt;[code]ServerAlias subdomena2.localhost[/code]&lt;br /&gt;Definiuje alias dla hosta, musi odpowiadać wpisowi w pliku &quot;hosts&quot;&lt;br /&gt;&lt;br /&gt;[code]ErrorLog &quot;logs/subdomena2-error.log&quot;[/code]&lt;br /&gt;Ustawia plik z logami błędów na &quot;logs/subdomena2-error.log&quot;&lt;br /&gt;&lt;br /&gt;[code]CustomLog &quot;logs/subdomena2-access.log&quot; common[/code]&lt;br /&gt;Ustawia plik z logami dostępu do hosta na &quot;logs/subdomena2-access.log&quot;&lt;br /&gt;&lt;br /&gt;Tutaj mała uwaga - jeśli chcemy korzystać również z przedrostka &quot;www.&quot; przy podawaniu nazwy subdomeny, powinniśmy zastosować wildcarda (*) w definicji ServerAlias, tj.:&lt;br /&gt;[code]ServerAlias *.subdomena1.localhost[/code]&lt;br /&gt;&lt;br /&gt;Nasz plik finalnie wyglądać będzie więc mniej więcej tak:&lt;br /&gt;[code]&lt;br /&gt;# Virtual Hosts&lt;br /&gt;#&lt;br /&gt;# Required modules: mod_log_config&lt;br /&gt;&lt;br /&gt;# If you want to maintain multiple domains/hostnames on your&lt;br /&gt;# machine you can setup VirtualHost containers for them. Most configurations&lt;br /&gt;# use only name-based virtual hosts so the server doesn&#39;t need to worry about&lt;br /&gt;# IP addresses. This is indicated by the asterisks in the directives below.&lt;br /&gt;#&lt;br /&gt;# Please see the documentation at&lt;br /&gt;# &amp;lt;URL:http://httpd.apache.org/docs/2.4/vhosts/&amp;gt;&lt;br /&gt;# for further details before you try to setup virtual hosts.&lt;br /&gt;#&lt;br /&gt;# You may use the command line option &#39;-S&#39; to verify your virtual host&lt;br /&gt;# configuration.&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;# VirtualHost example:&lt;br /&gt;# Almost any Apache directive may go into a VirtualHost container.&lt;br /&gt;# The first VirtualHost section is used for all requests that do not&lt;br /&gt;# match a ServerName or ServerAlias in any &amp;lt;VirtualHost&amp;gt; block.&lt;br /&gt;#&lt;br /&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAdmin webmaster@dummy-host.example.com&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &quot;c:/www&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerName localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAlias *.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ErrorLog &quot;logs/localhost-error.log&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; CustomLog &quot;logs/localhost-access.log&quot; common&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAdmin nasz@email.com&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &quot;c:/www/subdomena1&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerName subdomena1.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAlias *.subdomena1.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ErrorLog &quot;logs/subdomena1-error.log&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; CustomLog &quot;logs/subdomena1-access.log&quot; common&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;&lt;br /&gt;I analogiczny blok dla subdomeny2:&lt;br /&gt;&amp;lt;VirtualHost *:80&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAdmin nasz@email.com&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot &quot;c:/www/subdomena2&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerName subdomena2.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ServerAlias *.subdomena2.localhost&lt;br /&gt;&amp;nbsp; &amp;nbsp; ErrorLog &quot;logs/subdomena2-error.log&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; CustomLog &quot;logs/subdomena2-access.log&quot; common&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Zapisujemy plik.&lt;br /&gt;Poprawność konfiguracji vhostów możemy zweryfikować w konsoli, wpisując:&lt;br /&gt;[code]ścieżka/do/apache2/bin/httpd -S[/code]&lt;br /&gt;&lt;br /&gt;Jeśli wszystko jest OK, to restartujemy Apache&#39;a, możemy to zrobić poleceniem:&lt;br /&gt;[code]ścieżka/do/apache2/bin/httpd -k restart[/code]&lt;br /&gt;&lt;br /&gt;To wszystko.&lt;br /&gt;Od tej chwili możemy korzystać z naszych wirtualnych hostów pod adresami:&lt;br /&gt;[code]&lt;br /&gt;http://subdomena1.localhost&lt;br /&gt;http://subdomena2.localhost&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Polecam naprawdę używanie vhostów do pracy nad różnymi aplikacjami.&lt;br /&gt;Jest to bardzo wygodne i efektywne rozwiązanie separujące nam aplikacje, nad którymi pracujemy do oddzielnych od siebie domen. Wymaga to jak widać odrobiny czasu na konfigurację, ale zaręczam, że naprawdę warto pracować w taki właśnie sposób, zamiast robić to na zasadzie:&lt;br /&gt;[code]&lt;br /&gt;http://localhost/aplikacja1&lt;br /&gt;http://localhost/aplikacja2&lt;br /&gt;...itd&lt;br /&gt;[/code]</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/5013960491570143870/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-jak-stworzyc-i-skonfigurowac-wirtualnego-hosta.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5013960491570143870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5013960491570143870'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-jak-stworzyc-i-skonfigurowac-wirtualnego-hosta.html' title='[APACHE] Jak stworzyć i skonfigurować VirtualHosta?'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-hPAhhCVHKes/VWDoHy799fI/AAAAAAAAH5U/98WmkUupY9U/s72-c/apache_vhosts.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-3468871533248841170</id><published>2015-05-25T19:33:00.001+02:00</published><updated>2015-06-02T17:04:18.948+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2"/><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2_rewrite"/><title type='text'>[APACHE][mod_rewrite] Reguły, warunki i atrybuty - tworzymy pierwsze praktyczne przekierowania</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-VuU4Niy30eg/VWD0hzSypTI/AAAAAAAAH6w/uCF6JfDhLEY/s1600/apache_rewrite.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-VuU4Niy30eg/VWD0hzSypTI/AAAAAAAAH6w/uCF6JfDhLEY/s1600/apache_rewrite.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span id=&quot;goog_1414342673&quot;&gt;&lt;/span&gt;&lt;span id=&quot;goog_1414342674&quot;&gt;&lt;/span&gt;W poprzedniej części, czyli we wstępie określiliśmy sobie czym jest mod_rewrite, na co mniej więcej pozwala i jak wygląda przykładowa reguła przepisywania adresu. W tym odcinku nauczymy się tworzyć bardziej zaawansowane reguły, które pozwolą już na w pełni określone działanie naszych adresów. Przy okazji opiszę tutaj kilka standardowych problemów wraz z rozwiązaniami jak sobie z nimi radzić, gdyż mod_rewrite do poprawnego działania wymaga kilku &quot;tricków&quot;. Nauczymy się też testowania stworzonych reguł oraz przeanalizujemy atrybuty reguł oraz dostępne w mod_rewrite zmienne.&lt;br /&gt;&lt;br /&gt;Na początek małe przepomnienie - reguły określone w pliku .htaccess działają na folder, w którym plik ten się znajduje oraz na wszystkie jego podfoldery (o ile w danym podfolderze nie umieścimy kolejnego .htaccess nadpisującego reguły z pliku nadrzędnego). Na potrzeby tego poradnika nasz .htaccess umieszczamy w katalogu głównym naszego serwera. Przy okazji mały tip: nazwę pliku .htaccess można zmienić na inną dowolną, np. na &quot;config&quot; - określa się to w konfiguracji Apache&#39;a, radzę jednak pozostać przy domyślnej nazwie, żeby trzymać się standardów.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Środowisko testowe&lt;/h2&gt;Na potrzeby nauki powinniśmy przygotować sobie jakieś środowisko testowe.&lt;br /&gt;Moją propozycją jest utworzenie wirtualnego hosta na naszym lokalnym serwerze, tak abyśmy do testowanej strony mieli dostęp z poziomu subdomeny:&lt;br /&gt;&lt;br /&gt;[code]rewrite.localhost[/code]&lt;br /&gt;&lt;br /&gt;Głównym katalogiem (DocumentRoot) dla vhosta niech będzie np.&lt;br /&gt;[code]/NASZ_GŁÓWNY_KATALOG_Z_WWW/rewrite/[/code]&lt;br /&gt;i to na niego przekierujemy subdomenę &#39;rewrite&#39;.&lt;br /&gt;Jak stworzyć vhosta opisałem w &lt;a href=&quot;http://www.phpeverywhere.blogspot.com/2015/05/apache-jak-stworzyc-i-skonfigurowac-wirtualnego-hosta.html&quot; target=&quot;_blank&quot;&gt;tym artykule&lt;/a&gt;.&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dlaczego takie rozwiązanie, a nie np. &#39;localhost/rewrite&#39;?&lt;/b&gt;&lt;br /&gt;Ponieważ w momencie, gdy adres główny będzie miał postać typu &#39;serwer/katalog&#39; to stworzy nam to nadprogramowy ciąg (katalog/) w adresie, co za tym idzie nasze reguły będą musiały go uwzględniać. Można też oczywiście wszystko wrzucić bezpośrednio na localhost, wygodniej jednak jest tworzyć sobie oddzielne subdomeny (vhosty) do danych eksperymentów. No dobrze, jeśli mamy już vhosta, lub jeśli wybraliśmy katalog główny localhosta, to przystępujemy do pracy - utwórzmy w głównym katalogu plik .htaccess, na nim będziemy pracować.&lt;br /&gt;&lt;br /&gt;Tutaj jeszcze jedna wskazówka odnośnie testowania regułek - bardzo przyda się nam strona:&lt;br /&gt;&lt;a href=&quot;http://htaccess.madewithlove.be/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;http://htaccess.madewithlove.be/&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;która zawiera tester online dla takich reguł, wypluwając nam wynik przekierowania w czasie rzeczywistym. Bardzo gorąco polecam do testowania zasad i reguł, gdyż jest to niesamowicie przydatne narzędzie.&lt;br /&gt;&lt;br /&gt;Przygotujmy sobie też w głównym katalogu plik &#39;index.php&#39;, który będzie pokazywał nam na bieżąco parametry pobierane z przepisanego URL-a:&lt;br /&gt;[code]&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;foreach($_GET as $k =&amp;gt; $v)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; echo $k . &#39; = &#39; . $v . &#39;&amp;lt;br /&amp;gt;&#39;;&lt;br /&gt;}&lt;br /&gt;?&amp;gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Zmienne&lt;/h2&gt;Na początek warto znać podstawowe zmienne, które udostępniane są nam do wykorzystania w pliku .htaccess:&lt;br /&gt;Zakładając, że wywołujemy w adresie następujący URL, a właściwie to URI, ale na potrzeby poradnika używajmy bardziej przyjemnej nazwy URL:&lt;br /&gt;[code]http://rewrite.localhost/kategorie/21[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;%{REQUEST_FILENAME}&lt;/b&gt; - ścieżka i nazwa do wywoływanego w adresie pliku/katalogu, &lt;i&gt;&amp;nbsp;tutaj: &lt;b&gt;kategorie/21&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{REQUEST_URI}&lt;/b&gt; - pełny adres zapytania z jakiego nastąpiło wywołanie, &lt;i&gt;tutaj: &lt;b&gt;rewrite.localhost/kategorie/21&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{REQUEST_TIME}&lt;/b&gt; - obecny czas wywołania adresu&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{HTTP_HOST}&lt;/b&gt; - adres hosta do jakiego nastąpiło w adresie wywołanie, &lt;i&gt;tutaj:&amp;nbsp;&lt;b&gt;rewrite.localhost&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{REQUEST_METHOD}&lt;/b&gt; - rodzaj wywołania (GET/POST/PUT...itp)&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{HTTP_REFERER}&lt;/b&gt; - adres, z którego nastąpiło wywołanie adresu&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{QUERY_STRING}&lt;/b&gt; - wartość parametrów z adresu, np. wywołując &#39;http://localhost/kategorie/lista.html?sort=desc&#39; zawierać będzie &#39;sort=desc&#39;&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{DOCUMENT_ROOT}&lt;/b&gt; - katalog główny (pełna ścieżka)&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{AUTH_TYPE}&lt;/b&gt; - rodzaj autoryzacji dla katalogu (Digest/Basic...)&lt;/li&gt;&lt;li&gt;&lt;b&gt;%{THE_REQUEST} &lt;/b&gt;- pełna treść wywołania, &lt;i&gt;tutaj:&amp;nbsp;&lt;b&gt;GET /kategorie/21/ HTTP/1.1&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;To tylko kilka główniejszych zmiennych, które pozwolą na standardową pracę z mod_rewrite.&lt;br /&gt;Pełna lista zmiennych, wraz z opisami (a jest ich dużo) znajduje się pod adresem:&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://www.askapache.com/htaccess/mod_rewrite-variables-cheatsheet.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.askapache.com/htaccess/mod_rewrite-variables-cheatsheet.html&lt;/a&gt;,&lt;/b&gt; natomiast lista najczęściej używanych zmiennych - pod koniec artykułu.&lt;br /&gt;&lt;br /&gt;Przypomnijmy sobie przekierowanie jakie utworzyliśmy we wstępie:&lt;br /&gt;[code]&lt;br /&gt;# .htaccess&lt;br /&gt;RewriteEngine on&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-d&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Tworzyło ono przekierowanie z:&lt;br /&gt;[code]http://nazwa_hosta/AKCJA[/code]&lt;br /&gt;do&lt;br /&gt;[code]index.php?action=AKCJA[/code]&lt;br /&gt;uprzednio sprawdzając, czy w katalogu nie istnieje plik, lub folder o nazwie AKCJA.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Pierwszy problem - końcowy slash&lt;/b&gt;&lt;br /&gt;I w tym momencie napotykamy na pierwszy z problemów do rozwiązania, mianowicie na fakt występowania końcowego slasha.Na czym polega nasz problem?&lt;br /&gt;Na tym - adres nasz może wyglądać tak:&lt;br /&gt;[code]http://rewrite.localhost/kategorie[/code]&lt;br /&gt;ale moze i tak:&lt;br /&gt;[code]http://rewrite.localhost/kategorie/[/code]&lt;br /&gt;&lt;br /&gt;/dla celów testowych, będziemy tutaj wykorzystywać umownie nazwę naszego vhosta - rewrite.localhost/&lt;br /&gt;&lt;br /&gt;Akurat w naszej regułce obie formy wykonają poprawne przekierowanie, ale żeby ustandaryzować sobie formę adresu, na jakim będziemy dalej operować powinniśmy sprawić, aby:&lt;br /&gt;- albo wszystkie adresy kończyły się slashem&lt;br /&gt;- albo żeby żaden z adresów nie kończył się slashem&lt;br /&gt;&lt;br /&gt;Rozwiązanie takie jest ponadto dobrą praktyką jeśli chodzi o roboty wyszukiwarek - w przypadku linku z końcowym slashem i linku bez slasha mamy DWA różne linki, a więc zdublowaną zawartość, co nie jest mile widziane przez wyszukiwarki.&lt;br /&gt;&lt;br /&gt;Dodamy slasha na końcu do każdego adresu, zrobimy to warunkiem:&lt;br /&gt;[code]RewriteCond %{REQUEST_URI} !(.*)/$[/code]&lt;br /&gt;Powyższy warunek sprawdza, czy adres URL (REQUEST_URI) nie równa się wyrażeniu ze slashem na końcu (negacja - !)&lt;br /&gt;&lt;br /&gt;jeśli nie, to tworzymy przekierowanie dla takiego adresu, za pomocą:&lt;br /&gt;[code]RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=302][/code]&lt;br /&gt;Powyższa reguła przepisuje każdy adres na taki sam, ale ze slashem na końcu.&lt;br /&gt;Następnie mamy tutaj podane dwa argumenty objęte w nawiasy kwadratowe.&lt;br /&gt;Argumenty te wymagają wyjaśnienia.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Argumenty reguł&lt;/h2&gt;Tóż po wyrażeniu obsługującym regułę przekierowania w nawiasach kwadratowych [ ] możemy podać listę dodatkowych argumentów/parametrów/znaczników/flag - spotkamy się z różnymi nazwami - my przyjmijmy określenie &quot;argumenty&quot;.&lt;br /&gt;Argumenty takie mówią serwerowi co dodatkowo ma zrobić po wykonaniu reguły je poprzedzającej. Argument możemy podać jeden, możemy też kilka - w przypadku większej ich ilości podajemy je wszystkie w obrębie jednego nawiasu, oddzielając je przecinkiem. Lista możliwych argumentow jest długa i zostanie opisana na końcu artykułu, na chwilę obecną przedstawię jedynie te najczęściej wykorzystywane:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[L]&lt;/b&gt; - skrót od &quot;Last&quot;. Określa, iż reguła zawarta w linijce z tym argumentem jest ostatnią regułą przekierowania.&lt;br /&gt;Na czym to polega? Otóż mod-rewrite przelatuje po koleji po wszystkich pasujących regułach, aż do samego końca.&lt;br /&gt;Działanie takie jest zapętlone, aż do wykonania ostatniej pasującej reguły. Parametr [L] mówi serwerowi, że obecna regułka jest ostatnią i że w tym miejscu, jeśli nastąpi jej wykonanie nakazuje zignorowanie następujących po niej reguł. Wykorzystywane to jest głównie przy określaniu &quot;sztywnych&quot; przekierowań.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[R=]&lt;/b&gt; - skrót od &quot;Redirect&quot;, czyli przekierowanie. Po znaku &quot;=&quot; przyjmuje kod przekierowania, a więc kod statusu z grup 300 i 400.&lt;br /&gt;Przykładowo: [R=301] określa przekierowanie trwałe (301 Moved Permamently), natomiast [R=302] nakazuje przekierowanie tymczasowe (302 Moved Temporaly).&lt;br /&gt;W celach testowych powinniśmy zamiast przekierowań 301 używać tych o statusie 302, czyli czasowych. Dlaczego? Dlatego, iż np. Firefox zapamiętuje permamentne przekierowania w cache&#39;u, co może czasem utrudnić testowanie naszych regułek. W ostatecznej wersji natomiast powinniśmy używać 301.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[NC]&lt;/b&gt; - skrót od &quot;No case&quot;. Sprawia, że ignorowana jest wielkość liter podczas dopasowania i tak np. reguła dla &quot;index.php&quot; w adresie bedze obowiązywać również dla &quot;InDeX.pHp&quot;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[N]&lt;/b&gt; - skrót od &quot;Next&quot;. Powoduje rozpoczęcie przepisywania reguł od początku, z tym, że każde kolejne dopasowania wykonywane są dla już obecnie przepisanego URL-a, nie dla tego bazowego&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[C] &lt;/b&gt;- skrót od &quot;Chain&quot;, czyli łańcuch. Powoduje zawarcie kilku reguł w jeden łańcuch (grupę). Jeśli nie wystąpi żadna z reguł w takim łańcuchu, to wykonywana jest reguła po nich występująca.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[T=]&lt;/b&gt; - skrót od &quot;Mime Type&quot;. Pozwala na ustawienie własnego typu MIME. Np. wykonanie [T=image/png] spowoduje wywołanie przepisanego URL-a z typem &quot;image/png&quot;.&lt;br /&gt;&lt;br /&gt;Argumentów tych jest o wiele więcej. Opisałem w skrócie te najczęściej używane.&lt;br /&gt;Pełna lista argumentów znajduje się na samym dole artykułu.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Istnieją także 2 argumenty dla dyrektywy RewriteCond:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;[NC]&lt;/b&gt; - jak wyżej, ignorujący wielkość znaków&lt;br /&gt;&lt;b&gt;[OR]&lt;/b&gt; - domyślnie warunki są łączone za pomocą operatora logicznego AND, tj. muszą być spełnione wszystkie, aby wykonać regułę. Argument [OR] jak sama nazwa wskazuje wstawia pomiędzy dwa warunki operator logiczny OR zamiast AND.&lt;br /&gt;&lt;br /&gt;Wiemy już co nieco o argumentach, wwróćmy więc do naszej regułki:&lt;br /&gt;[code]&lt;br /&gt;RewriteCond %{REQUEST_URI} !(.*)/$&lt;br /&gt;RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=302]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Reguła jak widzimy dodaje nam slash do końca adresu, po czym informuje, że dopasowanie jest ostatnim i nie przetwarzamy już dalej w tym cyklu [L] oraz przekierowujemy na adres ze slashem w koncówce [R=302] (tutaj finalnie powinniśmy dać 301, dla testów pozostawmy 302). Mając już pewność, że adres kończy się slashem na końcu, część wyrażenia:&lt;br /&gt;[code]RewriteRule ^([^/.]+)&lt;b&gt;/?&lt;/b&gt;$ index.php?action=$1[/code]&lt;br /&gt;sprawdzająca wystąpienie, lub nie końcowego slasha może zostać zamieniona na:&lt;br /&gt;[code]RewriteRule ^([^/.]+)&lt;b&gt;/&lt;/b&gt;$ index.php?action=$1[/code]&lt;br /&gt;Na razie jednak pozostawy to w niezmienionej formie.&lt;br /&gt;&lt;br /&gt;Finalnie więc nasz .htaccess wygląda tak:&lt;br /&gt;[code]&lt;br /&gt;# .htaccess&lt;br /&gt;RewriteEngine on&lt;br /&gt;&lt;br /&gt;# blok1&lt;br /&gt;RewriteCond %{REQUEST_URI} !(.*)/$&lt;br /&gt;RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=302]&lt;br /&gt;&lt;br /&gt;# blok2&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-d&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Należy tutaj zrozumieć zasadę działania mechanizmu rewrite.&lt;br /&gt;Otóż silnik rewrite leci po pliku .htaccess po koleji.&lt;br /&gt;Polega to na tym, iż reguły z pliku przetwarzane są do skutku od początku do końca, aż do wystąpienia ostatniego pasującego dopasowania.&lt;br /&gt;W naszym przypadku najpierw sprawdzany jest slash na końcu (blok 1), po czym po znalezieniu go, wyłaczamy dalsze przetwarzanie [L], następnie następuje przekierowanie na adres ze slashem [R=301] po czym cały proces przetwarzania pliku .htaccess zaczyna się od początku, ale tym razem mając już slash na końcu pierwsza reguła nie wykona się (nie dopasuje), wykona się jedynie ta z bloku 2, następnie po dopasowaniu jej (lub nie) przetwarzanie .htaccess zakończy się. Bardzo ważne jest zrozumienie tego mechanizmu, gdyż bez zrozumienia go prawie na pewno zdarzy się nam popadnięcie w błędną pętlę przy bardziej złożonych regułach.&lt;br /&gt;&lt;br /&gt;Powyższy .htaccess w przypadku wpisania adresu:&lt;br /&gt;[code]http://rewrite.localhost/kategorie[/code]&lt;br /&gt;&lt;br /&gt;działa tak:&lt;br /&gt;[code]&lt;br /&gt;[URL] http://rewrite.localhost/kategorie&lt;br /&gt;[PIERWSZY PRZEBIEG .htaccess] &amp;gt;&amp;gt; http://rewrite.localhost/kategorie/&lt;br /&gt;[DRUGI PRZEBIEG .htaccess] &amp;gt;&amp;gt; http://rewrite.localhost/index.php?action=kategorie&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;b&gt;Diagram przedstawiający działanie mechanizmu Rewrite:&lt;/b&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-oZD3-bmuZyM/VWNhWz8ezzI/AAAAAAAAIDI/OtK3PGNZLeY/s1600/rewrite_rule_flow.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;http://2.bp.blogspot.com/-oZD3-bmuZyM/VWNhWz8ezzI/AAAAAAAAIDI/OtK3PGNZLeY/s640/rewrite_rule_flow.png&quot; width=&quot;582&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;i&gt;źródło: apache.org&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;b&gt;I jego dokładniejsza wersja:&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-IItXZfaHfAI/VWNhymj2TZI/AAAAAAAAIDQ/itRfXTCdAzg/s1600/rewrite_process_uri.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;610&quot; src=&quot;http://1.bp.blogspot.com/-IItXZfaHfAI/VWNhymj2TZI/AAAAAAAAIDQ/itRfXTCdAzg/s640/rewrite_process_uri.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;h2&gt;Dopasowania&lt;/h2&gt;Poki co zrobiliśmy jedno dopasowanie, do jednego parametru, dodajmy więc teraz więcej, podając np. ID kategorii:&lt;br /&gt;Najpierw musimy obmyśleć jak skonstruowane będą nasze URL-e i wybrać jakąś logikę.&lt;br /&gt;Chcemy sporządzić URL zawierający w sobie dwa elementy:&lt;br /&gt;1) nazwę akcji (przykładowo: kategoria)&lt;br /&gt;2) id przeglądanej kategorii&lt;br /&gt;&lt;br /&gt;Adres taki może mieć więc taką postać, gdzie &#39;kategoria&#39; to nazwa akcji, &#39;41&#39; to ID przegladanej kategorii:&lt;br /&gt;[code]http://rewrite.localhost/kategoria/41[/code]&lt;br /&gt;&lt;br /&gt;Adres taki tłumaczyć będziemy na adres wewnętrzny o postaci:&lt;br /&gt;[code]http://rewrite.localhost/index.php?action=kategoria&amp;amp;id=41[/code]&lt;br /&gt;&lt;br /&gt;Pierwszy problem: nasz URL może przybrać dwie możliwe formy:&lt;br /&gt;[code]http://rewrite.localhost/kategorie[/code]&lt;br /&gt;lub&lt;br /&gt;[code]http://rewrite.localhost/kategoria/41[/code]&lt;br /&gt;Musimy więc w jakiś sposób uwzględnić obie formy.&lt;br /&gt;Jak tego dokonamy? Za pomocą dwóch reguł.&lt;br /&gt;&lt;br /&gt;Zrobimy to tak:&lt;br /&gt;[code]&lt;br /&gt;# .htaccess&lt;br /&gt;RewriteEngine on&lt;br /&gt;&lt;br /&gt;# blok1 - dodajemy slash na końcu&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{REQUEST_URI} !(.*)/$&lt;br /&gt;RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=301]&lt;br /&gt;&lt;br /&gt;# blok2 - nasze regułki&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2 [L]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Pomijając resztę, nasze reguły wyglądają tak:&lt;br /&gt;[code]&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2 [L]&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Co się tutaj dzieje?&lt;br /&gt;1) Najpierw dopasowujemy regułę dla dłuższego ciągu, z wystąpieniem numeru ID w adresie, jeśli dopasowanie zostanie wykonane, to parametr [L] mówi serwerowi, że jest to ostatnie przetwarzanie i żeby nie dopasowywał już kolejnej reguły,&lt;br /&gt;2) Dopiero po sprawdzeniu powyższego sprawdzamy krótszą wersję, z podaniem samej akcji. Dlaczego ważna jest taka kolejność?&lt;br /&gt;Akurat w tym przypadku wykonanie reguł odwrotnie nie sprawi problemu, ale przy bardziej złożonych regułach mogłoby to powodować problemy, gdyż pamiętajmy, że każda kolejna reguła pracuje na wyniku poprzedniej, a więc dopasowanie początkowe niejako określa wszystko to co poleci dalej do przetwarzania.&lt;br /&gt;Dowód? Wykonajmy coś takiego:&lt;br /&gt;[code]&lt;br /&gt;RewriteRule ^(.+)/$ index.php?action=$1&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&lt;br /&gt;[/code]&lt;br /&gt;Usunęliśmy sprawdzenie wystąpienie slasha w środku adresu w pierwszej linijce w związku z czym pierwsza reguła zostanie dopasowana do:&lt;br /&gt;[code]http://rewrite.localhost/kategoria/41[/code]&lt;br /&gt;Do reguły kolejnej przekazany zostanie wynik dopasowanej pierwszej:&lt;br /&gt;[code]index.php?action=kategorie/41[/code]&lt;br /&gt;w związku z czym druga reguła nie wykona się nigdy!&lt;br /&gt;&lt;br /&gt;Powróćmy więc do wersji poprawnej:&lt;br /&gt;[code]&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2 [L]&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wynikiem w przypadku adresu:&lt;br /&gt;[code]http://rewrite.localhost/kategoria/123[/code]&lt;br /&gt;będzie wewnętrzne przekierowania na:&lt;br /&gt;[code]index.php?action=kategoria&amp;amp;id=123[/code]&lt;br /&gt;&lt;br /&gt;...natomiast w przypadku:&lt;br /&gt;[code]http://rewrite.localhost/kategorie[/code]&lt;br /&gt;będzie to:&lt;br /&gt;[code]index.php?action=kategorie[/code]&lt;br /&gt;&lt;br /&gt;Analogicznie zrobimy z np. 3 i więcej parametrami:&lt;br /&gt;[code]&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3&amp;amp;parametr4=$4 [L]&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3 [L]&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2 [L]&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1 [L]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Całość naszego .htaccess wyglądać więc może tak:&lt;br /&gt;[code]&lt;br /&gt;# .htaccess&lt;br /&gt;RewriteEngine on&lt;br /&gt;&lt;br /&gt;# blok1 - dodajemy slash na końcu&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{REQUEST_URI} !(.*)/$&lt;br /&gt;RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=301]&lt;br /&gt;&lt;br /&gt;# blok2 - nasze regułki&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3&amp;amp;parametr4=$4 [L]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3 [L]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2 [L]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1 [L]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Sprawdźmy teraz co się stanie, gdy wywołamy adres:&lt;br /&gt;[code]http://rewrite.localhost/kategoria/123/aaa/bbb/ccc/ddd/eeee[/code]&lt;br /&gt;Nie mamy żadnego wyrażenia dopasowującego taką ilość parametrów, serwer zwróci nam 404 Not Found.&lt;br /&gt;&lt;br /&gt;Możemy jednak tego uniknąć, ignorując po prostu większą ilość parametrów podawanych między nadprogramowymi slashami:&lt;br /&gt;Zmieńmy pierwszą regułę, zmieniając końcówkę jej dopasowania na:&lt;br /&gt;[code].*/$[/code]&lt;br /&gt;a więc na:&lt;br /&gt;[code]RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/([^/.]+).*/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3&amp;amp;parametr4=$4 [L][/code]&lt;br /&gt;.* oznaczać będzie nam tutaj dowolny ciąg znaków, który może, ale nie musi nadprogramowo na końcu wystąpić.&lt;br /&gt;Jest to bardziej eleganckie rozwiązanie, niż rzucenie błędem 404.&lt;br /&gt;Możemy też pobrać nadprogramowy ciąg, przekazać go jako parametr do index.php, następnie przetworzyć przez PHP, albo stworzyć do obsłużenia tego oddzielne reguły, ja podałem jedynie przykład na jeden ze sposóbów radzenia sobie z niepasującymi do wzorca URL-ami. Inne sposoby przeanalizujemy później.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;QSA - parametry GET w zapytaniu&lt;/h2&gt;A co jeśli wywołamy np. taki URL?&lt;br /&gt;[code]http://rewrite.localhost/kategorie/?sort=desc[/code]&lt;br /&gt;Po wykonaniu naszych przepisań, otrzymamy jedynie:&lt;br /&gt;[code]index.php?action=kategorie[/code]&lt;br /&gt;natomiast:&lt;br /&gt;[code]?sort=desc[/code]&lt;br /&gt;zostanie pominięte.&lt;br /&gt;&lt;br /&gt;Jak więc przekazać parametry podane po znaku zapytania?&lt;br /&gt;Służy do tego argument [QSA] - skrót od Query String Append.&lt;br /&gt;Zmodyfikujmy teraz nasze reguły w .htaccess do takiej postaci:&lt;br /&gt;[code]&lt;br /&gt;# .htaccess&lt;br /&gt;RewriteEngine on&lt;br /&gt;&lt;br /&gt;# blok1 - dodajemy slash na końcu&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{REQUEST_URI} !(.*)/$&lt;br /&gt;RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=301]&lt;br /&gt;&lt;br /&gt;# blok2 - nasze regułki, tym razem z uwzględnieniem QSA&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3&amp;amp;parametr4=$4 [L,QSA]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3 [L,QSA]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2 [L,QSA]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1 [L,QSA]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Voila! Wynikiem przepisania:&lt;br /&gt;[code]http://rewrite.localhost/kategorie/?sort=desc[/code]&lt;br /&gt;jest:&lt;br /&gt;[code]index.php?action=kategorie&amp;amp;sort=desc[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problem z prefixem &quot;www.&quot;&lt;/h2&gt;Nieszczęsna pozostałość po starych czasach, czyli prefix, a właściwie subdomena &#39;www&#39; może, ale nie musi wystąpić na początku naszego adresu.&lt;br /&gt;Wszystko zależy jaki adres wywoła użytkownik. Niestety tak to już jest, że:&lt;br /&gt;[code]http://www.rewrite.localhost[/code]&lt;br /&gt;i&lt;br /&gt;[code]http://rewrite.localhost[/code]&lt;br /&gt;to (pomimo że prowadzą w to samo miesjce) dwa rożne adresy, zarówno dla plików cookies, czy polityki Same Domain Origin, a nawet dla robotów wyszukiwarek.&lt;br /&gt;Co możemy z tym zrobić? Opcje są dwie:&lt;br /&gt;&lt;br /&gt;1) usuwamy wszędzie &quot;www.&quot; jeśli takowe wystąpi w adresie&lt;br /&gt;2) dodajemy wszędzie &quot;www.&quot; o ile nie występuje na początku adresu.&lt;br /&gt;&lt;br /&gt;Wybor należy do nas, podaję oba rozwiązania:&lt;br /&gt;&lt;br /&gt;1) usuwa &quot;www.&quot; z każdego adresu:&lt;br /&gt;[code]&lt;br /&gt;RewriteCond %{HTTP_HOST} ^www. [NC]&lt;br /&gt;RewriteRule ^(.*)$ http://rewrite.localhost/$1 [R=302,L]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;2) dodaje &quot;www.&quot; do każdego adresu:&lt;br /&gt;[code]&lt;br /&gt;RewriteCond %{HTTP_HOST} !^www. [NC]&lt;br /&gt;RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=302,L]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Uwaga: na czas testów dajemy tutaj przekierowanie 302, w finalnej wersji damy tutaj 301, czyli Moved Permamently.&lt;/b&gt;&lt;br /&gt;Reguły te umieszczamy na początku, przed regułami dodającymi slasha do końcówki adresu:&lt;br /&gt;[code]&lt;br /&gt;# .htaccess&lt;br /&gt;RewriteEngine on&lt;br /&gt;&lt;br /&gt;# blok0 - usuwamy &quot;www.&quot; z początku adresu&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{HTTP_HOST} ^www. [NC]&lt;br /&gt;RewriteRule ^(.*)$ http://rewrite.localhost/$1 [R=302,L]&lt;br /&gt;&lt;br /&gt;# blok1 - dodajemy slash na końcu&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{REQUEST_URI} !(.*)/$&lt;br /&gt;RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [L,R=302]&lt;br /&gt;&lt;br /&gt;# blok2 - nasze regułki, tym razem z uwzględnieniem QSA&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3&amp;amp;parametr4=$4 [L,QSA]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2&amp;amp;parametr3=$3 [L,QSA]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/([^/.]+)/?$ index.php?action=$1&amp;amp;id=$2 [L,QSA]&lt;br /&gt;&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1 [L,QSA]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Oczywiście konstrukcji takich jak powyżej nie tworzy się w praktyce, zamiast tego przekierowywuje się każdego requesta do jednego pliku PHP, który już sam dalej zajmuje się przeparsowaniem otrzymanego żądania:&lt;br /&gt;[code]&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-d&lt;br /&gt;RewriteRule .? index.php [L]&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;No i to tyle w dzisiejszym odcinku.&lt;br /&gt;Wiemy już jak przepisywać większą ilość parametrów w URL-u, jak używać atrybutów oraz na co zwracać uwagę przy tworzeniu regułek. W następnej części wykorzystamy to trochę bardziej praktycznie, a także poznamy kilka innych rozwiązań.&lt;br /&gt;&lt;br /&gt;Poniżej jeszcze lista wszystkich argumentów jakie stosować można do regułek oraz najczęściej używanych zmiennych. Lista zaczerpnięta z &lt;a href=&quot;http://4programmers.net/Z_pogranicza/Mod_rewrite&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://4programmers.net/Z_pogranicza/Mod_rewrite&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Argumenty - lista:&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Znacznik &lt;b&gt;[NC]&lt;/b&gt; (nocase)&lt;br /&gt;Sprawia, że w danym wzorcu pomijane są różnice w wielkościach znaków. Dla przykładu, dwa poniższe wzorce mają identyczne działanie:&lt;br /&gt;RewriteRule ^([A-Za-z])/?$ web.php?q=$1&lt;br /&gt;RewriteRule ^([a-z])/?$ web.php?q=$1 [NC]&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;R[=kod] &lt;/b&gt;(redirect)&lt;br /&gt;Znacznik ten powoduje formalne przekierowanie wraz z podaniem kodu stanu HTTP, domyślnie powoduje on wysłanie kodu HTTP 302 Moved Temporarily. Przykład:&lt;br /&gt;RewriteRule ^art/(\d+)/?$ art.php?id=$1 [R=301]&lt;br /&gt;Kod w powyższym przykładzie to 301 Moved Permanently.&lt;br /&gt;Używając tego znacznika można zwracać dowolny kod HTTP z zakresu od 300 do 400.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;F&lt;/b&gt; (forbidden)&lt;br /&gt;Działa podobnie do znacznika redirect, ale od razu wysyła odpowiedź HTTP 403. Jeżeli w ramach jednej reguły znajdzie się ten znacznik oraz redirect, to pierwszeństwa na znacznik forbidden, co oznacza, że zostanie wysłany kod 403 niezależnie od wartości kodu redirect.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;G&lt;/b&gt; (gone)&lt;br /&gt;Znacznik ten wysyła kod HTTP 410 - Usunięto, który informuje użytkownika o tym, że żądana strona została usunięta. Ma on pierwszeństwo przed znacznikiem redirect, ale ważniejszym od niego jest forbidden.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;L&lt;/b&gt; (last)&lt;br /&gt;Znacznik ten pozwala na zatrzymanie przetwarzania reguł RewriteRule po skutecznym dopasowaniu adresu URL do reguły.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;N&lt;/b&gt; (next)&lt;br /&gt;Znacznik next ponownie rozpoczyna proces przepisywania adresu od samego początku listy reguł. W momencie rozpoczęcia ponownego przetwarzania reguł obsługują one juz nie oryginalny adres URL, ale jego postać przepisano przez wszystkie reguły do momentu pojawienia się znacznika next.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;C&lt;/b&gt; (chain)&lt;br /&gt;Jeżeli chcielibyśmy traktować blok reguł jako jednostkę, to powinniśmy posłużyć się znacznikiem chain. Wytłumaczmy to na przykładzie:&lt;br /&gt;Rewrite Rule ^art/(\d+)/?$ art.php?id=$1 [C]&lt;br /&gt;RewriteRule ^cat/(\w+)/?$ cat.php?cat=$1 [C]&lt;br /&gt;RewriteRule ^art/[^\d+]/?$ error.php&lt;br /&gt;Jeżeli żadna z reguł związanych znacznikiem chain nie pasuje to przechodzimy do ostaniej.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;S=liczba&lt;/b&gt; (skip)&lt;br /&gt;Ten znacznik powoduje pominięcie podanej liczby reguł. Znacznik ów zachowuje podobnie się do chain, z tą różnicą, że pozwala pominąć reguły w przypadku udanego dopasowania.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;T=typ-mime&lt;/b&gt; (type)&lt;br /&gt;W przypadku kiedy chcemy zmienić typ MIME wysyłanego dokumentu, to możemy posłużyć się tym znacznikiem. Na przykład jeżeli mamy pliki xhtml i chcielibyśmy wysłać je za pomocą poprawnego typu MIME (application/xhtml+xml) to możemy wykorzystać tą regułę:&lt;br /&gt;RewriteRule ^.+\.xhtml$ - [T=application/xhtml+xml]&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;CO=nazwa:wartość:domena[:czaszycia[:sciezka]]&lt;/b&gt; (cookie)&lt;br /&gt;Znacznik ten służy do utworzenia ciasteczka w przeglądarce użytkownika . Wymagane są pola nazwa, wartość i domena. Możemy na przykład utworzyć ciasteczko o nazwie bylemtu, istnienie którego będzie oznaczało że użytkownik już odwiedzał naszą stronę.&lt;br /&gt;RewriteRule ^index\.php$ - [CO=bylemtu:true:domena.pl]&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;E=zmienna:wartosc &lt;/b&gt;(env)&lt;br /&gt;Znacznik ten pozwala nadać wartość zmiennej środowiskowej zmienna. W jednej grupie znaczników można przypisać wartości do wielu zmiennych środowiskowych.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;QSA&lt;/b&gt; (qsappend)&lt;br /&gt;W przypadku obecności tego znacznika mechanizm przepisywania pobierze oryginalny ciąg znaków zapytania i dopisze do niego ciąg znaków wygenerowany przez regułę.&lt;br /&gt;RewriteRule ^index\.php$ index.php?zmienna=wartosc [QSA]&lt;br /&gt;Jeżeli tej regule podamy adres postaci index.php?cos=bla to w wyniku jej działania otrzymamy index.php?zmienna=wartosc&amp;amp;cos=bla.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;NE&lt;/b&gt; (noescape)&lt;br /&gt;Znacznik ten pomaga unikać automatycznego wyróżniania znaków specjalnych.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;PT&lt;/b&gt; (passtrough)&lt;br /&gt;Używamy go w momencie kiedy chcemy połączyć moduł mod_rewrite z innymi moduła, które również zajmują się obsługą adresó URL.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;NS&lt;/b&gt; (nosubreq)&lt;br /&gt;Znacznik ten używamy w momencie jeżeli chcemy aby mechanizm przepisywania adresów pominął regułę, jeżeli żądanie jest wewnętrznym żądaniem podrzędnym. Bardzo rzadko jest używany, jezeli korzystamy z Apache i PHP, przydaje się w momencie dołączenia skryptów CGI.&lt;/li&gt;&lt;li&gt;Znacznik &lt;b&gt;P&lt;/b&gt; (proxy)&lt;br /&gt;Nakazuje on zakończenie przetwarzania reguł i przekazanie danych żądania do modułu mod_proxy.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Zmienne:&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;HTTP_USER_AGENT&lt;/b&gt; Ciąg znaków z informacja identyfikującą przeglądarke.&lt;/li&gt;&lt;li&gt;&lt;b&gt;HTTP_REFERER&lt;/b&gt; Dokładnie &quot;polecający&quot;, adres strony, która nas skierowała, na konkretną stronę. Nie wszystkie przeglądarki wysyłają, również firewall&#39;e często wycinają to.&lt;/li&gt;&lt;li&gt;&lt;b&gt;HTTP_COOKIE&lt;/b&gt; Ciąg znaków ciasteczka.&lt;/li&gt;&lt;li&gt;&lt;b&gt;HTTP_FORWARDER&lt;/b&gt; Jeżeli żądanie jest obsługiwane przez serwer proxy, to zawiera dowolne przekazywane informacje.&lt;/li&gt;&lt;li&gt;&lt;b&gt;HTTP_HOST&lt;/b&gt; Nazwa komputera wymieniana w rządaniu.&lt;/li&gt;&lt;li&gt;&lt;b&gt;HTTP_PROXY_CONNECTION &lt;/b&gt;Zwraca zawartość nagłówka Proxy-Connection.&lt;/li&gt;&lt;li&gt;&lt;b&gt;REMOTE_ADDR&lt;/b&gt; Adres ip komputera wysłającego żądanie.&lt;/li&gt;&lt;li&gt;&lt;b&gt;REMOTE_HOST&lt;/b&gt; Nazwa komputera wysyłającego żądanie.&lt;/li&gt;&lt;li&gt;&lt;b&gt;REMOTE_USER&lt;/b&gt; Nazwa użytkownika komputera wysyłającego żądanie. Nie musi być podana.&lt;/li&gt;&lt;li&gt;&lt;b&gt;REMOTE_IDENT&lt;/b&gt; Zmienne przeznaczone do celów indentyfikacji. Może zawierać nazwę użytkownika.&lt;/li&gt;&lt;li&gt;&lt;b&gt;REMOTE_METHOD &lt;/b&gt;Metoda żądania pliku (POST lub GET).&lt;/li&gt;&lt;li&gt;&lt;b&gt;SCRIPT_FILENAME&lt;/b&gt; Pełna lokalna ścieżka do żądanego pliku.&lt;/li&gt;&lt;li&gt;&lt;b&gt;PATH_INFO&lt;/b&gt; Dodatkowe informacje o ścieżce.&lt;/li&gt;&lt;li&gt;&lt;b&gt;QUERY_STRING &lt;/b&gt;Ciąg zapytania albo parametry zapytania metodą GET.&lt;/li&gt;&lt;li&gt;&lt;b&gt;AUTH_TYPE&lt;/b&gt; Rodzaj uwierzytelniania.&lt;/li&gt;&lt;li&gt;&lt;b&gt;DOCUMENT_ROOT&lt;/b&gt; Katalog główny strony.&lt;/li&gt;&lt;li&gt;&lt;b&gt;SERVER_ADMIN&lt;/b&gt; Adres email administratora serwera.&lt;/li&gt;&lt;li&gt;&lt;b&gt;SERVER_ADDR&lt;/b&gt; Adres ip lub komputera serwera.&lt;/li&gt;&lt;li&gt;&lt;b&gt;SERVER_PORT&lt;/b&gt; Podany w żądaniu port serwera.&lt;/li&gt;&lt;li&gt;&lt;b&gt;SERVER_PROTOCOL &lt;/b&gt;Nazwa i wersja protokołu żądania.&lt;/li&gt;&lt;li&gt;&lt;b&gt;SERVER_SOFTWARE&lt;/b&gt; Nazwa oprogramowania serwera.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME_YEAR&lt;/b&gt; Rok na serwerze.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME_MON&lt;/b&gt; Numer miesiąca.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME_DAY &lt;/b&gt;Numer dnia.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME_HOUR&lt;/b&gt; Godzina żądania.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME_MIN&lt;/b&gt; Minuta żądania.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME_SEC&lt;/b&gt; Sekunda żądania.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME_WDAY&lt;/b&gt; Dzień tygodnia żądania.&lt;/li&gt;&lt;li&gt;&lt;b&gt;TIME&lt;/b&gt; Bierząca godzina.&lt;/li&gt;&lt;li&gt;&lt;b&gt;API_VERSION&lt;/b&gt; Numer wersji interfejsu API serwera Apache.&lt;/li&gt;&lt;li&gt;&lt;b&gt;THE_REQUEST&lt;/b&gt; Pełne żądanie HTTP.&lt;/li&gt;&lt;li&gt;&lt;b&gt;REQUEST_URI&lt;/b&gt; Żądany zasób.&lt;/li&gt;&lt;li&gt;&lt;b&gt;REQUEST_FILENAME&lt;/b&gt; Pełna ścieżka w lokalnym systemie plików do żądanego pliku.&lt;/li&gt;&lt;li&gt;&lt;b&gt;IS_SUBREQ&lt;/b&gt; Informacja, czy żądanie jest wewnętrznym żądaniem podrzędnym.&lt;/li&gt;&lt;li&gt;&lt;b&gt;HTTPS&lt;/b&gt; Wartość on oznacza, że połączenie jest szyfrowane.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Pełna lista tutaj:&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://www.askapache.com/htaccess/mod_rewrite-variables-cheatsheet.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;http://www.askapache.com/htaccess/mod_rewrite-variables-cheatsheet.html&lt;/b&gt;&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/3468871533248841170/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-modrewrite-reguly-warunki-i-atrybuty.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3468871533248841170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/3468871533248841170'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-modrewrite-reguly-warunki-i-atrybuty.html' title='[APACHE][mod_rewrite] Reguły, warunki i atrybuty - tworzymy pierwsze praktyczne przekierowania'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-VuU4Niy30eg/VWD0hzSypTI/AAAAAAAAH6w/uCF6JfDhLEY/s72-c/apache_rewrite.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-5422605052919904069</id><published>2015-05-24T23:42:00.000+02:00</published><updated>2015-05-25T20:48:54.959+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2"/><category scheme="http://www.blogger.com/atom/ns#" term="APACHE2_rewrite"/><title type='text'>[APACHE][mod_rewrite] Wstęp do przepisywania URL-i</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-VuU4Niy30eg/VWD0hzSypTI/AAAAAAAAH6w/uCF6JfDhLEY/s1600/apache_rewrite.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-VuU4Niy30eg/VWD0hzSypTI/AAAAAAAAH6w/uCF6JfDhLEY/s1600/apache_rewrite.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Mechanizm przepisywania URL-i za pomocą modułu rewrite z początku może wydawać się nieco skomplikowany. O ile nauczenie się podstawowych regułek przepisywania i wykorzystanie ich w praktyce nie stanowi zbyt dużego problemu, to niestety, ale prędzej, czy później natrafimy na kilka problemów związanych z regułami przekierowań, na pewno też nie raz i nie dwa &quot;zapętlimy się&quot; przy co bardziej rozbudowanej hierarchi regułek. W artykułach tutaj postaram się przedstawić najczęstsze problemy z jakimi prawie na pewno spotkamy się podczas tworzenia plików .htaccess. Omówię też same podstawy tworzenia takich przekierowań. Zacznijmy więc może od początku - czym jest mod_rewrite? Jest to moduł serwera Apache, ktory za pomocą odpowiednio określonych warunków (conditions) wywołuje zadaną przez nas regułę (rule), która w dany, określony sposób dokonuje przekierowania z jednego URL-a na inny, zdefiniowany przez nas. Reguły takie określamy w specjalnym pliku o nazwie &#39;.htaccess&#39;, który umieszczamy w folderze, dla którego zawarte w nim reguły mają obowiązywać (będą też obowiązywać dla jego podfolderów). Plik &#39;.htacccess&#39; ma ściśle określoną strukturę, składającą się z kilku sekcji. Omówimy je kilka akapitów niżej. Na razie omówmy samą zasadę przepisywania URL-i, a więc - na czym to wszystko polega?&lt;br /&gt;&lt;br /&gt;Wyobraźmy sobie, że mamy przygotowaną w PHP aplikację, np. sklep internetowy.&lt;br /&gt;W aplikacji tej posiadamy system kategorii i podkategorii naszych produktów, listę tych produktów, oraz odpowiednie sekcje odpowiadające za wyświetlanie informacji o zadanym produkcie.&lt;br /&gt;Po sklepie tym poruszamy się w jakiś określony sposób definiujący nam np. gdzie obecnie się znajdujemy (czy np. w widoku listy kategorii, czy produktów) oraz jaką kategorię lub produkt obecnie wyświetlamy. Informacje takie przekazujemy zazwyczaj jako parametry w adresie, np.&lt;br /&gt;[code]http://nasz_sklep.com/index.php?action=category&amp;amp;id=20[/code]&lt;br /&gt;lub&lt;br /&gt;[code]http://nasz_sklep.com/index.php?action=product_info&amp;amp;id=45[/code]&lt;br /&gt;&lt;br /&gt;Brzydkie prawda? A i niezbyt chętnie indeksowane przez wyszukiwarki.&lt;br /&gt;O wiele ładniej wygladałoby to, gdyby linki przedstawiały się np. tak:&lt;br /&gt;[code]http://nasz_sklep/kategorie/telewizory[/code]&lt;br /&gt;lub&lt;br /&gt;[code]http://nasz_sklep/produkt/Samsung_Smart_LED_J6200.html[/code]&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;...albo jeszcze lepiej:&lt;br /&gt;[code]http://nasz_sklep/telewizory[/code]&lt;br /&gt;lub&lt;br /&gt;[code]http://nasz_sklep/telewizory/LED/Samsung_Smart_LED_J6200.html[/code]&lt;br /&gt;&lt;br /&gt;Dzięki mod_rewrite możemy uzyskać właśnie takie linki i wiele wiele więcej.&lt;br /&gt;Na czym polega takie zamiana? Otóż, zauważmy, iż każdy z naszych wewnętrznych linków ma jakąś określoną strukturę, np. w linku&lt;br /&gt;[code]?action=category&amp;amp;category_id=20[/code]&lt;br /&gt;parametr &#39;action&#39; przechowuje nam informacje o rodzaju oglądanej sekcji (akcji), w tym przypadku jest to widok kategorii produktów, natomiast parametr category_id mówi naszej aplikacji o numerze ID kategorii jaką wlaśnie przeglądamy. Zarazem parametr &#39;action&#39; jest tutaj niejako stałym elementem takiego linka. Zmienia się jedynie to co występuje w jego wartości, np.:&lt;br /&gt;&lt;br /&gt;[code]index.php?action=category&lt;br /&gt;index.php?action=product_info&lt;br /&gt;index.php?action=order_info[/code]&lt;br /&gt;&lt;br /&gt;itd...&lt;br /&gt;&lt;br /&gt;Analogicznie jest z parametrem &#39;id&#39;, który przechowuje nam numer ID oglądanego zasobu:&lt;br /&gt;[code]index.php?action=product_info&amp;amp;id=1&lt;br /&gt;index.php?action=product_info&amp;amp;id=54&lt;br /&gt;index.php?action=product_info&amp;amp;id=437[/code]&lt;br /&gt;itd...&lt;br /&gt;&lt;br /&gt;Struktura naszego linka przedstawia się więc następująco:&lt;br /&gt;[code]http://nasz_sklep.com/index.php?action=NAZWA_WYŚWIETLANEJ_AKCJI&amp;amp;id=ID_POKAZYWANEGO_ELEMENTU[/code]&lt;br /&gt;&lt;br /&gt;Załóżmy teraz, że chcemy taki link sprowadzić do bardziej ładnej wersji, np. do takiej formy:&lt;br /&gt;[code]http://nasz_sklep.com/NAZWA_WYŚWIETLANEJ_AKCJI/ID_POKAZYWANEGO_ELEMENTU[/code]&lt;br /&gt;&lt;br /&gt;Jak tego dokonać? Otóż musimy utworzyć:&lt;br /&gt;1) jakiś warunek sprawdzający jak nasz URL wygląda&lt;br /&gt;2) jakąś regułę, która na podstawie tego warunku dokona odpowiedniej zamiany&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Budowa pliku .htaccess&lt;/h2&gt;Zacznijmy od zapoznania się z przykładową budową pliku .htaccess, który będzie przepisywać nasze URL-e. Plik taki składa się z kilku sekcji, które po koleji sobie omówimy. Zacznijmy więc, poniżej przykładowy plik .htaccess:&lt;br /&gt;[code]&lt;br /&gt;RewriteEngine on //1&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f //2&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1 &amp;nbsp;//3[/code]&lt;br /&gt;&lt;br /&gt;Ten prosty plik dokonuje po koleji następujących działań:&lt;br /&gt;1) włącza moduł rewrite dla tego folderu i jego podfolderów&lt;br /&gt;2) sprawdza warunek, czy nie odwołujemy się do istniejącego na serwerze pliku&lt;br /&gt;3) jeśli powyższy warunek jest spełniony to przepisuje URL z postaci:&lt;br /&gt;[code]nasz_sklep.com/NAZWA_AKCJI/[/code]&lt;br /&gt;na&lt;br /&gt;[code]index.php?action=NAZWA_AKCJI[/code]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;RewriteCond&lt;/h2&gt;O ile pierwsza linijka nie wymaga zbytniego tłumaczenia, tak dalej sprawa robi się już bardziej skomplikowana. Przeanalizujmy wiec wszystko po koleji, na początek warunek zawarty w linijce drugiej:&lt;br /&gt;&lt;br /&gt;[code]RewriteCond %{REQUEST_FILENAME} !-f[/code]&lt;br /&gt;&lt;br /&gt;warunki dla danej reguły definiujemy na zasadzie:&lt;br /&gt;&lt;br /&gt;[code]RewriteCond NASZ_WARUNEK1&lt;br /&gt;RewriteCond NASZ_WARUNEK2&lt;br /&gt;RewriteCond NASZ_WARUNEK3&lt;br /&gt;itd...[/code]&lt;br /&gt;&lt;br /&gt;Każdy z warunków musi znaleźć się w oddzielnej linijce.&lt;br /&gt;Jeśli dany warunek zostaje spełniony, to silnik przeskakuje do następnej linijki i albo spradza kolejny warunek, albo natrafia na blok z regułą, tak jak w naszym przykładzie, gdzie warunek mamy tylko jeden. &lt;b&gt;W przypadku podania większej ilości warunków - wszystkie one muszą zostać spełnione, aby wykonała się reguła po nich następująca. Poprzedzające regułę warunki obowiązują tylko dla pierszej reguły po nich występującej!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ogólna zasada działania prezentuje się więc tak:&lt;br /&gt;[code]WARUNEK1&lt;br /&gt;WARUNEK2&lt;br /&gt;WARUNEK3&lt;br /&gt;REGUŁA1 (jeśli WARUNKI 1,2, i 3 spełnione)&lt;br /&gt;&lt;br /&gt;WARUNEK4&lt;br /&gt;REGUŁA2 (jeśli WARUNEK4 spełniony)&lt;br /&gt;REGUŁA3 (kolejna reguła, tutaj już nie obowiązuje WARUNEK4)[/code]&lt;br /&gt;&lt;br /&gt;itd...&lt;br /&gt;gdzie dana reguła wykona się jedynie wtedy, gdy określone przed nią warunki zostaną dla danej reguły spełnione.&lt;br /&gt;W naszym przykładzie mamy na początek jedynie jedną regułę:&lt;br /&gt;[code]RewriteCond %{REQUEST_FILENAME} !-f[/code]&lt;br /&gt;która sprawdza, czy przypadkiem nie odwołujemy się do istniejącego pliku.&lt;br /&gt;Dlaczego taka reguła? Już wyjaśniam. Załóżmy, że nasz plik .htaccess znajduje się w katalogu głównym naszej strony, przy czym w tym samym katalogu znajduje się plik o nazwie &#39;kategorie&#39;. Mało prawdopodone, ale wyobraźmy sobie, że jednak plik &#39;http://nasz_sklep.com/kategorie&#39; istnieje realnie w tym miejscu. Zarazem słowo &#39;kategorie&#39; jest tutaj jednym z parametrów jakie przyjmuje nasza zmienna $_GET[&#39;action&#39;].&lt;br /&gt;&lt;br /&gt;Mamy więc tutaj kolizję, gdyż adres &#39;http://nasz_sklep.com/kategorie&#39; może odwoływac się zarówno do realnie istniejącego pliku o nazwie:&lt;br /&gt;[code]http://nasz_sklep.com/kategorie[/code]&lt;br /&gt;jak i do przepisanego URL-a:&lt;br /&gt;[code]http://nasz_sklep.com/index.php?action=kategorie[/code]&lt;br /&gt;&lt;br /&gt;Jak więc rozwiązać ten problem? Od tego właśnie mamy tutaj nasz warunek.&lt;br /&gt;Sprawdza on, czy plik o zadanej w adresie nazwie nie istnieje fizycznie w obecnym katalogu i dopiero jeśli takowego pliku nie ma, to wykonywana jest reguła przepisująca adres:&lt;br /&gt;[code]http://nasz_sklep.com/kategorie[/code]&lt;br /&gt;na&lt;br /&gt;[code]http://nasz_sklep.com/index.php?action=kategorie[/code]&lt;br /&gt;&lt;br /&gt;Rozłóżmy ten warunek na czynniki pierwsze:&lt;br /&gt;[code]%{REQUEST_FILENAME} !-f[/code]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;%{REQUEST_FILENAME}&lt;/b&gt; - jest to zmienna środowiskowa przechowująca wywoływany właśnie adres, w naszym przypadku np. http://nasz_sklep.com/kategorie&lt;br /&gt;&lt;b&gt;-f &lt;/b&gt;- tóż po niej podany jest parametr -f, który oznacza lokalny plik.&lt;br /&gt;&lt;br /&gt;Podany jest on jednak ze znakiem negacji (wykrzyknik - !), a więc tłumacząc na zrozumiały język warunek brzmi następująco:&lt;br /&gt;[code]WYWOŁYWANY ADRES != REALNIE ISTNIEJACY PLIK O TAKIEJ NAZWIE[/code]&lt;br /&gt;a więc: jeśli nie istnieje plik o nazwie takiej jak wywoływany URL, to warunek zostaje spełniony i lecimy dalej, wywołać regułę w linijce trzeciej.&lt;br /&gt;&lt;br /&gt;W zasadzie zawsze jako startowe reguły podaje się właśnie sprawdzenie, czy wywoływany adres nie prowadzi do istniejącego pliku lub folderu:&lt;br /&gt;&lt;br /&gt;[code]%{REQUEST_FILENAME} !-f&lt;br /&gt;%{REQUEST_FILENAME} !-d[/code]&lt;br /&gt;&lt;br /&gt;Parametr -f oznacza plik, parametr -d oznacza folder.&lt;br /&gt;Wzbogaćmy więc nasz .htaccess o sprawdzenie folderu:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;RewriteEngine on //1&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-f //2&lt;br /&gt;RewriteCond %{REQUEST_FILENAME} !-d //3&lt;br /&gt;RewriteRule ^([^/.]+)/?$ index.php?action=$1 &amp;nbsp;//4&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Tego typu zmiennych jest więcej, np.&lt;br /&gt;&lt;b&gt;%{HTTP_HOST}&lt;/b&gt; - przechowywuje część z adresu z nazwą hosta, przykładowo: po wywołaniu http://nasz_sklep.com/kategorie w zmiennej tej znajdzie się &#39;nasz_sklep.com&#39;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;%{REQUEST_URI}&lt;/b&gt; - przechowuje cały URL z jakiego nastąpiło wywołanie.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;RewriteRule&lt;/h2&gt;&lt;br /&gt;Skoro oba warunki mamy spełnione (nie istnieje plik &#39;http://nasz_sklep.com/kategorie&#39; oraz nie istnieje folder &#39;http://nasz_sklep.com/kategorie&#39;) to wykonywana jest następująca po warunku reguła:&lt;br /&gt;&lt;br /&gt;[code]RewriteRule ^([^/.]+)/?$ index.php?action=$1[/code]&lt;br /&gt;&lt;br /&gt;Rozłóżmy ją na czynniki pierwsze.&lt;br /&gt;W pierwszym członie:&lt;br /&gt;[code]^([^/.]+)/?$[/code]&lt;br /&gt;znajduje się wyrażenie, z którego będziemy przepisywać URL, tutaj np.:&lt;br /&gt;&lt;br /&gt;[code]http://nasz_sklep.com/kategorie[/code]&lt;br /&gt;&lt;br /&gt;w drugim natomiast forma do jakiej przepisanie nastąpi:&lt;br /&gt;[code]index.php?action=$1[/code]&lt;br /&gt;&lt;br /&gt;Regułka ma postać:&lt;br /&gt;[code]RewriteRule ADRES_WYWOŁANY PRAWDZIWY_ADRES [atrybuty/flagi][/code]&lt;br /&gt;&lt;br /&gt;Pierwszy człon reguły jest wyrażeniem regularnym.&lt;br /&gt;Aby więc móc umiejętnie wykorzystywać reguły przypisań nieobca musi nam być wiedza dotycząca stosowania wyrażeń regularnych. Na potrzeby tego poradnika zakładam, że jesteś z wyrażeniami regularnymi zapoznany i umiesz używać ich w praktyce.&lt;br /&gt;&lt;br /&gt;Przyjrzyjmy się dopasowywanemu ciągowi:&lt;br /&gt;&lt;br /&gt;[code]^([^/.]+)/?$[/code]&lt;br /&gt;&lt;br /&gt;Po koleji:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;^&lt;/b&gt;&amp;nbsp;- początek adresu, wystąpi on zaraz po http://nasza_strona.com&lt;/li&gt;&lt;li&gt;&lt;b&gt;/?$&lt;/b&gt; - nasz adres może, ale nie musi kończyć się slashem (znak zapytania określa, że znak przed nim może wystąpić lub nie)&lt;/li&gt;&lt;li&gt;&lt;b&gt;[^/.]+&lt;/b&gt; - mamy tutaj dopasowywany zakres znaków, w którym na początku nie może wystąpić slash (znak negacji ^), następnie może wystąpić dowolna ilość znaków (kropka .), a całość takiej konstrukcji musi wystąpić conajmniej raz (znak + zastosowany dla podanego zakresu)&lt;/li&gt;&lt;li&gt;&lt;b&gt;([^/.]+)&lt;/b&gt; - dopasowane wyrażenie jest następnie wzięte w nawiasy okrągłe. Zawartość dopasowania objęta w nawiasy zostanie przypisana do zmiennej $1 w następnym członie.&lt;/li&gt;&lt;/ul&gt;Pamiętajmy, że dopasowywany zawsze w RewriteRule ciąg jest jedynie tą częścią adresu, która występuje po nazwie hosta, a więc w naszym przypadku wszystko to co występuje po &#39;http://nasz_sklep.com/&#39;. Jeśli chcemy dostać się do części z nazwą hosta wykorzystajmy zmienną %{HTTP_HOST}.&lt;br /&gt;&lt;br /&gt;Takich dopasowań możemy zrobić więcej, w przypadku takim każde kolejne dopasowanie wzięte w nawias będzie tworzyło odpowiednio kolejną zmienną, czyli $1, $2, $3 itd.&lt;br /&gt;&lt;br /&gt;Czas na drugą część wyrażenia:&lt;br /&gt;[code]index.php?action=$1[/code]&lt;br /&gt;określa ono co robimy z uzyskanym w pierwszej części dopasowaniem.&lt;br /&gt;W naszym przypadku przepisujemy adres na:&lt;br /&gt;[code]index.php?action=$1[/code]&lt;br /&gt;co jest równoważne z:&lt;br /&gt;[code]index.php?action=DOPASOWANE_W_NAWIASACH_WYRAŻENIE[/code]&lt;br /&gt;czyli z:&lt;br /&gt;[code]index.php?action=([^/.]+)[/code]&lt;br /&gt;&lt;br /&gt;Wywołując więc adres:&lt;br /&gt;[code]http://nasz_sklep.com/kategorie[/code]&lt;br /&gt;nasza reguła za pomocą wyrażenia regularnego dopasowywuje z niego ciąg &#39;kategorie&#39;, umieszcza go w zmiennej $1, a następne zmienną tą przekazuje jako parametr do:&lt;br /&gt;[code]index.php?action=$1[/code]&lt;br /&gt;generując tym samym adres:&lt;br /&gt;[code]index.php?action=kategorie[/code]&lt;br /&gt;&lt;br /&gt;Finalnie, efektem naszego działania będzie to, iż użytkownik wpisujący w przeglądarkę adres:&lt;br /&gt;[code]http://nasz_sklep.com/kategorie[/code]&lt;br /&gt;tak naprawdę&amp;nbsp;trafia do lokacji:&lt;br /&gt;[code]index.php?action=kategorie[/code]&lt;br /&gt;Takie przekierowanie jest oczywiście &quot;przezroczyste&quot; dla użytkownika, w pasku adresu pozostaje wciąż adres &#39;http://nasz_sklep.com/kategorie&#39;.&lt;br /&gt;Przepisywany URL jest widoczny jedynie wewnętrznie dla serwera oraz dla naszej aplikacji w PHP.&lt;br /&gt;&lt;br /&gt;To tyle tytułem krótkiego wstępu do silnika rewrite.&lt;br /&gt;Wiemy już mniej więcej na czym polega działanie mod_rewrite i do czego służy.&lt;br /&gt;W nastepnych artykułach przeanalizujemy bardziej złożone reguły i nauczymy się trochę bardziej skomplikowanych aspektów przepisywania URL-i.&lt;br /&gt;&lt;br /&gt;Tester online reguł mod_rewrite znajduje się tutaj:&lt;br /&gt;&lt;b&gt;&lt;a href=&quot;http://htaccess.madewithlove.be/&quot; target=&quot;_blank&quot;&gt;http://htaccess.madewithlove.be/&lt;/a&gt;&lt;/b&gt;</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/5422605052919904069/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-modrewrite-wstep-do-przepisywania-urli.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5422605052919904069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/5422605052919904069'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/apache-modrewrite-wstep-do-przepisywania-urli.html' title='[APACHE][mod_rewrite] Wstęp do przepisywania URL-i'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-VuU4Niy30eg/VWD0hzSypTI/AAAAAAAAH6w/uCF6JfDhLEY/s72-c/apache_rewrite.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4106195950283171870.post-2394048099834356901</id><published>2015-05-24T20:41:00.000+02:00</published><updated>2015-05-28T14:05:24.021+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="PHP_zaawansowane"/><title type='text'>[PHP] Namespaces - przestrzenie nazw w PHP</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-QLaNhRpjR38/VWD0pbQxHQI/AAAAAAAAH8c/eR32_BuZO8I/s1600/icoPHP_ADVANCED.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-QLaNhRpjR38/VWD0pbQxHQI/AAAAAAAAH8c/eR32_BuZO8I/s1600/icoPHP_ADVANCED.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Zapewne spotkaliśmy się już z dziwnie wyglądającymi nazwami klas w PHP, np. podczas pracy z frameworkami, takimi jak Symfony. Przykładowa nazwa klasy mogła wyglądać np. tak: &#39;Bundle\HelloBundle\Controller\HelloController&#39;. Nie ma tu jednak żadnej pokręconej magii, a jedynie przestrzeń nazw. Klasa w tym przypadku to &#39;HelloController&#39;, a wszystko to co znajduje się przed nią to jej przestrzeń nazwowa. Korzystanie z przestrzeni nazw znacznie usprawnia pracę z kodem, a także eliminuje problem kolizji, gdzie dwie klasy mogą mieć identyczne nazwy. Pozwalają one również na stworzenie bardzo fajnej i przejrzystej hierarchi naszego kodu. W tym krótkim tutorialu dowiemy się czym są i jak &amp;nbsp;poprawnie używać przestrzeni nazw w PHP. Funkcjonalność ta niczym nie różni się od tego samego rozwiązania stosowanego od zarania dziejów w językach takich jak C, czy Java. Przestrzenie nazw w PHP zostały dodane w wersji 5.3.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Przestrzeń globalna&lt;/h2&gt;Jest główną przestrzenią nazw. Zauważmy, że bardzo często piszemy sobie jakieś klasy, czy też funkcje, bądź też korzystamy z tych wbudowanych w silnik PHP.&lt;br /&gt;Korzystamy np. z funkcji &#39;header()&#39; służacej do ustawienia nagłówka, funkcji &#39;strip_tags()&#39; służącej do obcięcia tagów HTML i wielu innych. Nazewnictwo tych funkcji jest proste i składa się z jednego członu określającego nazwę funkcji. Funkcje takie istnieją w domyślnej przestrzeni nazw i są dostępne wszędzie w naszym kodzie. Podobnie jest z klasami, ich metodami i właściwościami. Nie wymagają poprzedzania ich nazwy nazwą przestrzeni w jakiej występują, gdyż globalna przestrzeń jest tą domyślną, bazową. Wyobraźmy sobie teraz, że tworzymy własną klasę, np. niech to będzie klasa o nazwie:&lt;br /&gt;&lt;br /&gt;[code]MyClass {}[/code]&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Tworzymy sobie plik z klasą, który będzie zamierał definicję naszej klasy, jednej funkcji i jednej stałej, niech będzie to np. plik &#39;classes/MyClass.php&#39;.&lt;br /&gt;W pliku tym stworzymy sobie definicję dla naszej klasy:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// classes/MyClass.php&lt;br /&gt;&lt;br /&gt;const MYCONST = &#39;classes/MyClass.php&#39;;&lt;br /&gt;&lt;br /&gt;function MyFunction()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; return __FUNCTION__;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class MyClass {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function MyMethodName()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return __METHOD__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function MyClassName()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return __CLASS__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public static function SayHello()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return &#39;Hello from &#39; . __CLASS__ . &#39;::&#39; . __METHOD__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Plik z klasą dołączymy do naszego głównego pliku, niech będzie to plik &quot;index.php&quot;.&lt;br /&gt;Następnie utworzymy nowy obiekt tejże klasy i wywołamy metodę &#39;GetMethodName()&#39;, która zwróci nam nazwę naszej metody w klasie &#39;MyClass&#39;:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;require_once(&#39;classes/MyClass.php&#39;);&lt;br /&gt;&lt;br /&gt;echo MYCONST; &amp;nbsp;// WYNIK: classes/MyClass.php&lt;br /&gt;echo &#39;Function name:&#39; . MyFunction(); &amp;nbsp;// WYNIK: MyFunction&lt;br /&gt;&lt;br /&gt;$c = new MyClass;&lt;br /&gt;echo &#39;Method name:&#39; . $c-&amp;gt;MyMethodName(); &amp;nbsp;// WYNIK: Method name: GetMethodName&lt;br /&gt;echo &#39;Class name:&#39; . $c-&amp;gt;MyClassName(); &amp;nbsp;// WYNIK: Class name: MyClass&lt;br /&gt;echo MyClass::SayHello(); // WYNIK: Hello from MyClass::SayHello&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Jak widzimy, na początku wyświetlamy stałą, potem nazwę funkcji, następnie klasę - jest to prościutka klasa, z trzema metodami zwracającymi odpowiednio:&lt;br /&gt;- nazwę wywoływanej metody&lt;br /&gt;- nazwę wywoływanej klasy&lt;br /&gt;- tekst przywitania z przedstawieniem się&lt;br /&gt;&lt;br /&gt;W tym prostym przypadku nie zdeklarowaliśmy żadnej przestrzeni nazw, nasza klasa istnieje zatem w przestrzeni globalnej.&lt;br /&gt;Możemy utworzyć jej obiety w dowolnym miejscu w kodzie. A co jeśli teraz stworzymy kolejną klasę o takiej samej nazwie? Stwórzmy plik &#39;other_classes/MyClass.php&#39; zawierający identyczną definicję klasy co &#39;classes/MyClass.php&#39; i dołączmy do naszego &#39;index.php&#39;:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;require_once(&#39;classes/MyClass.php&#39;);&lt;br /&gt;require_once(&#39;other_classes/MyClass.php&#39;);&lt;br /&gt;&lt;br /&gt;echo MYCONST;&lt;br /&gt;echo &#39;Function name:&#39; . MyFunction();&lt;br /&gt;&lt;br /&gt;$c = new MyClass;&lt;br /&gt;echo &#39;Method name:&#39; . $c-&amp;gt;MyMethodName();&lt;br /&gt;echo &#39;Class name:&#39; . $c-&amp;gt;MyClassName();&lt;br /&gt;echo MyClass::SayHello();&lt;br /&gt;&lt;br /&gt;// WYNIK: Fatal error: Cannot redeclare class Users&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Działanie takie spowoduje błąd, gdyż staramy się zdefiniować dwie takie same klasy w jednej i tej samej przestrzeni nazw (tutaj - w globalnej). Do rozwiązania tego problemu wykorzystamy właśnie oddzielne przestrzenie nazw.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;NAMESPACE&lt;/h2&gt;Przestrzeń nazw definiujemy za pomocą wyrażenia:&lt;br /&gt;[code]namespace NAZWA_PRZESTRZENI;[/code]&lt;br /&gt;&lt;br /&gt;Deklaracja taka musi się znaleźć zaraz na początku pliku - należy o tym pamiętać.&lt;br /&gt;Blok kodu jaki wystąpi po deklaracji przestrzeni nazw może należeć jednocześnie jedynie do jednej przestrzeni, jednakże możemy w jednym pliku zawrzeć kilka przestrzeni i bloków kodu:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;namespace MyApp1;&lt;br /&gt;// blok kodu dla MyApp1&lt;br /&gt;&lt;br /&gt;namespace MyApp2;&lt;br /&gt;// blok kodu MyApp2&lt;br /&gt;&lt;br /&gt;namespace MyApp3;&lt;br /&gt;// blok kodu dla MyApp3&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;Nie polecam jednak takiego rozwiazania - my będziemy stosować po jednej przestrzeni na jeden plik.&lt;br /&gt;&lt;br /&gt;Wyobraźmy sobie, że nasza aplikacja webowa ma nazwę &#39;MyApp&#39; i jest podzielona na jakieś elementy. Jednym z elementów moze być obsługa kont użytkowników, innym dostęp do bazy danych, jeszcze innym moduł do wyświetlania artykułów.&lt;br /&gt;&lt;br /&gt;Kod takich elementów zapewne rozmieścilibyśmy sobie w aplikacji mniej więcej w taki sposób:&lt;br /&gt;- classes/Users.php&lt;br /&gt;- classes/DB.php&lt;br /&gt;- classes/Articles.php&lt;br /&gt;itd.&lt;br /&gt;&lt;br /&gt;Idąc takim pomysłem, stwórzmy sobie nową klasę, o nazwie np. &#39;Users&#39; i zapiszmy w pliku &#39;classes/Users.php&#39;, ale tym razem dołączmy do niej przestrzeń nazw o nazwie np. &#39;MyApp\Users&#39;.&lt;br /&gt;Stwórzmy naszą klasę:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// classes/Users.php&lt;br /&gt;&lt;br /&gt;namespace MyApp\Users;&lt;br /&gt;&lt;br /&gt;class Users { &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function MyMethodName()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return __METHOD__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function MyClassName()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return __CLASS__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public static function SayHello()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return &#39;Hi, I\&#39;m users class: &#39; . __CLASS__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Na samym początku stworzyliśmy tutaj przestrzeń nazw o nazwie &#39;MyApp\Users&#39;.&lt;br /&gt;Zauważmy, że na początku podaliśmy &#39;MyApp&#39;, następnie po backslashu (\) podaliśmy &#39;Users&#39;.&lt;br /&gt;Taka właśnie jest konwencja nazewnictwa w przestrzeniach nazw, nic nie stoi na przeszkodzie, abyśmy następne przestrzenie nazywali jeszcze bardziej hierarchicznie, jak np.:&lt;br /&gt;&#39;MyApp\Users\Actions\AddUsers&#39;&lt;br /&gt;&lt;br /&gt;Załączmy teraz utworzoną klasę do naszego &#39;index.php&#39; i spróbujmy wywołać metodę &#39;Users::SayHello()&#39;:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;require_once(&#39;classes/Users.php&#39;); // dołączamy klasę Users&lt;br /&gt;echo Users::SayHello(); // WYNIK: Fatal error: Class &#39;Users&#39; not found!&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Wywołanie pliku &#39;index.php&#39; wyświetliło nam błąd informujący o tym, że klasa &#39;Users&#39; nie istnieje!&lt;br /&gt;Ale zaraz, zaraz - przecież właśnie ja stworzyliśmy i załączyliśmy do pliku &#39;index.php&#39;. W czym więc problem? Otóż problem w tym, że nasza klasa istnieje, ale w przestrzeni nazw o nazwie &#39;MyApp\Users&#39;. Nie istnieje natomiast w przestrzeni globalnej naszego kodu.&lt;br /&gt;&lt;br /&gt;Zmodyfikujmy teraz lekko nasz &#39;index.php&#39; i zmienmy jego kod na:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;require_once(&#39;classes/Users.php&#39;); // dołączamy klasę Users&lt;br /&gt;echo \MyApp\Users\Users::SayHello(); // WYNIK: Hi, I&#39;m users class: MyApp\Users\Users&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Voila! Zadziałało, mamy dostęp do klasy Users.&lt;br /&gt;Czego więc tutaj naprawdę dokonaliśmy? Otóż poprzedziliśmy nazwę wywoływanej klasy jej przestrzenią nazw.&lt;br /&gt;Zauważmy więc, że nasza klasa &#39;Users&#39; istnieje TYLKO I WYŁĄCZNIE w swojej przestrzeni i tylko w taki sposób możemy się do niej odwołać.&lt;br /&gt;&lt;br /&gt;Wyjaśnienia wymaga:&lt;br /&gt;[code]\MyApp\Users\[/code]&lt;br /&gt;Otóż tym zapisem podaliśmy prefix naszej klasy, czyli jej przestrzeń nazw, dopiero po tym prefixie właściwą nazwę klasy. Zapis ten rozpoczęliśmy jednak od backslasha (\) - co to oznacza? Oznacza to to, że pierwszy backslash zawsze oznacza przestrzeń główną, bazową, tą położoną najwyżej w hierarchi. Jej nazwa jest pusta, więc podajemy ją jedynie za pomocą jednego backslasha na początku.&lt;br /&gt;&lt;br /&gt;Wykonajmy teraz podobny manewr co wcześniej i stwórzmy drugą, identyczną klasę o nazwie &#39;Users&#39;, ale w innej przestrzeni nazw. Stwórzmy np. plik &#39;other_classes/Users.php&#39; i wpiszmy do niego to samo co w poprzedniej klasie &#39;Users&#39;, zmieńmy jednak jego przestrzeń nazw:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// other_classes/Users.php&lt;br /&gt;&lt;br /&gt;namespace MyApp\OtherUsers;&lt;br /&gt;&lt;br /&gt;class Users {&lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function MyMethodName()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return __METHOD__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public function MyClassName()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return __CLASS__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;&lt;br /&gt;&amp;nbsp; public static function SayHello()&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return &#39;Hi, I\&#39;m users class: &#39; . __CLASS__;&lt;br /&gt;&amp;nbsp; } &lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Załączmy definicję klasy do naszego &#39;index.php&#39; i zobaczmy co się stanie:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;require_once(&#39;classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni MyApp/Users)&lt;br /&gt;require_once(&#39;other_classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni MyApp/OtherUsers)&lt;br /&gt;echo \MyApp\Users\Users::SayHello(); // WYNIK: Hi, I&#39;m users class: MyApp\Users\Users&lt;br /&gt;echo &#39;&amp;lt;br /&amp;gt;&#39;;&lt;br /&gt;echo \MyApp\OtherUsers\Users::SayHello(); // WYNIK: Hi, I&#39;m users class: MyApp\OtherUsers\Users&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Jak widać - tym razem nie spowodowaliśmy błędu załączając dwie identyczne klasy o takich samych nazwach. Stało się to dlatego, iż obie klasy &#39;Users&#39; istnieją w oddzielnych przestrzeniach nazw.&lt;br /&gt;Dostęp do każdej z nich natomiast uzyskujemy za pomocą podania ich przestrzeni nazw przed właściwą nazwą.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;USE&lt;/h2&gt;Dostęp do klasy lub funkcji z danej przestrzeni nazw można uzyskać również w formie prostrzej, wykorzystując do tego celu dyrektywę &#39;use&#39;. Na czym to polega? Otóż dyrektywa &#39;use&#39; podana w kodzie informuje PHP o tym, z jakiej przestrzeni nazw obecnie chcemy korzystamy. Prześledźmy to na przykładzie, modyfikując nasz plik &#39;index.php&#39;:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;use MyApp\Users\Users; // informujemy o używaniu przestrzeni \MyApp\Users&lt;br /&gt;require_once(&#39;classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni MyApp/Users)&lt;br /&gt;require_once(&#39;other_classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni MyApp/OtherUsers)&lt;br /&gt;&lt;br /&gt;echo Users::SayHello(); // WYNIK: Hi, I&#39;m users class: MyApp\Users\Users&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Jak widać powyżej, poinformowaliśmy PHP o tym, że korzystamy obecnie z przestrzeni &#39;\MyApp\Users&#39; i dzięki temu w odwołaniu do klasy &#39;Users&#39; nie musimy już podawać jej przestrzeni nazw.&lt;br /&gt;Dyrektywa use zaczyna obowiązywać od miejsca jej użycia w kodzie.&lt;br /&gt;Co za tym idzie, zapis:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;require_once(&#39;classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni MyApp/Users)&lt;br /&gt;require_once(&#39;other_classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni MyApp/OtherUsers)&lt;br /&gt;&lt;br /&gt;echo Users::SayHello();&lt;br /&gt;use MyApp\Users\Users;&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;będzie niepoprawny i spowoduje błąd.&lt;br /&gt;&lt;br /&gt;Po słowie &#39;use&#39; nie podajemy backslasha na początku nazwy.&lt;br /&gt;Możemy jednocześnie korzystać z kilku przestrzeni nazw, podając je po przecinku, wg zasady:&lt;br /&gt;[code]use namespace1, namespace2, namespace3.....;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Aliasy nazw&lt;/h2&gt;Istnieje jeszcze jedno ciekawe usprawnienie związane z przestrzeniami nazw, mianowicie aliasy nazw. Wyobraźmy sobie, że stworzyliśmy sobie długą, hierarchiczną przestrzeń nazw:&lt;br /&gt;&lt;br /&gt;[code]MyApp\UsersAccounts\Actions\AddUsers[/code]&lt;br /&gt;&lt;br /&gt;a w niej dopiero klasę o nazwie &#39;Users&#39;.&lt;br /&gt;&lt;br /&gt;Wywołanie tej klasy w naszym kodzie będzie dość długie, np:&lt;br /&gt;&lt;br /&gt;[code]$user = new \MyApp\UsersAccounts\Actions\AddUsers\Users;[/code]&lt;br /&gt;&lt;br /&gt;Aby nie pisać tak długich konstrukcji (a przecież mogą być jeszcze dłuższe) wykorzystamy aliasy, czyli chwilowe zastąpienie nazwy naszej przestrzeni za pomocą skróconej nazwy pod jaką będzie ona dostępna w kodzie. Użycie aliasu wygląda następująco:&lt;br /&gt;[code]use NAZWA_PRZESTRZENI as ALIAS[/code]&lt;br /&gt;&lt;br /&gt;w naszym przypadku zróbmy więc:&lt;br /&gt;[code]use MyApp\UsersAccounts\Actions\AddUsers as U;[/code]&lt;br /&gt;&lt;br /&gt;Od tej chwili do przestrzeni &#39;MyApp\UsersAccounts\Actions\AddUsers&#39; możemy odwoływać się stosując formę skróconą &#39;U&#39;. Prześledźmy w praktyce (zakładając, że dołączamy klasę z przestrzeni MyApp\UsersAccounts\Actions\AddUsers):&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;use MyApp\UsersAccounts\Actions\AddUsers as U; // informujemy o używaniu przestrzeni&amp;nbsp;MyApp\UsersAccounts\Actions\AddUsers&amp;nbsp;pod&amp;nbsp;aliasem U&lt;br /&gt;require_once(&#39;classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni nazw MyApp\Users\Actions\AddUsers)&lt;br /&gt;&lt;br /&gt;echo U\Users::SayHello(); // WYNIK: Hi, I&#39;m users class: MyApp\UsersAccounts\Actions\AddUsers\Users&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Możemy też stworzyć alias bezpośrednio dla klasy (pamiętajmy, że sposób działa tylko dla klas, dla funkcji i zmiennych nie zadziała!):&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;// index.php&lt;br /&gt;&lt;br /&gt;use MyApp\UsersAccounts\Actions\AddUsers\Users as Obj; // tworzymy alias do klasy&lt;br /&gt;require_once(&#39;classes/Users.php&#39;); // dołączamy klasę Users (z przestrzeni nazw&amp;nbsp;MyApp\UsersAccounts\Actions\AddUsers)&lt;br /&gt;&lt;br /&gt;echo Obj::SayHello(); // WYNIK: Hi, I&#39;m users class: MyApp\UsersAccounts\Actions\AddUsers\Users&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;__autoload&lt;/h2&gt;Jak zapewne już zauważyliśmy, hierarchiczne nazewnictwo przestrzeni nazw przypomina coś co znamy na codzień - strukturę folderów. Spostrzeżenie jak najbardziej poprawne, gdyż właśnie w ten sposób jest to wykorzystywane. Standardem w obecnych frameworkach jest rozmieszczenie plików z klasami w folderach odpowiadającym ich hierarchicznej strukturze. Przykładowo, klasę &#39;Users&#39; zdeklarowaną w przestrzeni nazw &#39;MyApp\UsersAccounts\Actions\AddUsers zapisujemy&#39; w folderze &#39;/classes/MyApp/UsersAccounts/Actions/AddUsers/&#39;:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;classes&lt;br /&gt;|__MyApp&lt;br /&gt;| &amp;nbsp;|__UsersAccounts&lt;br /&gt;| &amp;nbsp;| &amp;nbsp;|__Actions&lt;br /&gt;| &amp;nbsp;| &amp;nbsp; &amp;nbsp; |__AddUsers&lt;br /&gt;| &amp;nbsp;| &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|__Users.php&lt;br /&gt;&lt;br /&gt;Jest to bardzo wygodne, proste i efektywne rozwiązanie - pozwala zachować strukturę umiejscowienia naszych plików z klasami odpowiadającą ich nazewnictwu w przestrzeni nazw.&lt;br /&gt;Ponadto jest to pomocne również dla samego programisty, który &quot;z automatu&quot; już wie, gdzie należy szukać definicji danej klasy. Rozwiązanie takie stosuje m.in. framework Symfony.&lt;br /&gt;&lt;br /&gt;Wykorzystajmy więc teraz funkcję &#39;__autoload()&#39; do zautomatyzowania sobie procesu dołączania naszych klas.&lt;br /&gt;Na początek prześledżmy jak wygląda taki standardowy &#39;__autoload()&#39; dla zwykłych klas:&lt;br /&gt;&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;function __autoload($class_name)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp; require_once(&#39;classes/&#39; . $class_name. &#39;.php&#39;);&lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Usprawnijmy więc jego działanie, tak aby podążał za hierarchią naszej przestrzeni nazw w folderach:&lt;br /&gt;[code]&lt;br /&gt;&amp;lt;?php&lt;br /&gt;function __autoload($class_name)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;$path_to_class = &#39;classes/&#39; . str_replace(&#39;\\&#39;, DIRECTORY_SEPARATOR, $class_name) . &#39;.php&#39;;&lt;br /&gt;&amp;nbsp; require_once($path_to_class); &lt;br /&gt;}&lt;br /&gt;?&amp;gt;&lt;br /&gt;[/code]&lt;br /&gt;&lt;br /&gt;Jak widzimy, wszystkie backslashe są zamieniane na slashe rozdzielające nam ścieżkę do pliku z klasą.&lt;br /&gt;I tak, np. wywołanie klasy &#39;Users&#39; z przestrzeni nazw:&lt;br /&gt;[code]MyApp\UsersAccounts\Actions\AddUsers[/code]&lt;br /&gt;spowoduje, że funkcja __autoload() załaduje nam definicję klasy z pliku:&lt;br /&gt;[code]/classes/MyApp/UsersAccounts/Actions/AddUsers/Users.php[/code]&lt;br /&gt;&lt;br /&gt;Jak widać rozwiązanie jest proste i zarazem bardzo efektywne.&lt;br /&gt;Ze swojej strony gorąco polecam stosowanie przestrzeni nazw nawet w mniejszych projektach, aby wyrobić sobie nawyk ich używania, gdyż przy większych projektach korzystanie z przestrzeni nazw jest wręcz konieczne.&lt;br /&gt;&lt;br /&gt;Poza tym, w roku 2009 została po raz pierwszy obuplikowana konwencja o nazwie PSR-0, która jasno określa sposoby nazewnictwa przestrzeni nazw i odpowiedniego rozmieszczenia klas w folderach projektu. Konwencja ta ustala pewne reguły, dzięki którym nie występuje kolizja pomiędzy poszczególnymi aplikacjami, szczególnie tyczy to się funkcji __autoload().&lt;br /&gt;Więcej o konwencji przeczytać możecie np. tutaj:&amp;nbsp;&lt;a href=&quot;http://phpedia.pl/wiki/Konwencja_nazewnictwa_PSR-0&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://phpedia.pl/wiki/Konwencja_nazewnictwa_PSR-0&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;No i to tyle, mam nadzieję, że opisałem cały mechanizm prosto i zrozumiale, zachęcam do własnoręcznego eksperymentowania.</content><link rel='replies' type='application/atom+xml' href='http://phpeverywhere.blogspot.com/feeds/2394048099834356901/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-namespaces-przestrzenie-nazw-w-php.html#comment-form' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/2394048099834356901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4106195950283171870/posts/default/2394048099834356901'/><link rel='alternate' type='text/html' href='http://phpeverywhere.blogspot.com/2015/05/php-namespaces-przestrzenie-nazw-w-php.html' title='[PHP] Namespaces - przestrzenie nazw w PHP'/><author><name>Marcin Szczygliński</name><uri>https://plus.google.com/114751653321349063487</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh3.googleusercontent.com/-VKXRY8wQsJY/AAAAAAAAAAI/AAAAAAAAHf8/mvNNdldc80k/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-QLaNhRpjR38/VWD0pbQxHQI/AAAAAAAAH8c/eR32_BuZO8I/s72-c/icoPHP_ADVANCED.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>