<?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>Athlan • Piotr Pelczar • blog programisty &#187; Publikacje</title>
	<atom:link href="http://athlan.pl/kategoria/publikacje/feed/" rel="self" type="application/rss+xml" />
	<link>http://athlan.pl</link>
	<description>Napisać kod zrozumiały dla komputera potrafi byle głupek. Dobrzy programiści tworzą kod zrozumiały dla człowieka...</description>
	<lastBuildDate>Sat, 17 Jul 2010 18:54:07 +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>jQuery Animate i Easing</title>
		<link>http://athlan.pl/jquery-animate-i-easing/</link>
		<comments>http://athlan.pl/jquery-animate-i-easing/#comments</comments>
		<pubDate>Sat, 08 May 2010 08:17:41 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[JS/Ajax]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[interface]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=457</guid>
		<description><![CDATA[Nie można kwestionować faktu, że jQuery.animate() jest jednym z najbardziej potężnych narzędzi jQuery. Służy on do animowania atrybutów CSS (czyli zmiany ich wartości w czasie od obecnego stanu A do definiowanego stanu B). Najprostszą implementacją jQuery Animate jest podanie zbioru atrybutów CSS, które mają ulec zmianie oraz czasu, w jakim ta zmiana ma nastąpić. Nie będę się [...]]]></description>
			<content:encoded><![CDATA[<p>Nie można kwestionować faktu, że <code><a href="http://api.jquery.com/animate/">jQuery.animate()</a></code> jest jednym z najbardziej potężnych narzędzi <strong>jQuery</strong>. Służy on do animowania <strong>atrybutów CSS</strong> (czyli zmiany ich wartości w czasie od obecnego stanu A do definiowanego stanu B). Najprostszą implementacją <strong>jQuery Animate</strong> jest podanie zbioru atrybutów CSS, które mają ulec zmianie oraz czasu, w jakim ta zmiana ma nastąpić. Nie będę się zagłębiał w najprostsze przykłady użycia, <a rel="nofollow" href="http://api.jquery.com/animate/">są one dostępne w oficjalnej dokumentacji</a> jQuery.</p>
<p>Należy pamiętać, że dzięki jQuery jesteśmy w stanie nie tylko płynnie zmieniać kolory, wielkość czcionki, obramowanie, ale także pozycje elementów, nadając stronie dynamicznego kształtu. Domyślnym sposobem animowania (<em>easing</em>) jest płynne przechodzenie. Istnieje natomiast sposób na zmianę adaptera animowania. Robert Penner &#8211; autor pluginu <a rel="nofollow" href="http://gsgd.co.uk/sandbox/jquery/easing/"><strong>jQuery Easing</strong></a> dostarczył nam niewiarygodnie efektowne i proste w implementacji narzędzie. Na oficjalnej stronie pluginu można znaleźć <a rel="nofollow" href="http://gsgd.co.uk/sandbox/jquery/easing/">wiele przykładów animacji</a>, które dostarcza nam dodatek. Efekty widoczne są zwłaszcza przy animowaniu pozycji i wymiarów obiektu, ale następują także w przypadku zmiany koloru &#8211; czyli są aplikowane do zmiany stanu każdego z atrybutów CSS.</p>
<p>Dziś postaram się pokazać efekty, jakie można uzyskać za pomocą <strong>jQuery Animate</strong> rozszerzonego o <strong>jQuery Interface</strong> oraz <strong>Easing</strong>.</p>
<ul>
<li><a href="http://athlan.pl/code/jQueryAnimateEasing/">Przykład różnego rodzaju easingu</a>.</li>
</ul>
<p>Pierwszym krokiem jest wygenerowanie własnej biblioteki <a href="http://jqueryui.com/download">jQuery Interface</a>. Dzięki generatorowi, jesteśmy w stanie ściągnąć tylko te części Interface, które są nam de facto potrzebne, zmniejszając jednocześnie ilość kodu. Klikamy &#8216;deselect all components&#8217;, a w sekcji <em>Effects</em> wybieramy efekty, których będziemy używać. Mnie w tej chwili interesuje <em>Bounce</em> i <em>Slide</em>. W paczce otrzymamy wersję deweloperską (z wcięciami) oraz <em>minified</em>, gotową do publikacji na serwerze.</p>
<p>Do wykorzystania efektu slideowania a&#8217;la iPhone (elastyczne odbicie od krawędzi ściany ekranu) sprowadza się drobny kawałek kodu, w którym istotnym jest parametr <em>easing</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">$<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#example'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">animate</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> left<span style="color: #339933;">:</span> <span style="color: #CC0000;">500</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span> duration<span style="color: #339933;">:</span> <span style="color: #CC0000;">1000</span><span style="color: #339933;">,</span> easing<span style="color: #339933;">:</span> <span style="color: #3366CC;">'easeOutElastic'</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p>Na pewno komuś się przyda.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/jquery-animate-i-easing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Chmura tagów Tagcloud w PHP</title>
		<link>http://athlan.pl/chmura-tagow-tagcloud-php/</link>
		<comments>http://athlan.pl/chmura-tagow-tagcloud-php/#comments</comments>
		<pubDate>Sun, 07 Mar 2010 19:12:21 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[tagcloud]]></category>
		<category><![CDATA[tagi]]></category>
		<category><![CDATA[tags]]></category>
		<category><![CDATA[web2.0]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=439</guid>
		<description><![CDATA[Ostatnio byłem zobligowany napisać nową klasę tagów do mojego projektu Sypacz.pl, która de facto zachowała stare API, lecz rozszerzyła swoje funkcjonalności, więc w kodzie projektu nie było wielu zmian. Wena spowodowała to, że zacząłem pisać kod od zera. Cały problem polega na tym, aby napisać na tyle elastyczną klasę tagów, która przyjmie nam zestaw danych, [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio byłem zobligowany napisać nową klasę tagów do mojego projektu <a href="http://sypacz.pl">Sypacz.pl</a>, która de facto zachowała stare API, lecz rozszerzyła swoje funkcjonalności, więc w kodzie projektu nie było wielu zmian. Wena spowodowała to, że zacząłem pisać kod od zera.</p>
<p>Cały problem polega na tym, aby napisać na tyle elastyczną klasę tagów, która przyjmie nam zestaw danych, a następnie zaprezentować ją w formie chmury, czym zaopiekuje się arkusz stylów CSS:</p>
<p><code>Nazwa tagu => Ilość występowań</code></p>
<p>Parę osób mnie pytało, jak wyciągnąć takie informacje z bazy danych:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">SELECT tag_name<span style="color: #339933;">,</span> <span style="color: #990000;">COUNT</span><span style="color: #009900;">&#40;</span>tag_name<span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">AS</span> tag_times FROM tags GROUP BY tag_name ORDER BY tag_times LIMIT <span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">50</span></pre></div></div>

<p>Wykorzystałem obiekt <a href="http://athlan.pl/code/Attribute.Class">Vframe_Attribute</a>, aby ustandaryzować komponent względem pozostałych w moim frameworku. Jeżeli ktoś nie chce używać obiektu Attribute, może w prosty sposób przekształcić klasę tagów, otrzymując ten sam efekt, deklarując tylko atrybut chroniony <code>protected $_aAttributes = array();</code>. Temat chmury tagów wydaje mi się na tyle trywialny, że nie ma się co nad nim zbyt wiele rozwodzić, zamieszczę tylko klasę i opiszę krótko w przykładach jej możliwości.</p>
<ul>
<li><a href="http://athlan.pl/code/Tagcloud.Class">Vframe_Tagcloud</a> &#8211; klasa tagów,</li>
<li><a href="http://athlan.pl/code/Attribute.Class"> Vframe_Attribute</a> &#8211; pomocnicza klasa atrybutów dla stosu $_aAttributes, dziedziczenie można usunąć i zadeklarować atrybut samemu.</li>
</ul>
<p>Aby stworzyć nowy obiekt tagów, po prostu wywołujemy konstruktor:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$oCloud</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Vframe_Tagcloud<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Konstruktor nie przyjmuje żadnych argumentów, wiec możemy od razu przejść do podawania obiektowi tagów. W tym miejscu warto nadmienić, że każdy znak jest rozróżniany (ze względów elastycznych), więc jeżeli chcesz, aby Nazwatagu oraz nazwatagu były rozpoznawane jako jeden klucz, wypadałoby użyć funkcji <a href="http://php.net/strtolower">strtolower</a> lub <a href="http://php.net/mb_strtolower">mb_strtolower</a> (dla Multibyte Strings):</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$iKey</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_times'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Najistotniejszą częścią klasy jest sposób renderowania chmury, które może działać w dwóch trybach:</p>
<ul>
<li><strong>Tryb prosty</strong> zwraca nam nazwę tagu oraz jego wagę po przeliczeniu w formie liczby.</li>
<li><strong>Tryb zaawansowany</strong> zwraca nam nazwę tagu oraz tablicę z danymi:
<ul>
<li><code>level</code> &#8211; waga tagu po przeliczeniu,</li>
<li><code>count</code> &#8211; ilość występowań, taka jaką podaliśmy,</li>
<li><code>count_percentage</code> &#8211; informacja, w jakiej procentowej części ilości występowań znajduje się tag, przyjmując za 100% tag, który występuje najczęściej.</li>
</ul>
</li>
</ul>
<p>Aby w prosty sposób wyrenderować chmurę tagów, używamy poniższego przykładu:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aDataTagsRender</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Najczęściej używa się trybu prostego. Oba tryby są dalej rozbudowane, bowiem <strong>mamy możliwość zdefiniowania zakresu i dokładności wag tagów</strong>. <u>Domyślnie wagi tagów zawierają się pomiędzy 1, a 10</u>. Możemy na przykład przyjąć, że najmniejszą wagą jest liczba 3, największą 5, a precyzja wag tagów to 2 miejsca po przecinku:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aDataTagsRender</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>W celu uniknięcia precyzji po przecinku (chcemy otrzymać liczby całkowite), ustawimy precyzję na 0.</p>
<p>Aby wywołać tryb zaawansowany, musimy podać 4 argument dla metody <code>render()</code> i ustawić go na <code>true</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aDataTagsRender</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">5</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Warto w tym miejscu nadmienić, że tagi mogą nie być posortowane alfabetycznie (co ma miejsce podczas tworzenia chmury tagów). Wystarczy wywołać funkcję <code>ksort</code> (key sort).</p>
<p>Finalny przykład używania klasy tagów, celem wywołania klas CSS level_X, gdzie X to liczba całkowita z zakresu od 1 do 10, resztę robi CSS (kolorowanie, nakładanie rozmiaru):</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
<span style="color: #000088;">$oCloud</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Vframe_Tagcloud<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$iKey</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#41;</span>
  <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">add</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">strtolower</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_name'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$aRow</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'tag_times'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$aDataTags</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$oCloud</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">render</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">ksort</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aDataTags</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sTag</span> <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$iTag</span><span style="color: #009900;">&#41;</span>
  <span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">'&lt;a href=&quot;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">route</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'tag'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$sTag</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&quot; class=&quot;level_'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$iTag</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&quot;&gt;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$sTag</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&lt;/a&gt;'</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #009900;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/chmura-tagow-tagcloud-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MySQL: remove duplicate entries/rows</title>
		<link>http://athlan.pl/mysql-remove-duplicate/</link>
		<comments>http://athlan.pl/mysql-remove-duplicate/#comments</comments>
		<pubDate>Sun, 05 Jul 2009 08:02:04 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[delete]]></category>
		<category><![CDATA[duplicated]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[remove]]></category>
		<category><![CDATA[rows]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=332</guid>
		<description><![CDATA[Usuwając coś permanentnie z bazy danych musimy być bardzo ostrożni, bowiem przywrócenie danych jest bardzo trudne, czasem niemożliwe. Podstawową strukturę bazy danych powinno się budować na samym początku tworzenia aplikacji, z biegiem czasu rozbudowywać ją, ale unikać przebudowywania. Niestety są przypadki, gdzie trzeba przebudować jedną rzecz, co powoduje zmianę w wielu warstwach nie tyle aplikacji, [...]]]></description>
			<content:encoded><![CDATA[<p>Usuwając coś permanentnie z bazy danych musimy być bardzo ostrożni, bowiem przywrócenie danych jest bardzo trudne, czasem niemożliwe. Podstawową strukturę bazy danych powinno się budować na samym początku tworzenia aplikacji, z biegiem czasu rozbudowywać ją, ale unikać przebudowywania. Niestety są przypadki, gdzie trzeba przebudować jedną rzecz, co powoduje zmianę w wielu warstwach nie tyle aplikacji, co strukturze bazodanowej.</p>
<p>Dziś postaram się opisać, jakie kroki trzeba wykonać, aby bezpiecznie usunąć zdublowane rekordy z bazy danych nie tracąc żadnych danych:</p>
<ol>
<li>Tworzymy dwie <strong>kopie bazy danych</strong> lub tabel, na których będziemy pracowali. Najlepiej, aby pracować na drugiej kopii, nigdy na oryginale, a potem wdrożyć zmiany z drugiej kopii na oryginał. Przezorny zawsze ubezpieczony.</li>
<li>Analiza danych w tabeli. Musimy dokładnie wiedzieć jakie są relacje między tabelami, kiedy występują JOIN&#8217;y itp. Jeżeli rekordy są zdublowane, a posiadają ustalony ID, do których odwołuje się inny rekord z sąsiedniej tabeli, trzeba będzie w niej zmienić ID rekord zdublowanego na ID &#8220;substytuta&#8221;, bądź takiego rekordu, który nie spowoduje zmian w serwisie.</li>
<li>Wykonanie operacji <strong>usunięcia zdublowanych rekordów</strong>.</li>
</ol>
<p>Po wykonaniu kroku pierwszego zabieramy się za kolejny. Jest to najważniejszy moment naszych operacji. Aby ułatwić zrozumienie problemu, podam przykład z życia. Aplikacja posiadała poważny błąd, który umożliwiał zdublowanie użytkowników, ściślej: można było zdublować username. Za każdym razem, gdy użytkownik się logował i pisał komentarze, był ich właścicielem, ale comment_author posiadały różne ID tego samego użytkownika. Zaraz po skopiowaniu bazy danych spróbowałem przepisać ID autorów komentarzy na pierwszy rekord identyfikujący użytkownika, jaki istnieje w tabeli użytkowników. Skonstruowałem zapytanie:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> cms_comments
<span style="color: #993333; font-weight: bold;">JOIN</span> cms_members <span style="color: #993333; font-weight: bold;">AS</span> user_original <span style="color: #993333; font-weight: bold;">ON</span><span style="color: #66cc66;">&#40;</span>user_original<span style="color: #66cc66;">.</span>user_id <span style="color: #66cc66;">=</span> comment_author<span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">SET</span> comment_author <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #993333; font-weight: bold;">SELECT</span> user_first<span style="color: #66cc66;">.</span>user_id <span style="color: #993333; font-weight: bold;">FROM</span> cms_members <span style="color: #993333; font-weight: bold;">AS</span> user_first
  <span style="color: #993333; font-weight: bold;">WHERE</span> user_first<span style="color: #66cc66;">.</span>user_name <span style="color: #66cc66;">=</span> user_original<span style="color: #66cc66;">.</span>user_name
  <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> user_first<span style="color: #66cc66;">.</span>user_id <span style="color: #993333; font-weight: bold;">ASC</span> <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Usunięcie zdublowanych użytkowników było już tylko formalnością. Teraz się okaże, dlaczego zależało mi na wyciągnięciu dokładnie pierwszego rekordu reprezentującego &#8220;unikalnego&#8221; użytkownika: poniższe zapytanie (<strong>ALTER IGNORE TABLE ADD UNIQUE</strong>) usunie wszystkie kolejne rekordy oznaczone jako <strong>duplicated</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">IGNORE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> cms_members <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">UNIQUE</span> <span style="color: #993333; font-weight: bold;">INDEX</span><span style="color: #66cc66;">&#40;</span>user_name<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Krótki komentarz z manuala do <strong>ALTER TABLE</strong>:</p>
<blockquote><p><strong>IGNORE</strong> is a <span style="text-decoration: underline;">MySQL extension to standard SQL</span>. It controls how ALTER TABLE works if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, <span style="text-decoration: underline;">only the first row is used of rows with duplicates on a unique key</span>, The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.</p></blockquote>
<p>Pisząc ostatnie posty związane z bazami danych, mam nadzieję, że komuś się przydadzą.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysql-remove-duplicate/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Przypadki w MySQL &#8211; CASE WHEN THEN ELSE END</title>
		<link>http://athlan.pl/mysql-case-when-then-else-end/</link>
		<comments>http://athlan.pl/mysql-case-when-then-else-end/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 13:15:07 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[Add new tag]]></category>
		<category><![CDATA[case]]></category>
		<category><![CDATA[conditions]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[syntax]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=299</guid>
		<description><![CDATA[Podobnie jak w PHP, baza danych MySQL ma odpowiednik if, czyli przypadków (inaczej serii warunków, instrukcji warunkowych). Różnicą między implementacją CASE&#8216;a w MySQL i ifa PHP jest to, że baza danych zwraca konkretną wartość z case&#8217;a, a nie wykonuje dowolnej ilości dowolnych akcji. CASE Syntax: Najprostsza struktura CASE&#8217;aprzedstawia się nastepująco: CASE WHEN [conditions] THEN ... ELSE [...]]]></description>
			<content:encoded><![CDATA[<p>Podobnie jak w PHP, baza danych MySQL ma odpowiednik <a href="http://pl2.php.net/manual/en/control-structures.if.php">if</a>, czyli przypadków (inaczej serii warunków, instrukcji warunkowych). Różnicą między implementacją <a href="http://dev.mysql.com/doc/refman/5.0/en/case-statement.html">CASE</a>&#8216;a w MySQL i ifa PHP jest to, że baza danych zwraca konkretną wartość z case&#8217;a, a nie wykonuje dowolnej ilości dowolnych akcji.</p>
<p><strong>CASE Syntax:</strong></p>
<p>Najprostsza struktura CASE&#8217;aprzedstawia się nastepująco:</p>
<p><code>CASE WHEN [conditions] THEN ... ELSE ... END</code></p>
<p>Składnia powinna rozpocząć się słowem kluczowym CASE, a zakończyć END. Pomiędzy znajdują się warunki WHEN oraz operacja zwrócenia odpowiedniej wartości, która po nich następuje THEN (mamy możliwość uwzględnić nieskończenie wiele warunków). Jeżeli żaden warunek nie zostanie spełniony możemy użyć opcjonalnie ELSE.</p>
<p><strong>Przykłady z życia.</strong></p>
<p>Wyobraźmy sobie, że mamy posortować listę aukcji przedmiotów na Allegro od najtańszych, do najdroższych. Należy założyć, że są 2 typy aukcji: kup teraz i licytacja. Pole licytacji w bazie danych zawiera największą zaproponowaną kwotę przez użytkowników w procesie licytacji, a cena kup teraz ustalana jest przez sprzedającego. Są to dwa różne pola w bazie danych, a jedno kryterium sortowania, dlatego trzeba scalić cenę w jedną, wybierając odpowiednią. Musimy przewidzieć sytuację, w której aukcja jest typu kup teraz oraz licytacji, wówczas jeżeli najwyższa oferta jest większa od ceny kup teraz, wówczas wybieramy pole z największa propozycją:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">&#40;</span>
  CASE
    WHEN <span style="color: #66cc66;">&#40;</span>auction_type <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'bidding'</span> <span style="color: #993333; font-weight: bold;">OR</span> auction_price_bid <span style="color: #66cc66;">&gt;</span> auction_price_buynow<span style="color: #66cc66;">&#41;</span>
      THEN auction_price_bid
    ELSE auction_price_buynow
  END<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> auction_price</pre></div></div>

<p>Stworzyliśmy pole auction_price, po którym można sortować aukcje od najtańszej do najdroższej i na odwrót.</p>
<p>Mam nadzieję, że krótki wpis przyda się początkującym. <span style="color: #c0c0c0;">Nic więcej nie trzeba opisywać, temat wydaje się co najmniej trywialny.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysql-case-when-then-else-end/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>MVC &#8211; Model</title>
		<link>http://athlan.pl/mvc-model/</link>
		<comments>http://athlan.pl/mvc-model/#comments</comments>
		<pubDate>Mon, 09 Mar 2009 15:21:19 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[batabae]]></category>
		<category><![CDATA[baza danych]]></category>
		<category><![CDATA[dane]]></category>
		<category><![CDATA[last.fm]]></category>
		<category><![CDATA[model]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[wzorce projektowe]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=258</guid>
		<description><![CDATA[Powstało masę artykułów na temat MVC, temat staje się naprawdę oklepany. Postanowiłem zebrać wszystkie informacje w jedno miejsce i streścić je w jednym artykule uzupełniając go o informacje, które nabyłem z własnego doświadczenia oraz zwracając uwagę na najistotniejsze informacje. Czym jest model Model to jedna z warstw wzorca projektowego MVC, który odpowiada logikę biznesową, czyli [...]]]></description>
			<content:encoded><![CDATA[<p>Powstało <a href="http://phpedia.pl/wiki/MVC">masę artykułów</a> na temat <strong>MVC</strong>, temat staje się naprawdę <em>oklepany</em>. Postanowiłem zebrać wszystkie informacje w jedno miejsce i streścić je w jednym artykule uzupełniając go o informacje, które nabyłem z własnego doświadczenia oraz zwracając uwagę na najistotniejsze informacje.</p>
<p><strong>Czym jest model</strong></p>
<p><strong>Model </strong>to jedna z warstw wzorca projektowego <strong>MVC</strong>, który odpowiada logikę biznesową, czyli pozyskiwanie oraz modelowanie danych pozyskanych ze źródła danych. Na samym wstępie brzmi to bardzo abstrakcyjnie. W myśl architektury MVC, <span style="text-decoration: underline;">dostęp</span> do modelu <span style="text-decoration: underline;">powinien mieć tylko kontroler</span>, a w żadnym wypadku widok. Dodatkowo model musi pobrać i modelować dane w taki sposób, <span style="text-decoration: underline;">aby można było go ewentualnie wymienić bez jakiejkolwiek ingerencji w kontroler</span>, a co za tym idzie – widok. Niezależnie od tego, z jakiego źródła informacji korzysta (pliki tekstowe, bazy danych, pliki XML)  kontroler powinien otrzymać maksymalnie zbliżone dane podczas wymiany źródła informacji.</p>
<p style="text-align: center;"><a href="http://athlan.pl/wp-content/uploads/mvc-model.png"><img class="aligncenter size-medium wp-image-259" style="border: 0pt none;" title="mvc-model" src="http://athlan.pl/wp-content/uploads/mvc-model-265x300.png" alt="mvc-model" width="265" height="300" /></a></p>
<p><strong>Model != baza danych</strong></p>
<p>Często spotykam się z definicją modelu jako źródłem połączenia i wykonywania zapytań do serwera bazy danych. Otóż nie jest to prawdą. Według ideologii MVC model powinien być jedynie pośrednikiem między warstwą aplikacji przeznaczoną do połączenia do bazy danych, wykonywania zapytań itp., a kontrolerem. Dodatkowo powinien pomóc kontrolerowi w zbudowaniu zapytania do źródła informacji (pobranie danych na podstawie kryteriów), zmodelować je i zwrócić. Dlaczego model nie jest połączeniem do bazy danych? Jeżeli model potraktujemy jako pośrednika między kontrolerem a źródłem danych, ma on prawo wybrać dowolny sposób uzyskania żądanych informacji. Wcale nie oznacza to, że model musi używać baz danych, ale może użyć plików XML lub API udostępniane przez konkretny serwis (np. YouTube)</p>
<p><strong>Wymienialność modeli i modelowanie danych</strong></p>
<p>Modelowanie informacji jest to dostosowanie ich do użytku przez kontroler. Zazwyczaj jest to przekazywanie informacji w postaci tablic, wartości logicznych, liczb i ciągów znaków. Przykładem może być pobieranie informacji z bazy danych. Kontroler de facto nie wie skąd są pobierane dane, wie to tylko model, otrzymuje suche informacje. Jak rozumieć modelowanie danych przy projektowaniu aplikacji? Wyobraźmy sobie sytuację, że zmieniamy źródło informacji z bazy danych na pliki XML. W tym przypadku kontroler <span style="text-decoration: underline;">powinien otrzymać rekordy danych jako tablica o tych samych kluczach i tych samych typach danych</span>, jak miało to miejsce przy używaniu bazy danych. <span style="text-decoration: underline;">Wymiana modelu odbywa się bez ingerowania w kontroler</span>.</p>
<p><strong>Przykłady modeli</strong></p>
<p>Najpopularniejszym sposobem pozyskania informacji jest połączenie do bazy danych i pobieranie (reprezentowanie) ich na różnoraki sposób. Doskonale wyjaśnia to tekst znajdujący się w wikipedii:</p>
<p style="padding-left: 30px;">Frameworki MVC do operacji na bazach danych używają modeli i mapowania relacyjno-obiektowego, <a class="mw-redirect" title="ORM" href="http://pl.wikipedia.org/wiki/ORM">ORM</a> (ang. <em>object-relationship mapping</em>) &#8211; w Railsach jest to ActiveRecord, w Catalyscie np. DBIx::Class, a framework <a title="Spring Framework" href="http://pl.wikipedia.org/wiki/Spring_Framework">Spring</a> w Javie używa Hibernate. Zwykle jest też możliwe użycie baz danych przez bezpośrednie zapytania <a title="SQL" href="http://pl.wikipedia.org/wiki/SQL">SQL</a>. Użycie modeli upraszcza typowe operacje &#8211; wyświetlanie ze stronicowaniem, edycję danych, a także uniezależnia od konkretnego typu bazy danych.</p>
<p>Posiadam przykład od siebie. Źródłem danych jest API serwisu Last.fm:</p>
<ul>
<li><a href="http://athlan.pl/code/ModelLastfmApi">Model</a> informacji o utworze.</li>
<li><a href="http://athlan.pl/code/ModelLastfmApiAbstract">Klasa abstrakcyjna modelu</a> opartego o API Last.fm (oparty na klasie bazowej modelu frameworka).</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mvc-model/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>jQuery form post ajax request</title>
		<link>http://athlan.pl/jquery-form-post-ajax-request/</link>
		<comments>http://athlan.pl/jquery-form-post-ajax-request/#comments</comments>
		<pubDate>Sun, 22 Feb 2009 09:48:46 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[JS/Ajax]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[request]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=232</guid>
		<description><![CDATA[Już kiedyś interesowałem się jQuery, ale w związku z podjęciem się nowego, dużego projektu postanowiłem pogłębić swoją wiedzę i pobawić się tą biblioteką. Jako, że klient ma bzika na punkcie przeładowań ajax postanowiłem zaimplementować automatyczne przesyłanie formularzy w tle i wklejanie w &#60;body&#62; response żądania. Od strony PHP sprawa wygląda bardzo prosto &#8211; jeżeli request [...]]]></description>
			<content:encoded><![CDATA[<p>Już kiedyś interesowałem się <strong>jQuery</strong>, ale w związku z podjęciem się nowego, dużego projektu postanowiłem pogłębić swoją wiedzę i pobawić się tą biblioteką.</p>
<p>Jako, że klient ma bzika na punkcie przeładowań <strong>ajax</strong> postanowiłem zaimplementować automatyczne przesyłanie formularzy w tle i wklejanie w <code>&lt;body&gt;</code> response żądania. Od strony PHP sprawa wygląda bardzo prosto &#8211; jeżeli <strong>request</strong> został wysłany przez jQuery, wyświetlamy tylko to, co jest pomiędzy <code>&lt;body&gt;</code> i <code>&lt;/body&gt;</code>. Po wysłaniu requesta, jQuery powinno wkleić wynik do body na naszej stronie.</p>
<p>Przykładu nie będę tłumaczył, bo wydaje mi się trywialny.</p>
<ul>
<li><a href="/code/live/jQueryAjaxPostForm/">Live demo</a></li>
<li><a href="/code/live/jQueryAjaxPostForm/jquery.autoload.js">jquery.autoload</a></li>
<li><a href="/code/jQueryAjaxPostForm">index.php</a></li>
</ul>
<p>Dodatkowe ficzery:</p>
<ul>
<li>disable submita do momentu, aż ajax nie otrzyma odpowiedzi (aby użytkownik nie mógł kliknąć drugi raz),</li>
<li>automatyczne wykrywanie adresu URL, do którego odnosi się formularz (jeżeli nie sprecyzowano atrybutu <code>action</code>, wówczas wysyłamy żądanie do <code>window.location</code>).</li>
</ul>
<p>Aby nasz formularz zaczął przesyłać dane w tle wystarczy dołączyć plik <code>jquery.autoload</code>, a w kodzie napisać:</p>
<pre>$(document).ready(function() {  InitAjaxPost(' ... SUBMIT_ID ... '); });</pre>
<p>Ten sposób nie rozwiązuje przesyłania pól typu <code>file</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/jquery-form-post-ajax-request/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Wzorzec projektowy Registry w PHP</title>
		<link>http://athlan.pl/wzorzec-registry-php/</link>
		<comments>http://athlan.pl/wzorzec-registry-php/#comments</comments>
		<pubDate>Sat, 17 Jan 2009 22:22:54 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[registry]]></category>
		<category><![CDATA[wzorce projektowe]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=195</guid>
		<description><![CDATA[Registry to wzorzec projektowy, który ma za zadanie przechowywać i udostępniać dane w obrębie aplikacji. Implementacja wzorca zastępuje globalny zasięg wartości zarejestrowanych w przestrzeni klasy. Różnicą globalnego zasięgu zmiennych oraz wartości ujętych w Registry jest to, że można je ściśle kontrolować (dostęp w aplikacji itd.). W tej publikacji przedstawię jedną z najprostszego wykorzystania wzorca Registry. [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Registry</strong> to <a href="http://phpedia.pl/wiki/Wzorce_projektowe">wzorzec projektowy</a>, który ma za zadanie przechowywać i udostępniać dane w obrębie aplikacji. Implementacja wzorca zastępuje globalny zasięg wartości zarejestrowanych w przestrzeni klasy. Różnicą globalnego zasięgu zmiennych oraz wartości ujętych w Registry jest to, że można je ściśle kontrolować (dostęp w aplikacji itd.). W tej publikacji przedstawię jedną z najprostszego wykorzystania wzorca Registry.</p>
<p>Głównym założeniem Registry jest globalny zasięg (pomijając już zabezpieczenia dostępowe, którymi się nie zajmujemy). Język PHP od wersji 5 obsługuje statyczne <em>static</em> wywołania metod klas, czyniąc tym samym ich globalny zasięg wraz z połączeniem ze słowem kluczowym <em>public</em>. Dla wygody &#8211; nie trzeba tworzyć instancji klasy, więc wywołanie jest bardzo proste i nie zajmuje dużo miejsca w naszym kodzie.</p>
<p>Podstawowymi funkcjonalnościami Registry będzie:</p>
<ul>
<li>dodawanie i usuwanie,</li>
<li>pobieranie</li>
</ul>
<p>&#8230;zmiennych z rejestru. Pojęcie <em>zmienna</em> jest bardzo względne. Przechowywać w rejestrze możemy praktycznie wszystkie typy zmiennych dostępnych w PHP, włączając w to typ <em><a href="http://pl.php.net/manual/pl/resource.php">resource</a> (zasoby)</em>. Registry to nic innego, jak przechowywanie zmiennych w przestrzeni jednej klasy, więc nie mamy wobec tego żadnych ograniczeń.</p>
<ul>
<li><a href="http://athlan.pl/code/RegistrySimple">Przykładowy kod najprostszej implementacji wzorca Registry</a>.</li>
<li><a href="http://athlan.pl/code/RegistrySimpleUsage">Użycie powyższej klasy <em>RegistrySimple</em></a>.</li>
</ul>
<p>Zajmiemy się teraz bardziej rozbudowanym przykładem wzorca. Wykonamy następujące operacje:</p>
<ol>
<li>Nowa klasa <em>RegistryAdvenced</em> będzie dziedziczyła z <em>RegistrySimple</em> na potrzeby metody <em>Registry()</em>.</li>
<li>Zaimplementujemy interfejsy:
<ul>
<li><a href="http://pl.php.net/manual/pl/class.iterator.php">Iterator</a></li>
<li><a href="http://pl.php.net/manual/pl/class.arrayaccess.php">ArrayAccess</a> (na potrzeby poruszania się po instancji jak po tablicy)</li>
<li><a href="http://pl.php.net/manual/pl/class.countable.php">Countable</a> (aby łatwo otrzymać liczbę przechowywanych danych)</li>
<li><a href="http://pl.php.net/manual/pl/class.serializable.php">Serializable</a> (żeby można było <a href="http://pl.php.net/manual/pl/function.serialize.php">zaserializować</a> i <a href="http://pl.php.net/manual/pl/function.unserialize.php">odserializować</a> instancję obiektu)</li>
</ul>
</li>
<li>Dodamy prywatny konstruktor, skorzystamy ze wzorca <a href="http://phpedia.pl/wiki/Singleton">Singleton</a>.</li>
</ol>
<p><a href="http://athlan.pl/code/RegistryExtended">Gotowy kod klasy <em>RegistryAdvenced</em></a>.</p>
<p>Interpretacja i rozwijanie swojego wzorca Registry jest szeroka, można na przykład zastosowac przestrzenie rejestrów, tj. tworzyć wiele rejestrów na podstawie ich instancji. Ile programistów, tyle pomysłów, ale zasada działania nie zmienia się. Zainteresowanych zapraszam do manuala, jak problem został rozwiązany w <a href="http://framework.zend.com/manual/en/zend.registry.html">Zend_Registry</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/wzorzec-registry-php/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Paginacja (stronicowanie) w PHP</title>
		<link>http://athlan.pl/paginacja-php-stronicowanie/</link>
		<comments>http://athlan.pl/paginacja-php-stronicowanie/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 18:03:37 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[mysql limit]]></category>
		<category><![CDATA[pager]]></category>
		<category><![CDATA[paginacja]]></category>
		<category><![CDATA[stronicowanie]]></category>
		<category><![CDATA[strony]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=177</guid>
		<description><![CDATA[Zaczynając swoją przygodę z PHP nie miałem pojęcia jak wykonać paginację newsów, która załamywałaby łańcuchy liczb w momencie, w których chce. Na dzień dzisiejszy postanowiłem napisać swój nowy pager, gdyż ten, który dotychczas używałem przez ostatnie 2 lata nie odpowiadał mi pod trzema względami: nagromadzenie metod, tj. setLimit(), getLimit(), zamiast pojedynczego limit(), brak możliwości ustawienia [...]]]></description>
			<content:encoded><![CDATA[<p>Zaczynając swoją przygodę z PHP nie miałem pojęcia jak wykonać paginację newsów, która załamywałaby łańcuchy liczb w momencie, w których chce. Na dzień dzisiejszy postanowiłem napisać swój nowy pager, gdyż ten, który dotychczas używałem przez ostatnie 2 lata nie odpowiadał mi pod trzema względami:</p>
<ul>
<li>nagromadzenie metod, tj. setLimit(), getLimit(), zamiast pojedynczego limit(),</li>
<li>brak możliwości ustawienia załamywania się łańcucha (domyślnie były to 2 liczby):<br />
<code>1, 2 ... 6, 7, 8 ...  12, 13</code>.</li>
<li>brak możliwości definiowania limitu, ilości elementów oraz aktualnie przeglądanej strony w jednej metodzie, najchętniej w samym konstruktorze.</li>
</ul>
<p>Ostatnio potrzebowałem zwiększyć limit liczb &#8220;z przodu&#8221; i &#8220;tyłu&#8221; oraz &#8220;w środku&#8221;:<br />
<code>1, 2, 3 ... 5, 6, 7, 8, 9 ...  11, 12, 13</code></p>
<p>Dla tych, którzy ciągle szukają komponentu obsługującego paginację prezentuję <a href="http://athlan.pl/code/Vframe_Pagination">Vframe_Pagination</a>.</p>
<p>Implementacja od strony kontrolera (metoda krótka):</p>
<p><code>$oPager = new Vframe_Pagination($iItemsCount, $iLimit, $iCurrentPage);</code></p>
<p>Metoda długa:</p>
<p><code>$oPager = new Vframe_Pagination();<br />
$oPager-&gt;limit($iLimit);<br />
$oPager-&gt;items($iItemsCount);<br />
$oPager-&gt;page($iPage);</code></p>
<p>Metody limit, items oraz page zwracają liczby odpowiadające ich nazwą niezależnie od tego, czy została podana nowa wartość w argumencie, czy nie, co jest absolutnie wygodnym (dla mnie) rozwiązaniem.</p>
<p>Aby wyświetlić oczekiwane rekordy, wykorzystujemy pagera:</p>
<p><code>$aData = $oModel-&gt;GetList($iUser, $oPager-&gt;start(), $oPager-&gt;limit());</code></p>
<p>Lub bezpośrednio w zapytaniu do bazy dancyh:</p>
<p><code>$sSql = "SELECT news_id FROM news LIMIT " . $oPager-&gt;start() . ", " . $oPager-&gt;limit();</code></p>
<p>Od strony widoku, prezentacja pagincaji prezentuje się w bardzo prosty sposób:</p>
<p>&lt;?php echo $oPager-&gt;Render(true); ?&gt;</p>
<p>Metoda render przyjmuje kolejno:</p>
<ol>
<li><em>$mMode</em> (mixed: bool, null, string), jeżeli true, paginacja jest zwracana w formacie HTML. Jeżeli null, numerki stron podane w formie array&#8217;a zamiast linków HTML. Jeżeli string, zostaje zwracana wartość po renderowaniu pagera, np. element startujący przedział mnożony po limicie: $oPager-&gt;Render(&#8216;start&#8217;);. Ten sam efekt powoduje metoda $oPager-&gt;start();</li>
<li><em>$iDrawCutLimit</em> (int) ilość numerków na początku i końcu łańcucha paginacji.</li>
<li><em>$iDrawCutLimitCenter</em> (int) ilość numerków &#8220;w środku&#8221; obok aktualnie przeglądanej strony.</li>
<li><em>$bNavigation</em> (bool) linki &#8220;poprzednia&#8221; i &#8220;następna&#8221; strona znajdujące się na początku i końcu łańcucha.</li>
</ol>
<p>Możemy sami ostylować linki generowane przez pager. Wystarczy że w widoku dodamy swój apperance:</p>
<p><code>$this-&gt;oPager-&gt;PatternPage('&lt;a href="?[$]"&gt;[$]&lt;/a&gt;');<br />
$this-&gt;oPager-&gt;PatternPageCurrent('&lt;strong&gt;[$]&lt;/strong&gt;');<br />
$this-&gt;oPager-&gt;PatternPageNavigation('&lt;a href="?[$]" rel="nofollow"&gt;[$$]&lt;/a&gt;', array('&amp;laquo; poprzednia', 'następna &amp;raquo;'));<br />
$this-&gt;oPager-&gt;PatternSeparator('&lt;span&gt;...&lt;/span&gt;');</code></p>
<p>Końcowy efekt, możemy nie wyświetlać pagera, gdy jest tylko jedna strona elementów:</p>
<p><code>&lt;?php if($this-&gt;oPager-&gt;Render('pages') &gt; 1) {<br />
// wyswietl pager...<br />
} ?&gt;</code></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/paginacja-php-stronicowanie/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Podtrzymanie sesji</title>
		<link>http://athlan.pl/podtrzymanie-sesji/</link>
		<comments>http://athlan.pl/podtrzymanie-sesji/#comments</comments>
		<pubDate>Fri, 26 Dec 2008 19:35:39 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[Usablity]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[sesje]]></category>
		<category><![CDATA[sessions]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=159</guid>
		<description><![CDATA[Dla niektórych wygasanie sesji jest zabezpieczeniem (banki, etc.). Realizując jeden z projektów oczekiwałem od systemu tego, aby użytkownik nigdy nie gubił sesji, gdy ma otwarte okno w przeglądarce. Dlaczego? Może dodaje posta, być może uzupełnia dość obszerny tekst na stronie. Gdy klika zapisz, przerzuca go do strony logowania, a cały tekst zniknął za sprawą tego, [...]]]></description>
			<content:encoded><![CDATA[<p>Dla niektórych wygasanie sesji jest zabezpieczeniem (banki, etc.). Realizując jeden z projektów oczekiwałem od systemu tego, aby użytkownik nigdy nie gubił sesji, gdy ma otwarte okno w przeglądarce. Dlaczego? Może dodaje posta, być może uzupełnia dość obszerny tekst na stronie. Gdy klika <em>zapisz</em>, przerzuca go do strony logowania, a cały tekst zniknął za sprawą tego, że jego przeglądarka nie zapisuje wartości pól formularza. Skąd to znamy.</p>
<p><strong>Jak użytkownik gubi sesję?</strong></p>
<ol>
<li>Jego ciastko wygasa, więc serwer nie może go zidentyfikować z sesją.</li>
<li>Po jakimś czasie, choćby odtworzył ciastko, plik sesji znika z naszego serwera (<a href="http://pl.php.net/manual/pl/session.configuration.php#ini.session.gc-divisor">garbage collection</a>).</li>
</ol>
<p><strong>Rozwiązania:</strong></p>
<ol>
<li>Wydłużenie czasu wygasania ciastka i sesji.</li>
<li>Odświeżenie strony w interwale mniejszym, niż wynosi czas wygasania sesji i ciastka.</li>
</ol>
<p>Rozmyślając nad podtrzymaniem sesji, próbowałem znaleźć wszystkie metody oraz wybrać najlepszą. Wszystkie sprowadzają się do &#8220;odświeżenia&#8221; strony lub jej fragmentu tak, aby nasz silnik wykonał tylko potrzebne session_start(); czyli podtrzymanie aktywności sesji. Jest kilka mniej lub bardziej zadowalających sposobów:</p>
<ol>
<li><strong>Odświeżenie całej strony.</strong><br />
To może spowodować, że dane wprowadzane przez użytkownika w formularzu zostaną utracone. Ponad to, jeżeli użytkownik czyta newsy, denerwującym może być fakt, że lista nagle zostanie przescrollowana do góry (prócz opery).</li>
<li><strong>Wysłanie requestu ajax w tle.</strong><br />
Minusem jest to, że trzeba używać biblioteki ajax lub pisać dodatkowy kod javascriptu. Jeżeli ktoś na stronie używa jakiegoś ajaxa &#8211; co za różnica. Poza tym same plusy.</li>
<li><strong>Odświeżanie ukrytej ramki</strong> iframe lub elementu frameset.<br />
Minusów usablity prawie brak. Brak potrzeby instalacji javascriptów i ajaxa. Odświeżacz powinien wysłać nagłówek <em>Refresh</em> lub odpowiedni metatag.</li>
</ol>
<p>Sposób 3 wydaje mi się najlepszy. Można go ulepszyć w ten sposób, aby ramka nie wysyłała żądania zaraz po załadowaniu strony. Powodowałoby to podwójne requesty do serwera.</p>
<ul>
<li><a href="http://athlan.pl/code/PingIframe">Przykład z ukrytym iframe</a>.</li>
<li><a href="http://athlan.pl/code/PingAdvajax">Przykład z Advajax</a>.</li>
<li>plik <code>ping.php</code> wygląda wówczas następująco: <span style="color: #999999; font-size: 9px;">aplikacje nie używające frameworków ingerujących w standardowe działanie sesji</span><br />
<code>session_start(); header('Refresh: 60');</code></li>
</ul>
<p><span style="font-size: 9px">Zapewne znajdą się osoby, które powiedzą: a co z użytkownikami, którzy mają wyłączone ramki, lub ich przeglądarki w ogóle ich nie obsługują. Zapytam wówczas: a co z użytkownikami, którzy nie akceptują cisteczek (wówczas sesje nie są dla nich użyteczne, chyba, że użyjemy przesłyki jej identyfikatora w adresie url). Dopytam również: a co z użytkownikami, którzy mają wyłączony Javascript? Patologiczne przepadki się po prostu pomija ;)</span></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/podtrzymanie-sesji/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Hashowanie haseł z solą</title>
		<link>http://athlan.pl/hashowanie-hasel-z-sola/</link>
		<comments>http://athlan.pl/hashowanie-hasel-z-sola/#comments</comments>
		<pubDate>Mon, 22 Dec 2008 18:50:26 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[hash]]></category>
		<category><![CDATA[md5]]></category>
		<category><![CDATA[sha1]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=150</guid>
		<description><![CDATA[Przeglądając forum.php.pl często widziałem, jak użytkownicy przechowują hasła w swoich bazach danych. Najczęściej używają funkcji hashujących md5, sha1 i sha2. Wszystko wygląda bardzo dobrze, hasła są przechowywanie bezpiecznie. No właśnie&#8230; na ile bezpiecznie. Nie będę tutaj rozwodził się nad zabezpieczeniem baz danych, w których owa baza haseł się znajduje, ale nad samym zahashowanym ciągu. Wszyscy [...]]]></description>
			<content:encoded><![CDATA[<p>Przeglądając forum.php.pl często widziałem, jak użytkownicy przechowują hasła w swoich bazach danych. Najczęściej używają funkcji hashujących <code>md5</code>, <code>sha1</code> i <code>sha2</code>. Wszystko wygląda bardzo dobrze, hasła są przechowywanie bezpiecznie. No właśnie&#8230; na ile bezpiecznie.</p>
<p>Nie będę tutaj rozwodził się nad zabezpieczeniem baz danych, w których owa baza haseł się znajduje, ale nad samym zahashowanym ciągu. Wszyscy doskonale wiemy, że istnieją bazy md5 (sha1, sha2 również).</p>
<p><em>Przezorny zawsze ubezpieczony.</em> Wiadomo, że nigdy nic nie wiadomo.</p>
<p>Pokażę, jak dodatkowo zabezpieczyć nasze hasła. Będą przechowywane w tej samej bazie danych, używając tych samych metod hashowania, a jednak szansa na &#8220;złamanie&#8221; hasła (wyszukania w bazie) będzie niemożliwa. Posłużymy się ciągiem znaków zwanym przez programistów <em>solą </em>(<em>salt</em>). Przykład implementacji możemy znaleźć w forum IPB, natomiast phpBB pozbawione jest tego <span style="text-decoration: line-through;">fjuczuru</span> ficzera. Cała sprawa sprowadza się do wygenerowania dowolnego kawałka ciągu znaków i doklejenia go do hasła. Sól potrzebna nam będzie również przy porównaniu hasła, więc trzeba ją zapisać w bazie danych obok hasła.</p>
<p>Poniżej zamieszczam przykładową klasę, która obsługuje solenie haseł. Doklejanie soli może być napisane w dowolny sposób, zależy to od Waszej wyobraźni. Ja dodatkowo dodałem element &#8220;losowy&#8221; w postaci doklejenia do soli wyniku działania funkcji microtime().</p>
<ul>
<li><a href="http://athlan.pl/code/PassSalt">Klasa, która soli hasła.</a></li>
<li><a href="http://athlan.pl/code/PassSaltExample">Przykład</a> &#8211; zapisywanie hasła do bazy danych oraz sprawdzanie go przy logowaniu.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/hashowanie-hasel-z-sola/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Weryfikacja właściciela strony</title>
		<link>http://athlan.pl/weryfikacja-wlasciciela-strony/</link>
		<comments>http://athlan.pl/weryfikacja-wlasciciela-strony/#comments</comments>
		<pubDate>Sun, 17 Aug 2008 09:48:58 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Framework]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Solutions]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=133</guid>
		<description><![CDATA[Niedługo być może zaimplementuje w jeden z moich nowych projektów weryfikację właściciela strony. Pomysł pozwoliłem zrobię zaczerpnąć z Google Webmaster Tool. Natomiast troszeczkę zmieniłem jeden ze sposobów, aby mniej się napracować. Zweryfikowanie właściciela witryny odbywa się po wywołaniu jednej z poniższych metod. Oto one: Weryfikacja poprzez upload pliku na serwer. Chwilowe dodanie meta-tagu do sekcji [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" style="margin-left: 10px; margin-right: 10px; float: right;" src="http://img232.imageshack.us/img232/194/bannerwebsitedesignbx2.jpg" alt="" width="352" height="352" />Niedługo być może zaimplementuje w jeden z moich nowych projektów weryfikację właściciela strony. Pomysł pozwoliłem zrobię zaczerpnąć z Google Webmaster Tool. Natomiast troszeczkę zmieniłem jeden ze sposobów, aby mniej się napracować. Zweryfikowanie właściciela witryny odbywa się po wywołaniu jednej z poniższych metod. Oto one:</p>
<ul>
<li>Weryfikacja poprzez upload pliku na serwer.</li>
<li>Chwilowe dodanie meta-tagu do sekcji HEAD.</li>
</ul>
<p>W stosunku do google, zmianie uległa u mnie weryfikacja pierwsza.</p>
<p>Sposób Google: Upload pliku bez zawartości (lub z dowolną) o nazwie jako hash aktywacyjny, np: <code>&lt;?php md5( secret-salt ) . '.html'; ?&gt;</code></p>
<p>Mój sposób: Upload pliku ze stałą lub hashowaną nazwą o zawartości 32 znakowego hashu md5.</p>
<p>Zmienia się tylko zawartość pliku. Dlaczego? Niektóre strony zamiast zwracać kod 404 dla nieistniejących plików/podstron zwracają kod 200 (sukces). Wówczas trudno stwierdzić, czy jest to oczekiwany plik. Google dodatkowo sprawdza, czy strona zawsze zwraca kod 200, ale po co się babrać i wykonywać więcej requestów, jak można zrobić to trochę prościej. Jeżeli plik nie będzie fizycznie istniał na serwerze, a strona zwróci kod 200, skrypt musi oczekiwać w odpowiedzi tylko i wyłącznie hashu strony. Nazwa pliku na serwerze może być stała, ale niekoniecznie (dla większego bezpieczeństwa zalecane jest logiczne hashowanie nazwy pliku).</p>
<p>Przygotujmy zatem zarys klasy (od tego zawsze zaczynam):</p>
<ul>
<li><code>public function CheckFile($sUrl, $sFilename)</code> funkcja sprawdzająca hash w pliku na serwerze.</li>
<li><code>public function CheckMetatag($sUrl, $sTagName)</code> funkcja sprawdzająca hash w metatagu.</li>
<li><code>public static function Hash($sUrl)</code> funkcja budująca hash na postawie adresu URL (jako że podajemy go jako parametr obu metod sprawdzających, zmienna jest łatwo dostępna dla systemu).</li>
<li><code>public static function Metatag($sHash, $sTagName)</code> generowanie kodu XHTML dla metatagu &#8211; metoda potrzebna nam przy podaniu użytkownikowi meta tagu oraz do prega w metodzie CheckMetatag();</li>
<li><code>protected static function _Request($sUrl)</code> tworzenie requestu za pomocą HttpRequest i zwracanie treści metodą getResponseBody() wspomnianej klasy.</li>
</ul>
<p>Jako że komponent jest niejako zewnętrzną biblioteką, nie mogłem go wcisnąć w komponentu frameworka. Otrzymał status biblioteki: VframeLib_WebVeryfication.</p>
<p>Oczekiwane API:</p>
<p><code>var_dump(VframeLib_WebVeryfication::CheckFile('http://example.com/', 'Veryfication.txt')); // bool result<br />
var_dump(VframeLib_WebVeryfication::CheckMetatag('http://example.com/', 'Veryfication'));</code><code> // bool result</code></p>
<p>Gotowy kod:</p>
<p><a href="http://athlan.pl/code/VframeLib_WebVeryfication">http://athlan.pl/code/VframeLib_WebVeryfication</a></p>
<p><em style="color: red">Uwaga. Kod jest w fazie testowej. Wszelkie Wasze komentarze będą uwzględniane przy poprawkach.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/weryfikacja-wlasciciela-strony/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Obrona przed spamem</title>
		<link>http://athlan.pl/obrona-przed-spamem/</link>
		<comments>http://athlan.pl/obrona-przed-spamem/#comments</comments>
		<pubDate>Sat, 15 Mar 2008 19:10:03 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/obrona-przed-spamem/</guid>
		<description><![CDATA[Kiedyś poruszyłem temat spamu w postaci niechcianych komentarzy, wpisów w księdze gości, whatever. Unikanie captchy jest oczywiste. Zbiorę teraz niektóre metody unikania spamu: Zbudowanie ukrytego pola zatytułowanego dla przeglądarek tekstowych za pomocą label: &#8220;tego pola nie wypełniaj&#8221;. Jeżeli jego wartość będzie różna od pustego stringu, oznacza to, że formularza na 100% nie wypełniał człowiek (pomijamy [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://img137.imageshack.us/img137/8600/spamfx4ji2.jpg" align="right" border="1" hspace="5" vspace="5" />Kiedyś <a href="http://athlan.vgroup.pl/jak-sie-bronic-przed-spamem/">poruszyłem temat spamu</a> w postaci niechcianych komentarzy, wpisów w księdze gości, whatever. Unikanie <a href="http://pl.wikipedia.org/wiki/CAPTCHA">captchy</a> jest oczywiste. Zbiorę teraz niektóre metody unikania spamu:</p>
<ul>
<li>Zbudowanie ukrytego pola zatytułowanego dla przeglądarek tekstowych za pomocą <em>label</em>: &#8220;tego pola nie wypełniaj&#8221;. Jeżeli jego wartość będzie różna od pustego stringu, oznacza to, że formularza na 100% nie wypełniał człowiek <em>(pomijamy patologiczne przypadki)</em>.</li>
<li>Zmiana nazw pól, np z <em>comment </em>na <em>athlan</em>, lub z <em>email </em>na <em>betband</em>. W ten sposób można przeprowadzać walidację adresu email, robot nie powinien się zorientować.</li>
<li>Zmiana wartości argumentu <em>action </em>dla <em>form</em>. W tym artykule poruszę nieco ten temat.</li>
</ul>
<p>Boty analizując kod HTML strony w formie XML&#8217;a wyłapuje podelementy (pola <em>input</em>) i ich argumenty (włącznie z argumentami <em>form</em>). Na podstawie tych danych stwierdza, jak wysłać request do serwera, aby dodać spam. Pomyślmy chwilkę&#8230; jeżeli argument wskazywałby na wadliwy adres, bot mógłby na niego wskazać. Programista ma do dyspozycji Javascript, który ma dostęp do <em>DOM</em> struktury kodu strony www.</p>
<p>Krytycy takich wycieczek powiedzą, że pewien procent użytkowników nie ma dostępu do javascript (przeglądarki tekstowe) lub ich ustawienia nie interpretują tego języka (opcja wyłączona). Alternatywą dla takiej sytuacji jest wskazanie w kodzie HTML dla atrybutu <em>action </em>adresu url, który wyświetli komunikat, aby włączyć javascript potrzebny do funkcjonowania serwisu.</p>
<p>Pozostałym doradzam, aby jako domyślny adres użyli <a href="http://example.com"><em>example.com</em></a>, <a href="http://example.net"><em>example.net</em></a> lub <a href="http://example.org"><em>example.org</em></a>. Klauzula 3 w dokumencie <a href="http://www.rfc-editor.org/rfc/rfc2606.txt">RFC    2606</a> mówi, że domeny te powstały dla linkowania przykładów, dokumentacji itp.</p>
<blockquote><p>   The Internet Assigned Numbers Authority (IANA) also currently has the following second level domain names reserved which can be used as examples.</p></blockquote>
<p>Najlepszym rozwiązaniem wydaje się być połączenie wszystkich technik. Postanowiłem <a href="http://athlan.vgroup.pl/code/html-antispam">napisać kawałek kodu</a> jako przykład. <u>Reszta zależy od Waszej kreatywności</u>.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/obrona-przed-spamem/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tasowanie tablic bez utraty kluczy</title>
		<link>http://athlan.pl/tasowanie-tablic-bez-utraty-kluczy/</link>
		<comments>http://athlan.pl/tasowanie-tablic-bez-utraty-kluczy/#comments</comments>
		<pubDate>Tue, 21 Aug 2007 11:01:08 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/taskowanie-tablic-bez-utraty-kluczy/</guid>
		<description><![CDATA[Ostatnio napotkałem problem z tasowaniem tablic, który dość sprawnie rozwiązałem. Publikując notkę oraz sposób wybrnięcia z tego problemu zapewne komuś pomoże. Tablicę możemy tasować, tzn losowo ustawić jej wartości. Do tej operacji potrzebujemy funkcji shuffle() o której mowa w manualu. Spójrzmy jednak na notatkę: Notatka: Ta funkcja przypisuje nowe klucze dla elementów argumentu tablica. Wszystkie [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio napotkałem problem z <a href="http://php.net/shuffle">tasowaniem tablic</a>, który dość sprawnie rozwiązałem. Publikując notkę oraz sposób wybrnięcia z tego problemu zapewne komuś pomoże.</p>
<p>Tablicę możemy <a href="http://php.net/shuffle">tasować</a>, tzn losowo ustawić jej wartości. Do tej operacji potrzebujemy funkcji <a href="http://php.net/shuffle">shuffle() o której mowa w manualu</a>. Spójrzmy jednak na notatkę:</p>
<blockquote><p><strong>Notatka: </strong> Ta funkcja przypisuje nowe klucze dla elementów argumentu <em><tt>tablica</tt></em>. Wszystkie istniejące klucze zostaną usunięte.</p></blockquote>
<p>Nieciekawie prawda? W moim przypadku klucze tablicy były bardzo potrzebne, bowiem zawierały istotne informacje potrzebne do działania aplikacji. Doszedłem do wniosku, że jest możliwe zachowanie kluczy, trzeba tylko rozpisać sobie nową funkcję, która ma za zadanie:</p>
<ul>
<li>Stworzyć kopię tasowanej tablicy.</li>
<li>Operując na kopii przetworzyć ją tak, aby nowa tablica zawierała tylko klucze, naturalnie je przypisując operatorem []</li>
<li>Tasować nowopowstałą tablicę kluczy.</li>
<li>Do potasowanej tablicy kluczy przypisać wartości szukając po kluczach w oryginalnej tablicy.</li>
</ul>
<p>Działania proste. Spróbujmy stworzyć z powyższych punktów zlepek kodu:</p>
<p>[php]function array_shuffle(array $aArray)<br />
{<br />
$aArrayShuffle = array();</p>
<p>foreach($aArray as $mKey => $mValue)<br />
$aArrayShuffle[] = $mKey;</p>
<p>shuffle($aArrayShuffle);</p>
<p>$aResult = array();</p>
<p>foreach($aArrayShuffle as $sKey)<br />
$aResult[$sKey] = $aArray[$sKey];</p>
<p>return $aResult;<br />
}[/php]</p>
<p>Małe testy: <a href="http://phpfi.com/257646">http://phpfi.com/257646</a></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/tasowanie-tablic-bez-utraty-kluczy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jak zrobić Tagi?</title>
		<link>http://athlan.pl/jak-zrobic-tagi/</link>
		<comments>http://athlan.pl/jak-zrobic-tagi/#comments</comments>
		<pubDate>Thu, 05 Jul 2007 22:33:58 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/tagi/</guid>
		<description><![CDATA[UWAGA! Artykuł nie jest już aktualny. Nowa wersja artykułu znajduje się pod adresem: http://athlan.pl/chmura-tagow-tagcloud-php/ Niewątpliwie do standardów Web 2.0 można zakwalifikować tagcloud, chmurę pojedynczych słów, za pomocą której szybko i przyjemnie można znaleźć interesujące nas informacje. Przykładem chmury tagów jest digart -&#62; tagi. Na łamach forum.php.pl opublikowałem niedawno swoją klasę do tworzenia chmury tagów, dziś [...]]]></description>
			<content:encoded><![CDATA[<p style="border: 1px solid red; background: pink; padding: 20px; color: brown; font: bold 13px Arial; line-height: 150%;">UWAGA! Artykuł nie jest już aktualny. Nowa wersja artykułu znajduje się pod adresem:<br />
<a href="/chmura-tagow-tagcloud-php/">http://athlan.pl/chmura-tagow-tagcloud-php/</a></p>
<p>Niewątpliwie do standardów <a href="http://pl.wikipedia.org/wiki/Web_2.0"><em>Web 2.0</em></a> można zakwalifikować tagcloud, chmurę pojedynczych słów, za pomocą której szybko i przyjemnie można znaleźć interesujące nas informacje. Przykładem chmury tagów jest <a href="http://www.digart.pl/tagi">digart -&gt; tagi</a>.</p>
<p>Na łamach <a href="http://forum.php.pl">forum.php.pl</a> opublikowałem niedawno <a href="http://forum.php.pl/php-Klasa-tagow-t68963.html">swoją klasę do tworzenia chmury tagów</a>, dziś postaram się opisać, jak można zrobić chmurę tagów w php.</p>
<p><strong><a href="http://phpfi.com/247653">[zobacz źródło klasy]</a></strong></p>
<p><strong>Co nam będzie potrzebne?</strong> Wystarczy odrobina pomyślunku i zasad matematyki &#8211; reszta sama się obliczy : ) .</p>
<p>Założenia klasy:</p>
<ul>
<li>możliwość dodawania, usuwania oraz nadpisywania tagów w klasie,</li>
<li>możliwość wybrania dowolnej ilości poziomów (wielkości, wag)</li>
<li>initialize()</li>
</ul>
<p>Tak więc do pracy : ). Nasze tagi będą przetrzymywane w prywatnym argumencie funkcji jako tablica TAG =&gt; ILOŚĆ WYSTĘPOWANIA TAGU.</p>
<p><strong>Jak to działa? </strong>W konstruktorze klasy wybieramy sobie ilość poziomów tagów, po czym liczymy ich stosunek do pozostałych. Prosty wzór:</p>
<p><strong>Wzór?</strong></p>
<p><em>ceil(((ILOŚĆ_WYSTĄPIEŃ * 100) / MAKSYMALNA_ILOŚĆ_WYSTĄPIEŃ_TAGÓW) / <span style="text-decoration: underline;">ceil(100 / ILOŚĆ_POZIOMÓW)</span>)</em></p>
<p>Podkreślona część powyższego wzoru obrazuje nam jak odwrócić proporcję tak, aby otrzymać liczbę przez jaką trzeba dzielić na kawałki 100%, aby otrzymać dokładnie podaną równych ilość kawałków. Np dla 20 będzie to liczba 5 (5 równych kawałków to 20).</p>
<p><strong>Zakończenie.</strong> Otrzymujemy tablicę TAG =&gt; POZIOM : ) <a href="http://forum.php.pl/php-Klasa-tagow-t68963.html">Wykorzystanie?</a> To już zależy tylko i wyłącznie od Twojej wyobraźni. Przy 6-levelowym trybie możesz utworzyć nagłówki HTML, przy 20 poziomowym nadać odpowiednie klasy CSS i w nich definiować kolory i wielkości czcionek tagów.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/jak-zrobic-tagi/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Analiza zawartości i treści strony</title>
		<link>http://athlan.pl/analiza-zawartosci-i-tresci-strony/</link>
		<comments>http://athlan.pl/analiza-zawartosci-i-tresci-strony/#comments</comments>
		<pubDate>Wed, 04 Jul 2007 21:30:10 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[Solutions]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/analiza-zawartosci-i-tresci-strony/</guid>
		<description><![CDATA[Obecnie pracuje nad dość zaawansowanym systemem wymiany linków kontekstowych (umieszczonych w kontekście &#8211; w treści). Ostatnimi czasy dostałem wiadomość od klienta, że chciałby wykonać analizę treści strony. Na czym miałby polegać? łączymy się ze stroną główną bloga i sprawdzamy o czym mniej więcej dany użytkownik pisze na swoim pamiętniku internetowym. Zbieramy poszczególne wyrazy, licząc ich [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://vgroup.pl"><img src="http://vgroup.pl/www/img/projects/project_contextlink.jpg" align="left" border="1" height="160" hspace="15" vspace="15" width="160" /></a>Obecnie pracuje nad dość zaawansowanym systemem wymiany <a href="http://pl.wikipedia.org/wiki/Wikipedia:Linkowanie#Linki_kontekstowe">linków kontekstowych (umieszczonych w kontekście &#8211; w treści)</a><a href="http://technorati.com"></a>. Ostatnimi czasy dostałem wiadomość od klienta, że chciałby wykonać analizę treści strony. Na czym miałby polegać? łączymy się ze stroną główną bloga i sprawdzamy o czym mniej więcej dany użytkownik pisze na swoim pamiętniku internetowym. Zbieramy poszczególne wyrazy, licząc ich występowanie i ignorujemy wyrazy z czarnej listy (popularne wyrazy, np: &#8220;które&#8221;, &#8220;który&#8221;, &#8220;kiedy&#8221;) oraz odrzucamy te krótkie (poniżej 3 liter). Sortujemy malejąco i wykluczamy słowa, które występują mniej razy niż określona przez administratora ilość.</p>
<p>Wszystko pięknie ładnie&#8230; ale co z algorytmem PHP? Naskrobałem coś takiego:</p>
<p><a href="http://phpfi.com/247378">http://phpfi.com/247378</a></p>
<p>Prototyp, ale mniej więcej działa. Jak? Najpierw zawartość strony trzeba przefiltrować funkcją <a href="http://php.net/strip_tags">strip_tags()</a>, aby pozbyć się XHTML&#8217;a. Następnie używamy <a href="http://php.net/explode">explode()</a> po spacji i <a href="http://php.net/preg_replace">wyrażenia regularnego w preg_replace() <em>&#8220;/([^A-Z])/i&#8221;</em></a> które usuwa wszystkie niepotrzebne znaki ze stringu tak, aby wyszło nam słowo. Jeżeli słowo ma więcej niż 2 litery, sprawdzamy czy nie istnieje na blackliście &#8220;popularnych słów&#8221;. Jeżeli słowo już zostało dodane do tablicy, dodajemy liczbę jego występowania, w przeciwnym wypadku tworzymy kolejny element tablicy z wartością 1. Następnie sortujemy tablicę wielowymiarową funkcją <a href="http://php.net/usort">usort()</a>.</p>
<p>Dodatkowo wynik możemy przelecieć funkcją, która wypluje tylko te słowa, które spełnią równą lub większą ilość występowań określoną w argumencie metody.</p>
<p>Proste? Ale czy skuteczne? 90% tak, no ale jaki algorytm jest idealny&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/analiza-zawartosci-i-tresci-strony/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
