<?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>m1chu.eu - another devblog &#187; Aplikacje internetowe</title>
	<atom:link href="http://m1chu.eu/category/aplikacje-internetowe/feed/" rel="self" type="application/rss+xml" />
	<link>http://m1chu.eu</link>
	<description>we live, as we dream... alone - another devblog</description>
	<lastBuildDate>Fri, 25 Jun 2010 22:04:21 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Jak wyizolować liczbę subskrybentów RSS korzystając z FeedBurner&#8217;a?</title>
		<link>http://m1chu.eu/2009/02/15/jak-wyizolowac-liczbe-subskrybentow-rss-korzystajac-z-feedburnera/</link>
		<comments>http://m1chu.eu/2009/02/15/jak-wyizolowac-liczbe-subskrybentow-rss-korzystajac-z-feedburnera/#comments</comments>
		<pubDate>Sun, 15 Feb 2009 12:55:53 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[easy feed counter]]></category>
		<category><![CDATA[feedburner]]></category>
		<category><![CDATA[feedcount]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[repozytorium]]></category>
		<category><![CDATA[simplexmlelement]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=1237</guid>
		<description><![CDATA[
W niezbędniku prawie każdego blogera leży możliwość menadżerowania swoimi kanałami RSS, bądź Atom. Któż z nas nie zna FeedBurner&#8217;a?. Zestawu narzędzi ułatwiających nam, czy to udostępnianie użytkownikom możliwości subskrypcji treści naszej strony, czy po prostu możliwość przejrzenia lub zamieszczenia statystyk w naszym serwisie. Pomimo dostarczonego API nie znajdziemy jednak bezpośrednio w panelu FeedBurner&#8217;a kodu pozwalającego [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3316/3276810158_fd2d4b8829_o.png" alt="Pobieramy liczbę subskrybentów RSS poprzez FeedBurner" style="height: 119px;" /></p>
<p>W niezbędniku prawie każdego blogera leży możliwość menadżerowania swoimi kanałami RSS, bądź Atom. Któż z nas nie zna <strong>FeedBurner&#8217;a</strong>?. Zestawu narzędzi ułatwiających nam, czy to udostępnianie użytkownikom możliwości subskrypcji treści naszej strony, czy po prostu możliwość przejrzenia lub zamieszczenia statystyk w naszym serwisie. Pomimo dostarczonego API nie znajdziemy jednak bezpośrednio w panelu <strong>FeedBurner&#8217;a</strong> kodu pozwalającego na umieszczenie samej liczby subskrybentów bloga. I rozwiązanie tego, pozornie błahego problemu postaram się Wam dziś przedstawić&#8230;<br />
<span id="more-1237"></span></p>
<h2>Stary, dobry FeedBurner.com&#8230;</h2>
<p>Niespełna dwa lata temu słynny serwis zajmujący się obsługą kanałów RSS został przejęty za sto milionów dolarów przez <strong>Google</strong>. Pomimo tego, że minęło aż tyle czasu wielu blogerów nadal korzysta z zasobów starego, wysłużonego, pierwotnego FeedBurner&#8217;a. I co może wydawać się dziwne, to właśnie oni mają najbardziej ułatwioną sytuację.</p>
<p>Zarówno stara, jak i nowa odsłona serwisu oferują usługę <strong>FeedCount</strong> dostępną z poziomu menu <strong>Publicize</strong>. Pozwala ona na dobranie typu wbudowanego tła wyświetlającego ilość subskrybentów (statyczne, bądź animowane) oraz na dobranie jego barwy i koloru tekstu. Wraz z ustawieniem tych parametrów otrzymujemy kod HTML do wstawienia na naszą stronę. I tu rodzi się problem. Prócz kilku stylistycznych zmian wygląd tychże &#8220;chickletów&#8221; jest zawsze taki sam i najczęściej nijak pasuje do designu naszego bloga. Co zrobić jeżeli np. chcemy wraz z tekstem przycisku odnoszącego użytkowników do wygenerowanego kanału wstawić także ilość osób śledzących naszą stronę?</p>
<p>Rozwiązanie zaprezentuje na podstawie użytkowania platformy <a target="_blank" href="http://wordpress.org/"  title="Wordpress">Wordpress</a> (oczywiście ilość subskrybentów &#8211; opierając się na dalszym tekście &#8211; można zamieścić w każdym innym systemie zarządzania treścią, bądź nawet na własnej, prywatnej stronie). W takim wypadku wystarczy zainteresować się wtyczkami <a target="_blank" href="http://utnij.eu/5b5/"  title="FeedBurner FeedSmith 2.3">FeedSmith 2.3</a> (<a target="_blank" href="http://utnij.eu/632cd7/"  title="FeedBurner FeedSmith 2.3 PL">polska wersja</a>) (wg. developerów Wordpress&#8217;a kompatybilną ze wszystkimi wersjami 2.x) i <a target="_blank" href="http://utnij.eu/feed-count-plugin/"  title="Feed Count 1.2">Feed Count 1.2</a> (<a target="_blank" href="http://utnij.eu/776e/"  title="Feed Count 1.2 PL">polska wersja</a>). Pierwsza z nich niezbędna jest do obsługi kanału RSS przez serwis FeedBurner. </p>
<p>Jej instalacja oraz rejestracja w serwisie jest niezbędna do działania drugiej z nich. Jak wykonuje się instalacje wtyczek? Wystarczy wyodrębnić z archiwum odpowiednie pliki (w naszym pierwszym przypadku będzie to <strong>FeedBurner_FeedSmith_Plugin.php</strong>, w drugim <strong>feedcount.php</strong>) i umieścić je w katalogu <strong>wp-content/plugins/</strong> systemu Wordpress. Następnie wtyczki należy zaktywować w panelu administratora (<strong>Wtyczki / Nazwa wtyczki / Włącz</strong>).</p>
<p>Obydwa pluginy należy dodatkowo skonfigurować w zakładce <strong>Ustawienia</strong>. Pierwszy z nich swoje opcje ukrywa w podmenu <strong>FeedBurner</strong>. Zobaczycie tam dwa pola do uzupełnienia, jedno wymagane, drugie opcjonalne. Pierwsze z nich to pełny odnośnik do feedu strony w serwisie FeedBurner (i dla starej odsłony, i dla nowej na serwerach Google), a drugi to link do kanału RSS komentarzy.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3325/3278708424_d49400bae8_o.png" alt="Konfiguracja wtyczki FeedSmith w panelu" style="height: 280px;" /><br />Konfiguracja wtyczki FeedSmith w panelu.</p>
<p>Co do drugiego rozszerzenia to działa ono dla wersji <strong>2.x</strong> Wordpress&#8217;a, z tymże przy najnowszej <strong>2.7x</strong> może sprawiać problemy natury zwracania wyniku w postaci <strong>N/A</strong> zamiast poprawnej wartości.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3447/3277035819_12a3295a07_o.png" alt="Konfiguracja wtyczki Feed Count w panelu" style="height: 280px;" /><br />Konfiguracja wtyczki Feed Count w panelu.</p>
<p>Rozszerzenie to także należy dodatkowo skonfigurować. Robimy to w panelu poprzez menu <strong>Ustawienia / Feed Count</strong>. W jej opcjach trzeba podać co najmniej adres kanału (<em>Feed Url</em>) w postaci nazwy kanału na <strong>FeedBurner&#8217;ze</strong>, częstość aktualizowania ilości subskrybentów (<em>Update interval</em>) oraz częstość aktualizacji po wystąpieniu błędu (<em>Update interval (recovery)</em>). Pozostałe pola nie są wymagane. <em>Link url</em> to adres odnośnika pojawiającego się na zwróconej przez skrypt ilości osób śledzących stronę. <em>Before</em> za to jest treścią pojawiającą się przed liczbą w.w. użytkowników, a <em>After</em> to treść po.</p>
<p>Po wykonaniu konfiguracji należy jeszcze w strukturze szablonu strony dodać odpowiedni kod.</p>
<pre class="brush: php;">&lt;?php if (function_exists('fc_feedcount')) fc_feedcount(); ?&gt;</pre>
<p>Wstawić go musimy w miejscu w którym chcemy wyświetlać wystylizowaną liczbę użytkowników RSS (plugin ten nie zwraca tylko liczby otaczając ją poprzez dodatkowe tagi HTML). Oczywiście możemy go modyfikować. Jeżeli chcielibyście np. wyświetlić go w odnośniku (w <strong>header.php</strong>) o nazwie <strong>RSS</strong> w dodatkowych nawiasach to możecie to zrobić w następujący sposób:</p>
<pre class="brush: php;">&lt;?php
if (function_exists('fc_feedcount'))
{
	print ' (' . fc_feedcount() . ')';
}
?&gt;</pre>
<p>No i ostatecznie musicie w panelu <strong>FeedBurner&#8217;a</strong> (nie wtyczki, a profilu w serwisie w którym zakładaliście konto) zezwolić wtyczce na działanie z API tegoż serwisu. Wystarczy wejść do zakładki <strong>Publicize</strong>, a następnie do menu <strong>Awareness API</strong> i zaktywować tą funkcjonalność.</p>
<h2>Wtyczka Feed Count 1.2 dla Google FeedBurner!</h2>
<p>Jeżeli zdecydowaliście się jednak na migracje z starych serwerów serwisu, na ultraszybkie i megafajne klastry Google, a wcześniej trafnie stosowaliście w.w. metodę do wyodrębniania liczby użytkowników to prawdopodobnie będzie ona także działać po przejściu na <a target="_blank" href="http://feedburner.google.com/"  title="Google FeedBurner">feedburner.google.com</a>.</p>
<p>Trzeba jednak w takim wypadku dokonać pewnych, małych zmian w kodzie wyżej opisywanej wtyczki <strong>Feed Count</strong>. W tym celu edytujemy plik <strong>feedcount.php</strong> (np. poprzez <strong>Notepad++</strong> lub <strong>ZendStudio</strong>). Przechodzimy w okolice <strong>41</strong> linii w celu odnalezienia następującego kodu.</p>
<pre class="brush: php;">		  'map_fc_queryurl' =&gt;'http://api.feedburner.com/awareness/1.0/GetFeedData?uri=',</pre>
<p>Co można zauważyć element tablicy o nazwie przed <code>=></code> wskazuje na adres dostępowy do API, ale <em>feedburner.com</em>. A my przecież chcemy korzystać już z API Google. W tym celu należy tą linijkę zmienić niżej wymienionym kodem, po czym zapisać plik i ponownie wysłać go na serwer.</p>
<pre class="brush: php;">		  'map_fc_queryurl' =&gt;'https://feedburner.google.com/api/awareness/1.0/GetFeedData?uri=',</pre>
<h2>C&#8230; bombki strzelił! Jedyne co otrzymuje w wyniku to ten niewdzięczny &#8220;N/A&#8221;&#8230;</h2>
<p>Po pierwsze musicie sprawdzić czy biblioteka <a target="_blank" href="http://utnij.eu/curl-wiki/"  title="cURL Wiki">cURL (Client URL Library Functions)</a> jest dostępna w konfiguracjach Waszych serwerów (jako pakiet PHP). W tym celu wystarczy stworzyć jakikolwiek plik o rozszerzeniu <strong>.php</strong>, wypełnić go poniższym kodem i wywołać na hipotetycznie problematycznym serwerze.</p>
<pre class="brush: php;">&lt;?php
phpinfo();
?&gt;</pre>
<p>W wylistowanych wynikach wystarczy poszukać wpisu <strong>cURL support</strong> i sprawdzić, czy jego flaga ustawiona jest na <strong>enabled</strong>. Jeżeli nie, to właśnie znaleźliście przyczynę problemu. Powyższa, kluczowa dla nas wtyczka oparta jest na tym libie, a co za tym idzie jego brak powoduje niemożność poprawnego wykonania kodu tego rozszerzenia.</p>
<h2>Diagnoza problemu: cURL&#8230;</h2>
<p>Kiedy zawodzą dostępne już rozwiązania najlepszym sposobem na pozbycie się własnego problemu jest&#8230; napisanie indywidualnej solucji. Niestety to wiążę się najczęściej z jedną z dwóch rzeczy. Albo z posiadaniem konkretnej wiedzy odnośnie danego problemu, albo z wydatkiem związanym z opłaceniem osoby która rozwiąże Waszą dolegliwość.</p>
<p>Jeżeli dotarliście do tego punktu tzn. że nadal nie uzyskaliście pożądanego efektu. Pora więc właśnie na w.w. sposób, z tymże ja dla Was przygotuję go w stu procentach&#8230; za friko :] Mógłbym Wam zaprezentować kilkulinijkowy sposób, bo praktycznie do tego ogranicza się rozwiązanie &#8211; pytanie po co? Blog ten ma uczyć, dlatego postaram się Wam przedstawić dwie metody pobierania potrzebnych nam danych które po lekkim tuningu złożą się w jedną, w pełni funkcjonalną wtyczkę napisaną specjalnie na potrzeby tego artykułu. I w gruncie rzeczy będzie to najbardziej optymalne rozwiązanie ze wszystkich tutaj przedstawionych&#8230;</p>
<p>Przypadek numer jeden: <strong>brak możności użytkowania cURL&#8217;a</strong>. Jak to w życiu bywa, jak nie da wejść się jednym oknem, trzeba próbować drugim. Sposobów jest wiele, ja wybiorę użycie funkcji <a target="_blank" href="http://pl.php.net/file_get_contents"  title="file_get_contents - php.net">file_get_contents</a>. Zaimplementowana jest ona w PHP od wersji <strong>4.3</strong> i dodatkowo do jej działania konfiguracja serwera musi zezwalać na zdalne (z zewnętrznych źródeł) pobieranie plików. Trik który zastosujemy ogranicza się kolejno do:</p>
<ul>
<li>pobrania danych z adresu FeedBurner&#8217;a korzystając z udostępnionego przez niego API,</li>
<li>sprawdzenia czy odebrane dane są poprawne (pod kątem poprawności adresu i ewentualnych wyjątków),</li>
<li>wyszukanie frazy <code>circulation="</code> w posiadanym buforze. Kod który pobraliśmy wcześniej <strong>musi</strong> być w formacie XML, a co za tym idzie składa się on ze znaczników i parametrów. Właśnie parametr <code>circulation</code> zawiera w sobie wartość będącą ilością subskrybentów,</li>
<li>jeżeli fraza nie zostanie znaleziona, zwrócenie błędu,</li>
<li>w przeciwnym razie pobranie ciągu od pozycji wyszukiwanej wyżej frazy + 13 znaków (długość szukanego słowa), aż do znalezienia następnego cudzysłowia (bez niego).</li>
</ul>
<pre class="brush: php;">&lt;?php
$buffer = file_get_contents(ADRES_SERWER . NAZWA_KANALU); // pobranie pliku
if ( $buffer === false ) // zwrócenie błędu
{
	print 'n/d';
}

$pre_position = strpos($buffer, 'circulation=&quot;'); // wyszukanie pozycji frazy z drugiego argumentu
if ( $pre_position === false ) // w wypadku nieodnalezienia zwrócenie błędu (niepoprawny plik)
{
	print 'n/d';
}
else {
	print substr($buffer, ($pre_position+13), strpos($buffer, '&quot;', ($pre_position+14)) - ($pre_position+13)); // &quot;wypisanie na ekran&quot; zawartości parametru &quot;circulation&quot; z pobranego pliku XML
}
?&gt;</pre>
<h2>Kiedy problemem nie jest jednak cURL&#8230;</h2>
<div class="explain"><code>SimpleXMLElement</code> &#8211; klasa rozszerzenia <code>SimpleXML</code> dostarczająca prosty zestaw narzędzi do konwersji XML na obiekt na którym można operować poprzez użycie selektorów.</p>
<p>Przykład:</p>
<pre class="brush: xml;">&lt;parent&gt;
	&lt;children&gt;raz&lt;/children&gt;
	&lt;children&gt;dwa&lt;/children&gt;
&lt;/parent&gt;</pre>
<pre class="brush: php;">$xml = new SimpleXMLElement(XML);
$found = $xml-&gt;xpath('parent/children'); // wyszukiwanie potomka w drzewie dokumentu XML (argument w postaci np. rodzic/potomek/potomek_potomka/itp.)
print_r($found); // wypisanie tablicy wyników</pre>
</div>
<p>Plugin <strong>FeedCount</strong> nie zawsze działa na Wordpress&#8217;ie <strong>2.7x</strong>. Nie pytajcie dlaczego. Szczerze? Nie wiem i nie chciało mi się dociekać co jest tego powodem. Postanowiłem jakiś czas temu spotykając się z tą przypadłością po prostu stworzyć bardziej uproszczony kod, niż ten z popularnej wtyczki. Jak wygląda jego schemat krokowy? Po kolei:</p>
<ul>
<li>inicjalizacja cURL,</li>
<li>ustawienie opcji transferu biblioteki (zwracanie zawartości bez wypisywania jej na ekran oraz wprowadzenie adresu docelowego),</li>
<li>wykonanie zadania, po czym zniszczenie sesji połączenia,</li>
<li>sprawdzenie, czy nie występuje znacznik nadrzędny <code>err</code> z parametrem <code>code</code> o wartości <strong>1</strong> (oznaka zwrócenia błędu, najczęściej nieodnalezienia pliku),</li>
<li>jeżeli powyższy punkt nie okaże się prawdą to utworzenie obiektu <a target="_blank" href="http://pl.php.net/simplexml"  title="SimpleXML - php.net"><code>SimpleXMLElement</code></a> i wyszukanie zawartości wyżej już wspomnianego atrybutu <code>circulation</code>.</li>
</ul>
<pre class="brush: php;">&lt;?php
$resource = curl_init(); // inicjalizacja
curl_setopt($resource, CURLOPT_RETURNTRANSFER, 1); // bez wypisania na ekran
curl_setopt($resource, CURLOPT_URL, ADRES_SERWER . NAZWA_KANALU); // przekazanie adresu do pobrania
$buffer = curl_exec($resource); // wykonanie
curl_close($resource); // zamknięcie sesji

$xml = new SimpleXMLElement($buffer); // obiekt analizy składni XML
if ( $xml-&gt;err['code'] == '1' ) // sprawdzenie wystąpienia błędu
{
	print 'n/d';
}
print $xml-&gt;feed-&gt;entry['circulation']; // pobranie ilości subskrybentów
?&gt;</pre>
<p>Aby bardziej wyjaśnić działanie powyższej partii kodu posłużę się przykładowymi danymi, jakie mogą zostać pobrane.</p>
<pre class="brush: xml;">&lt;rsp stat=&quot;ok&quot;&gt;
  &lt;!--This information is part of the FeedBurner Awareness API. If you want to hide this information, you may do so via your FeedBurner Account.--&gt;
  &lt;feed id=&quot;0ua2berteje16lsipgq0b8uk74&quot; uri=&quot;worldclub-pl&quot;&gt;
    &lt;entry date=&quot;2009-02-13&quot; circulation=&quot;1&quot; hits=&quot;2&quot; downloads=&quot;0&quot; reach=&quot;0&quot; /&gt;
  &lt;/feed&gt;
&lt;/rsp&gt;</pre>
<p>Można z niego wywnioskować, że odpowiednio operując na klasie <code>SimpleXMLElement</code> moglibyśmy uzyskać identyfikator konta, jego część adresu zwaną w tym artykule po prostu nazwą, datę utworzenia, ilość osób śledzących RSS&#8217;a, liczbę kliknięć oraz ściągnięć. Działanie powyższej klasy jest proste. Z kodu XML tworzymy obiekt po którym możemy przesuwać się za pomocą zwyczajnych selektorów. Przykładowo jeżeli chcielibyśmy wyłuskać z powyższego przykładu identyfikator (<code>id</code>) zrobilibyśmy to w następujący sposób:</p>
<pre class="brush: php;">print $xml-&gt;feed['id'];</pre>
<p>Pierwszy, główny element <code>rsp</code> jest pomijany w instancji obiektu.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3601/3279482457_2255ac2de9_o.png" alt="Zasada działania SimpleXMLElement na podstawie kodu pobierania liczby subskrybentów" style="height: 230px;" /><br />Zasada działania SimpleXMLElement na podstawie kodu pobierania liczby subskrybentów.</p>
<h2>Autorska wtyczka finalnym rozwiązaniem naszego problemu!</h2>
<p>I tak oto dochodząc do meritum przedstawiam Wam rozszerzenie uproszczone, ale za to bardziej wzbogacone o trzy, moim zdaniem niezbędne funkcjonalności. <a href="http://dev.m1chu.eu/index.php?title=Easy_Feed_Counter"  title="Easy Feed Counter"><strong>Easy Feed Counter</strong></a> posiada możliwość łatwej instalacji i konfiguracji poprzez panel administratora. Proces wdrażania tego pluginu jest adekwatny do dodawania opisywanego wcześniej <strong>FeedCount</strong> (jest także dokładnie opisany w linku powyżej w repozytorium modyfikacji). Pozwala on na ustawienie serwera feedów, metody pobierania statystyk oraz wpisanie nazwy konta kanału RSS na FeedBurner&#8217;ze. Opcjonalnie możecie także dodać konto komentarzy na tym serwisie, o ile takowe posiadacie.</p>
<p style="text-align: center; font-size: 10px;"><img class="iborder" src="http://farm4.static.flickr.com/3302/3279600765_6edbcf3db2_o.png" alt="Rezultaty działania wtyczki" style="height: 171px;" /><br />Rezultaty działania wtyczki.</p>
<p>Rozwiązanie to ma także jeden wielki, dodatkowy atut. Nie formatuje jak inne pluginy zwracanej treści, a ogranicza się do podania wartości (liczby użytkowników), bądź kodu błędu (<strong>n/d</strong>). To pozwala na szersze modyfikacje położenia bądź wyglądu wyników po wywołaniu funkcji <code>easyfeedcounter_get([opcjonalny: parametr])</code> bez dodatkowej ingerencji w sam kod rozszerzenia.</p>
<pre class="brush: php;">&lt;?php
if (function_exists('easyfeedcounter_get'))
{
	$subscribers = easyfeedcounter_get(1); // argument o wartości 1 wskazuje wtyczce, że ma zwrócić dane dotyczące komentarzy
	if ( is_numeric($subscribers) !== false ) // brak błędów
	{
		print $subscribers . ' osób subskrybuje aktualnie Twoje komentarze!';
	}
}
?&gt;</pre>
<p>Bardziej skrupulatne objaśnienie, opisane krok po kroku znajdziecie w moim <a href="http://dev.m1chu.eu/index.php?title=Easy_Feed_Counter"  title="Easy Feed Counter">repozytorium</a>. W przypadku wątpliwości dotyczących tematu, bądź instalacji tego tworu proszę śmiało pytać :]</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2009/02/15/jak-wyizolowac-liczbe-subskrybentow-rss-korzystajac-z-feedburnera/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Kolizje współdziałania bibliotek JavaScript na podstawie wtyczek WordPress&#8230;</title>
		<link>http://m1chu.eu/2008/10/02/kolizje-wspoldzialania-bibliotek-javascript-na-podstawie-wtyczek-wordpress/</link>
		<comments>http://m1chu.eu/2008/10/02/kolizje-wspoldzialania-bibliotek-javascript-na-podstawie-wtyczek-wordpress/#comments</comments>
		<pubDate>Thu, 02 Oct 2008 10:45:38 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Prototype]]></category>
		<category><![CDATA[Webhosting]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[biblioteka]]></category>
		<category><![CDATA[dom]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[wtyczka]]></category>

		<guid isPermaLink="false">http://m1chu.eu/?p=96</guid>
		<description><![CDATA[
Coraz więcej różnorodnych stron internetowych korzysta z techniki która w szeroki sposób pozwoliła rozwinąć się przede wszystkim JavaScriptowi &#8211; z Ajaxa. Podobnie jest z różnorodnymi wtyczkami do systemu blogów WordPress. Z reguły korzystają one jednak z jakiejś biblioteki JavaScript zbierającej w całość jego najważniejsze funkcje i pozwalającej na ich prostsze użycie. W momencie jednak, kiedy [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="iborder" src="http://farm4.static.flickr.com/3066/2953934393_d684ed0058_o.png" alt="Współdziałanie framework'ów na przykładzie WordPress'a" /></p>
<p>Coraz więcej różnorodnych stron internetowych korzysta z techniki która w szeroki sposób pozwoliła rozwinąć się przede wszystkim JavaScriptowi &#8211; z Ajaxa. Podobnie jest z różnorodnymi wtyczkami do systemu blogów <a target="_blank" href="http://wordpress.org/"  title="WordPress">WordPress</a>. Z reguły korzystają one jednak z jakiejś biblioteki JavaScript zbierającej w całość jego najważniejsze funkcje i pozwalającej na ich prostsze użycie. W momencie jednak, kiedy w naszych pluginach pojawi się w użyciu kilka wtyczek możemy napotkać problem kolizji ich współdziałania.</p>
<p><span id="more-96"></span></p>
<h2>Prolog!</h2>
<p>Zanim zacznę muszę wspomnieć, że kolizja opisywana poniżej może występować na jakiejkolwiek stronie, a opisywana przeze mnie sytuacja jest tylko przykładem. Nie mniej jednak mankament ten postaram się wytłumaczyć na podstawie jednoczesnego działania <a target="_blank" href="http://utnij.eu/ajax-comments/"  title="WP Ajax Comments">AJAX Comments</a> i przystosowanej do personalnych potrzeb modyfikacji zakładek (przykładem są te umieszczone z lewej strony tego wpisu). Pierwsza wtyczka domyślnie używa <a target="_blank" href="http://script.aculo.us/"  title="Script.Aculo.Us">Script.Aculo.Us</a>, a co za tym idzie także frameworku <a target="_blank" href="http://www.prototypejs.org/"  title="Prototype">Prototype</a>. W drugim wypadku oprę się o <a target="_blank" href="http://vivee.info/2008/08/05/zakladki-do-sidebara/"  title="Zakładki do Sidebara">kurs tworzenia zakładek</a> w WP <strong>palmiaka</strong>, który używa za to <a target="_blank" href="http://jquery.com/"  title="jQuery">jQuery</a>.</p>
<p>Po poprawnej instalacji obydwu modyfikacji pewnie spora część z Was nie dostrzeże dręczącego nas feleru. Dlaczego? Gdyż na stronie głównej wszystko będzie działało prawidłowo, ale bynajmniej nie na podstronach w których będzie możliwe komentowanie wpisów. Dla przykładu w momencie wczytania najpierw <strong>prototype.js</strong> i <strong>scriptaculous.js</strong>, a później <strong>jquery.js</strong> stworzone przez nas zakładki nie będą poprawnie działać (nie zostaną one ukryte i nie będzie możliwości przejścia pomiędzy nimi). Dlaczego tak się dzieje? Tutaj należałoby poruszyć pewną sprawę dotyczącą samego działania frameworków tego typu.</p>
<h2>Funkcja $(argumenty)</h2>
<p>Między innymi do tworzenia obiektu danej biblioteki używa się funkcji <code>$(argumenty);</code>. Dzięki temu operujące np. na obiektach DOM, czy tablicach frameworki dzięki tej specjalnej konstrukcji pozwalają użytkownikowi na wykorzystywanie ich konkretnych funkcji.</p>
<p style="text-align: center;"><a target="_blank" href="http://farm4.static.flickr.com/3155/2905203185_36c209390b_o.png"  title="Powiększenie" class="lightbox"><img src="http://farm4.static.flickr.com/3155/2905203185_1e8236bb72.jpg" alt="Różnorodne metody korzystania z elementów strony" /></a></p>
<h2>Problematyka korzystania z więcej niż jednej biblioteki naraz&#8230;</h2>
<p>W momencie kiedy w skrypcie korzystamy z dwóch lub większej ilości frameworków może nastąpić kolizja w ich działaniu. W uproszczeniu przez użycie <code>$();</code> w każdej z nich. I tak to w naszym przykładzie funkcje, czy odwołania do obiektów które powinny być wykonane za pomocą <strong>jQuery</strong> zostaną wykonane przez pierwszą wczytaną klasę. A wszystko przez to, że każda z podanych bibliotek odwołuje się do danego elementu w taki sam sposób.</p>
<h2>Solucja!</h2>
<p>Na szczęście od wersji <strong>1.1.4</strong> z pomocą przychodzą nam developerzy <strong>jQuery</strong> wraz z funkcją pozwalającą na interoperacyjność &#8211; <code>jQuery.noConflict(param);</code>.</p>
<pre class="brush: jscript;">jQuery.noConflict(); // zwraca kontrolę nad $ bibliotece domyślnej (wcześniej używanej)
jQuery.noConflict(true); // zwraca kontrolę nad $ i jQuery (którego $ jest aliasem) oryginalnemu właścicielowi - należy używać z ostrożnością!</pre>
<p>Co należy wiedzieć w kwestii używania tego to przede wszystkim fakt, że wymaga się, aby powyższą funkcję wywołać przed użyciem elementów innych bibliotek, a także <strong>jQuery</strong> powinno być wczytywane po pozostałych frameworkach. W konkretnym wypadku związanym z WP który opisujemy należy także domyślnie dostarczone niżej wymienione biblioteki uaktualnić. Niestety w opisywanych tutaj wtyczkach i systemie blogów są to wersje starsze i przedstawiony trick w tym artykule nie zadziała dopóki nie ściągniemy zaktualizowanych wersji frameworków.</p>
<pre class="brush: jscript;">&lt;script type=&quot;text/javascript&quot; src=&quot;libs/prototype.js&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;libs/scriptaculous.js&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;libs/jquery.js&quot; /&gt;</pre>
<p>Domyślnie także należy używać w tym trybie <strong>jQuery</strong> zamiast <strong>$</strong>.</p>
<pre class="brush: jscript;">jQuery.noConflict();
jQuery(&quot;p&quot;).hide(); // użycie frameworka jQuery
$(&quot;div&quot;).style.display = 'none'; // użycie innego frameworka, np. prototype</pre>
<p>Ponieważ oczywiście zaprezentowana funkcja jest podatna na przypisywanie do zmiennych to niekoniecznie musimy używać standardowej, dłuższej nazwy. Negatywem tego rozwiązania jest jednak potencjalny konflikt nazw w przypadku pisania aplikacji internetowej przez wielu programistów.</p>
<pre class="brush: jscript;">var q = jQuery.noConflict();
q(&quot;p&quot;).hide();
$(&quot;div&quot;).style.display = 'none';</pre>
<p>Ostatecznie moglibyście także spytać <strong>&#8220;co zrobić, aby móc wewnątrz bloku kodu używać $ dla jQuery?&#8221;</strong>. Wystarczy poprzedzić zadaną funkcję przez <code>jQuery</code>, bądź zakończyć poprzez <code>(jQuery)</code>.</p>
<pre class="brush: jscript;">jQuery(function($) { [...] }); // wersja pierwsza
(function($) { [...] })(jQuery); // wersja druga</pre>
<p>Niestety w takim wypadku wewnątrz powyższych bloków kodu nie ma możliwości odniesienia się do obiektów innych bibliotek.</p>
<h2>Przykład pozwalający na prawidłowe działanie wspomnianych zakładek&#8230;</h2>
<p>Poprawiony przykład z <strong>vivee</strong>, który należy użyć w wypadku w.w. konfliktu (kod JavaScript).</p>
<pre class="brush: jscript;">jQuery.noConflict();

function tabs(id) {
	jQuery(&quot;#&quot;+id+&quot; h2:first a&quot;).addClass(&quot;active&quot;);
    jQuery(&quot;#&quot;+id+&quot; div&quot;).not(&quot;:first&quot;).hide();

    jQuery(&quot;#&quot;+id+&quot; h2 a&quot;).click(function() {
    	var licznik = jQuery(&quot;#&quot;+id+&quot; h2 *&quot;).index(this);                                             

        jQuery(&quot;#&quot;+id+&quot; h2 a&quot;).removeClass(&quot;active&quot;);
        jQuery(this).addClass(&quot;active&quot;);
        jQuery(&quot;#&quot;+id+&quot; div:visible&quot;).hide();

        jQuery(&quot;#&quot;+id+&quot; div&quot;).eq(licznik).show();
        return false;
    });
}

jQuery(document).ready(function(){
    tabs(&quot;zakladki&quot;);
});</pre>
<h2>Epilog&#8230;</h2>
<p><strong>WPNinja</strong> na swoim blogu poświęconym WordPressowi prawidłowo stwierdził w stosunku do mojej osoby, że mieszanie bibliotek nie jest dobrym zwyczajem.</p>
<pre class="brush: plain;">&quot;@m1chu,
Mieszanie ze sobą bibliotek to masakra. Nie dość, że zajmuje to niemiłosiernie dużo miejsca to, jak zauważyłeś w swoim artykule, może powodować konflikty.&quot;</pre>
<p>Opisany przeze mnie artykuł powinien być stosowany tylko w wyjątkowych sytuacjach. Należy z reguły <strong>unikać</strong> użytkowania kilku frameworków naraz, bo to obciąża w znacznym stopniu skrypt poprzez ich wagę, a co za tym idzie ilością danych do załadowania. Zdaję sobie jednak sprawę, że niekiedy jest to niezmiernie trudne (czego jak na razie w fazie rozwojowej przykładem jest mój blog ;]). Podziękowania za przypomnienie dla <strong>WPNinja&#8217;y</strong> o tym, że zapomniałem tak ważnego faktu umieścić w swoich wpisie.</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2008/10/02/kolizje-wspoldzialania-bibliotek-javascript-na-podstawie-wtyczek-wordpress/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Ciąg dalszy problemów z przekazywaniem tablic w phpBB by Przemo 1.12.5</title>
		<link>http://m1chu.eu/2008/03/22/ciag-dalszy-problemow-z-przekazywaniem-tablic-w-phpbb-by-przemo-1125/</link>
		<comments>http://m1chu.eu/2008/03/22/ciag-dalszy-problemow-z-przekazywaniem-tablic-w-phpbb-by-przemo-1125/#comments</comments>
		<pubDate>Sat, 22 Mar 2008 18:04:22 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Bugtrack]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[phpBB]]></category>
		<category><![CDATA[memberlist]]></category>
		<category><![CDATA[phpbb by przemo]]></category>
		<category><![CDATA[tablice]]></category>

		<guid isPermaLink="false">http://m1chu.eu/bugtrack/ciag-dalszy-problemow-z-przekazywaniem-tablic-w-phpbb-by-przemo-1125</guid>
		<description><![CDATA[Jeszcze w wigilię roku poprzedniego opisywałem rozwiązanie drobnego problemu z przekazywaniem tablic w jednym z plików forum phpBB by Przemo. Co ciekawsze na zasadzie tak jak poprzednio doszliśmy do wniosku, że skrypt ten w większości przypadków filtrowania danych wejściowych nie pozwala na poprawne filtrowanie przekazywanych tablic.

Dla przykładu podam kilka konkretnych błędnych elementów kodu wraz z [...]]]></description>
			<content:encoded><![CDATA[<p>Jeszcze w wigilię roku poprzedniego <a href="http://m1chu.eu/bugtrack/przekazywanie-tablic-w-memberlistphp-phpbb-by-przemo-1125"  title="Przekazywanie tablic w memberlist.php">opisywałem</a> rozwiązanie drobnego problemu z przekazywaniem tablic w jednym z plików forum <a target="_blank" href="http://przemo.org"  title="Strona skryptu">phpBB by Przemo</a>. Co ciekawsze na zasadzie tak jak poprzednio doszliśmy do wniosku, że skrypt ten w większości przypadków filtrowania danych wejściowych nie pozwala na poprawne filtrowanie przekazywanych tablic.</p>
<p><span id="more-34"></span></p>
<p>Dla przykładu podam kilka konkretnych błędnych elementów kodu wraz z jednym z rozwiązań poprawkowych. Dodam na wstępie, że wszelkie podane bugi dotyczą elementu tablicy globalnej o nazwie <strong>mode</strong> lub <strong>folder</strong> występujących w kilku osobnych plikach. Kolejno &#8211; <strong>privmsg.php</strong> standardowo może przyjmować domyślnie w tym elemencie wartości takie jak <strong>birthday</strong>, <strong>newpm</strong>, czy <strong>read</strong>. Co jeśli ktoś zażyczy sobie np. dla testu przekazać wartość w postaci elementu tablicy?</p>
<pre class="brush: php;">if ( !empty($HTTP_POST_VARS['mode']) || !empty($HTTP_GET_VARS['mode']) )
{
	$mode = ( !empty($HTTP_POST_VARS['mode']) ) ? $HTTP_POST_VARS['mode'] : $HTTP_GET_VARS['mode'];
	$mode = htmlspecialchars($mode);
}
else
{
	$mode = '';
}</pre>
<p>To kod odpowiadający za podstawowe filtrowanie wprowadzanych danych. Niestety nie sprawdza się on w wypadku, gdy w adresie forum wprowadzimy np. poniższy adres:</p>
<blockquote><p>/privmsg.php?mode[]=1,2,3</p></blockquote>
<p>Niby w tym przykładzie oprócz wizualnych większych szkód nie ma, nie mniej jest to bug. Teoretycznie można by wprowadzić dwa rodzaje korekt w tym kodzie. Jeden w stylu mojego ostatniego wpisu z tej tematyki, a mianowicie:</p>
<pre class="brush: php;">if ( is_array($HTTP_POST_VARS['mode']) || is_array($HTTP_GET_VARS['mode']) )
{
	$mode = '';
}
else if ( !empty($HTTP_POST_VARS['mode']) || !empty($HTTP_GET_VARS['mode']) )
{
	$mode = ( !empty($HTTP_POST_VARS['mode']) ) ? $HTTP_POST_VARS['mode'] : $HTTP_GET_VARS['mode'];
	$mode = htmlspecialchars($mode);
}
else
{
	$mode = '';
}</pre>
<p> Dodałem w tym wypadku po prostu pierwszy warunek który sprawdza czy przesyłane przez <strong>$_GET</strong> lub <strong>$_POST</strong> wartości nie są tablicą, a jeżeli są to zmienna <strong>$mode</strong> staje się pusta. Jest to o tyle bezpieczna wersja poprawki, że wyklucza przekazywanie jakichkolwiek tablic w tym przypadku. Druga wersja poprawki to taka, która pozwala na przekazywanie tablic, ale filtruje je w taki sposób, aby odebrane przez skrypt były jako <strong>string</strong>.</p>
<pre class="brush: php;">if ( is_array($HTTP_POST_VARS['mode']) || is_array($HTTP_GET_VARS['mode']) )
{
	$mode = ( !empty($HTTP_POST_VARS['mode']) ) ? $HTTP_POST_VARS['mode'] : $HTTP_GET_VARS['mode'];
	$mode = htmlspecialchars($mode[0]);
}
else if ( !empty($HTTP_POST_VARS['mode']) || !empty($HTTP_GET_VARS['mode']) )
{
	$mode = ( !empty($HTTP_POST_VARS['mode']) ) ? $HTTP_POST_VARS['mode'] : $HTTP_GET_VARS['mode'];
	$mode = htmlspecialchars($mode);
}
else
{
	$mode = '';
}</pre>
<p> Adekwatnie sprawa wygląda w plikach <strong>profile.php</strong> i <strong>modcp.php</strong>, a także w <strong>privmsg.php</strong> w związku z elementem <strong>folder</strong>. Ciut inna sytuacja występuje za to w <strong>posting.php</strong>. Tam filtrowane są w pętli wszystkie niezbędne elementy tablic.</p>
<pre class="brush: php;">$params = array('submit' =&gt; 'post', 'preview' =&gt; 'preview', 'delete' =&gt; 'delete', 'poll_delete' =&gt; 'poll_delete', 'poll_add' =&gt; 'add_poll_option', 'poll_edit' =&gt; 'edit_poll_option', 'mode' =&gt; 'mode');
while( list($var, $param) = @each($params) )
{
	if ( !empty($HTTP_POST_VARS[$param]) || !empty($HTTP_GET_VARS[$param]) )
	{
		$$var = ( !empty($HTTP_POST_VARS[$param]) ) ? htmlspecialchars($HTTP_POST_VARS[$param]) : htmlspecialchars($HTTP_GET_VARS[$param]);
	}
	else
	{
		$$var = '';
	}
}</pre>
<p>Co możemy zamienić tak jak w pierwszym przypadku na:</p>
<pre class="brush: php;">//
// Check and set various parameters
//
$params = array('submit' =&gt; 'post', 'preview' =&gt; 'preview', 'delete' =&gt; 'delete', 'poll_delete' =&gt; 'poll_delete', 'poll_add' =&gt; 'add_poll_option', 'poll_edit' =&gt; 'edit_poll_option', 'mode' =&gt; 'mode');
while( list($var, $param) = @each($params) )
{
	if ( is_array($HTTP_POST_VARS[$param]) || is_array($HTTP_GET_VARS[$param]) )
	{
		$$var = '';
	}
	else if ( !empty($HTTP_POST_VARS[$param]) || !empty($HTTP_GET_VARS[$param]) )
	{
		$$var = ( !empty($HTTP_POST_VARS[$param]) ) ? htmlspecialchars($HTTP_POST_VARS[$param]) : htmlspecialchars($HTTP_GET_VARS[$param]);
	}
	else
	{
		$$var = '';
	}
}</pre>
<p> lub</p>
<pre class="brush: php;">//
// Check and set various parameters
//
$params = array('submit' =&gt; 'post', 'preview' =&gt; 'preview', 'delete' =&gt; 'delete', 'poll_delete' =&gt; 'poll_delete', 'poll_add' =&gt; 'add_poll_option', 'poll_edit' =&gt; 'edit_poll_option', 'mode' =&gt; 'mode');
while( list($var, $param) = @each($params) )
{
	if ( is_array($HTTP_POST_VARS[$param]) || is_array($HTTP_GET_VARS[$param]) )
	{
		$$var = ( !empty($HTTP_POST_VARS[$param]) ) ?  htmlspecialchars($HTTP_POST_VARS[$param][0]) :  htmlspecialchars($HTTP_GET_VARS[$param][0]);
	}
	else if ( !empty($HTTP_POST_VARS[$param]) || !empty($HTTP_GET_VARS[$param]) )
	{
		$$var = ( !empty($HTTP_POST_VARS[$param]) ) ? htmlspecialchars($HTTP_POST_VARS[$param]) : htmlspecialchars($HTTP_GET_VARS[$param]);
	}
	else
	{
		$$var = '';
	}
}</pre>
<p>Są to tylko przykłady błędów. Reasumując całą sytuację należałoby względnie tych przykładów pozmieniać filtrując w taki sposób wszelkie zmienne wejściowe (z tablic superglobalnych <strong>$_GET</strong>, <strong>$_POST</strong>) przy których jesteśmy pewni, że nie będziemy przekazywać w nich żadnych wartości tablicowych. Uchroni nas to od błędów typu:</p>
<blockquote><p>Warning: htmlspecialchars() expects parameter 1 to be string, array given in /adres/modcp.php on line 116</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2008/03/22/ciag-dalszy-problemow-z-przekazywaniem-tablic-w-phpbb-by-przemo-1125/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Przekazywanie tablic w memberlist.php &#8211; phpBB by Przemo 1.12.5</title>
		<link>http://m1chu.eu/2007/12/24/przekazywanie-tablic-w-memberlistphp-phpbb-by-przemo-1125/</link>
		<comments>http://m1chu.eu/2007/12/24/przekazywanie-tablic-w-memberlistphp-phpbb-by-przemo-1125/#comments</comments>
		<pubDate>Mon, 24 Dec 2007 11:41:58 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Bugtrack]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[phpBB]]></category>
		<category><![CDATA[memberlist]]></category>
		<category><![CDATA[phpbb by przemo]]></category>
		<category><![CDATA[tablice]]></category>

		<guid isPermaLink="false">http://m1chu.eu/bugtrack/przekazywanie-tablic-w-memberlistphp-phpbb-by-przemo-1125</guid>
		<description><![CDATA[Dziś napisał do mnie d3d!k z prośbą o rejestrację na pewnym forum, na którym jestem technicznym adminem. Zaproszenie otrzymał i kilka minut później przekazał mi tekst błędu występującego na nim. I tutaj zaczyna się sens mojego wpisu&#8230;

Błąd jest standardowym bugiem występującym w phpBB by Przemo w wersji 1.12.5. Polega on na tym, że w wypadku [...]]]></description>
			<content:encoded><![CDATA[<p>Dziś napisał do mnie <strong>d3d!k</strong> z prośbą o rejestrację na pewnym forum, na którym jestem technicznym adminem. Zaproszenie otrzymał i kilka minut później przekazał mi tekst błędu występującego na nim. I tutaj zaczyna się sens mojego wpisu&#8230;</p>
<p><span id="more-30"></span></p>
<p>Błąd jest standardowym bugiem występującym w <strong>phpBB by Przemo</strong> w wersji <strong>1.12.5</strong>. Polega on na tym, że w wypadku przekazywania parametru <strong>mode</strong> w pliku <strong>memberlist.php</strong> w postaci tablicy otrzymujemy błąd argumentu funkcji <strong>htmlspecialchars</strong> w stylu:</p>
<pre class="brush: php;">Warning: htmlspecialchars() expects parameter 1 to be string, array given in /home/adres</pre>
<p>Dzieje się tak z prostego powodu. Funkcja powyższa w podstawowej formie przyjmuje <strong>jeden</strong> parametr, który musi być string-iem. W wypadku kiedy chcielibyśmy przekazać tablicę musielibyśmy każdy z jej elementów np. poprzez wpuszczenie w pętlę przefiltrować. Skrypt, a dokładniej jego autorzy nie przewidzieli takiej opcji.</p>
<p><strong>D3d!k</strong> dał mi też pewien rodzaj zabezpieczenia. Nie wdając się w dyskusję na temat jego formy, powiem tylko, że nie było one prawidłowe. Pozbawiało skrypt w tym elemencie jakiegokolwiek zabezpieczenia.</p>
<p>Moja propozycja jest następująca. A mianowicie, należy znaleźć w pliku <strong>memberlist.php</strong>:</p>
<pre class="brush: php;">if ( isset($HTTP_GET_VARS['mode']) || isset($HTTP_POST_VARS['mode']) )
{
	$mode = ( isset($HTTP_POST_VARS['mode']) ) ? htmlspecialchars($HTTP_POST_VARS['mode']) : htmlspecialchars($HTTP_GET_VARS['mode']);
}
else
{
	$mode = 'joined';
}</pre>
<p>Po czym zamienić na:</p>
<pre class="brush: php;">if ( (isset($HTTP_GET_VARS['mode']) || isset($HTTP_POST_VARS['mode'])) &amp;&amp; ( is_array($HTTP_POST_VARS['mode']) || is_array($HTTP_GET_VARS['mode']) ) )
{
	$mode = 'joined';
}
else if ( isset($HTTP_GET_VARS['mode']) || isset($HTTP_POST_VARS['mode']) )
{
	$mode = ( isset($HTTP_POST_VARS['mode']) ) ? htmlspecialchars($HTTP_POST_VARS['mode']) : htmlspecialchars($HTTP_GET_VARS['mode']);
}
else
{
	$mode = 'joined';
}</pre>
<p>Doszedł jak widać jeden warunek. Sprawdza on czy został ustawiony parametr <strong>mode</strong> jednej z tablic superglobalnych <strong>$_POST</strong> lub <strong>$_GET</strong> po czym dodatkowo sprawdza czy którakolwiek z nich jest tablicą. Jeśli tak to ustawia <strong>$mode</strong> na standardową opcję. Jeśli nie, tzn. że przekazywana nie jest tablica i dalej sprawdza już wg. starej instrukcji.</p>
<p>Podziękowania dla <strong>d3d!ka</strong> za ukazanie błędu.</p>
<p>Także z tego miejsca chciałbym Wam życzyć Wesołych Świąt, hucznego Sylwestra, a także pomyślności w nowym &#8211; już <strong>2008</strong> roku. A powyżej macie drobny prezent.</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2007/12/24/przekazywanie-tablic-w-memberlistphp-phpbb-by-przemo-1125/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>bbGeSHi &#8211; A better syntax highlighter 0.7.5</title>
		<link>http://m1chu.eu/2007/09/30/bbgeshi-a-better-syntax-highlighter-075/</link>
		<comments>http://m1chu.eu/2007/09/30/bbgeshi-a-better-syntax-highlighter-075/#comments</comments>
		<pubDate>Sun, 30 Sep 2007 18:44:25 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Bugtrack]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[phpBB]]></category>
		<category><![CDATA[bbgeshi]]></category>
		<category><![CDATA[modyfikacja]]></category>
		<category><![CDATA[phpbb3]]></category>

		<guid isPermaLink="false">http://m1chu.eu/informatyka/bugtrack/bbgeshi-a-better-syntax-highlighter-075/</guid>
		<description><![CDATA[Kolejny mod do nowej wersji phpBB3 w którym zauważyłem drażniący błąd. I pomimo, że i skrypt i modyfikacje do niego są w wersji rozwojowej to zbędne parsowanie (co najważniejsze tylko niektórych) tagów bbcode w znaczniku code było dla mnie nazbyt uciążliwe i coś było trzeba z tym zrobić.

Dla uwidocznienia problemu przedstawiam screena:

W wypadku znacznika code [...]]]></description>
			<content:encoded><![CDATA[<p>Kolejny mod do nowej wersji phpBB3 w którym zauważyłem drażniący błąd. I pomimo, że i skrypt i modyfikacje do niego są w wersji rozwojowej to zbędne parsowanie (co najważniejsze tylko niektórych) tagów bbcode w znaczniku <strong>code</strong> było dla mnie nazbyt uciążliwe i coś było trzeba z tym zrobić.</p>
<p><span id="more-20"></span></p>
<p>Dla uwidocznienia problemu przedstawiam screena:</p>
<p style="text-align: center;"><img src="http://farm4.static.flickr.com/3026/2842486593_52beae99e5.jpg" alt="bbGesHi 0.7.5 - bug parsowania" style="width: 500px; height: 200px;" /></p>
<p>W wypadku znacznika <strong>code</strong> jego zawartość nie powinna być parsowana. Nie mniej jednak autor skryptu bez względu na typ zastosowanego tagu parsuje jego zawartość metodami wbudowanymi w silnik GeSHi. Ominąć ten problem można na wiele sposobów, np. poprzez użycie funkcji <strong>str_replace</strong> w celu wydzielenia poszczególnych znaków na encje html lub po prostu zastosowanie jakieś wbudowanej funkcji. Osobiście przedstawię drugą wersję.</p>
<p>Przede wszystkim w momencie inicjalizacji klasy obsługującej silnik GeSHi przekazując w parametrze zmienną (<strong>$code</strong>) zawierającą zawartość znacznika należy przekonwertować znaki bbcode na encję html. Adekwatnie znajdujemy:</p>
<pre class="brush: php;">	function bbcode_highlight($code, $stx)
{
[...]
}</pre>
<p>W celu konwersji możemy posłużyć się metodą <strong>bbcode_specialchars</strong> której jedynym parametrem jest zmienna tekstowa. Należy wyszukać:</p>
<pre class="brush: php;">		$geshi = new GeSHi($code, $stx);</pre>
<p>I zamienić np. na:</p>
<pre class="brush: php;">		$geshi = new GeSHi((( $stx == 'text' ) ? $this-&gt;bbcode_specialchars($code) : $code), $stx);</pre>
<p>To niestety nie koniec. Przy parsowaniu GeSHi należy także rozróżnić, czy parsowany będzie znacznik <strong>code</strong>, czy inny. W wypadku tego pierwszego po sparsowaniu musi nastąpić konwersja zwrotna z encji na znaki. Nie można po prostu ominąć parsowania GeSHi, co też mogłoby rozwiązać problem z np. wyświetlaniem grafik w znaczniku <strong>code</strong> z tego powodu, że albo otrzymamy w wyniku encje html, albo opcja numerowania i ukrywania nie będzie działać.</p>
<p>Tak więc należy tym razem znaleźć:</p>
<pre class="brush: php;">		$result = $geshi-&gt;parse_code());</pre>
<p>I zamienić np. na:</p>
<pre class="brush: php;">		$result = (( $stx == 'text' ) ? htmlspecialchars_decode($geshi-&gt;parse_code(), ENT_NOQUOTES) : $geshi-&gt;parse_code());</pre>
<p>W celu zachowania bezpieczeństwa należało by także w powyższym przykładzie utworzyć tablicę z dozwolonymi znacznikami do konwersji zwrotnej. W tym wypadku bardziej odpowiednią metodą (bezpieczniejszą) byłoby użycie pierwszej metody z wymienionych wcześniej.<br />
Może się zdarzyć, że niektóre gotowe posty będą wyświetlały nie kod, a wynik parsowania &#8211; należy je w takim wypadku zedytować i zapisać znowu.</p>
<p>PS. sposób ten będzie działał na wersji php5 równej lub większej niż 5.1. W starszych wersjach można użyć wspomnianego już <strong>str_replace</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2007/09/30/bbgeshi-a-better-syntax-highlighter-075/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Raz-Captcha (Wordpress anti-spambot plugin)</title>
		<link>http://m1chu.eu/2007/09/26/raz-captcha-wordpress-anti-spambot-plugin/</link>
		<comments>http://m1chu.eu/2007/09/26/raz-captcha-wordpress-anti-spambot-plugin/#comments</comments>
		<pubDate>Wed, 26 Sep 2007 19:07:46 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Bugtrack]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[anti-spambot]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[raz-captcha]]></category>
		<category><![CDATA[token]]></category>

		<guid isPermaLink="false">http://m1chu.eu/informatyka/bugtrack/raz-captcha-wordpress-anti-spambot-plugin/</guid>
		<description><![CDATA[Kilka dni temu zauważyłem (co chyba na tego typu skryptach nie jest niczym niesamowitym) pełną ofensywę botów na stronie w postaci ich rejestracji. Z braku czasu dopiero dziś udało mi się wprowadzić kilka udoskonaleń które mam nadzieję, że pomogą w pozbyciu się zbędnych robotów.

Oczywiście z wyżej podanego powodu wprowadziłem gotowe rozwiązania, a mianowicie m.in. Raz-Captcha. [...]]]></description>
			<content:encoded><![CDATA[<p>Kilka dni temu zauważyłem (co chyba na tego typu skryptach nie jest niczym niesamowitym) pełną ofensywę botów na stronie w postaci ich rejestracji. Z braku czasu dopiero dziś udało mi się wprowadzić kilka udoskonaleń które mam nadzieję, że pomogą w pozbyciu się zbędnych robotów.</p>
<p><span id="more-19"></span></p>
<p>Oczywiście z wyżej podanego powodu wprowadziłem gotowe rozwiązania, a mianowicie m.in. <a href="http://raz-soft.com/display-english-posts-only/wordpress-plugin-login-register-anti-spambots-captcha/" title="Raz-Captcha" onclick="this.target='_blank'" >Raz-Captcha</a>. Część osób miało problem z systemem weryfikacji graficznej, które autor modyfikacji w dziwny sposób tłumaczył zerowaniem elementu <em>$_SESSION</em> odpowiedzialnego za przekazanie zahashowanej wartości wygenerowanego tokena, a druga część twierdziła, że mod działa (jakim sposobem nie wiem). Miałem podobny problem jak ta pierwsza grupa i dlatego postanowiłem przyjrzeć się problemowi ciut dokładniej.</p>
<p>Zakładam z góry, że nie jest to wina Wordpressa, czy zastosowanego stylu. Nie widzę powodu aby tak twierdzić, tym bardziej że z samego kodu który zanalizowałem wynika, że bug jest uzasadniony i dotyczy opcji silnika captcha dla <strong>PNG-phpBB3 8bit Grey</strong> i <strong>PNG-phpBB3 Advanced</strong>. I pomimo, że pomyłka jest naprawdę znikoma w sensie objętości to przysparza ona wielu problemów. W czym tkwi błąd?</p>
<p>Pozwolicie, że zanalizuje go na opcji <strong>PNG-phpBB3 8bit Grey</strong>, gdyż problem z drugim silnikiem jest adekwatny do tego, dotyczy tylko następnego warunku (<em>else if</em>) w pliku który zaraz omówię. Na początek należy otworzyć <strong>raz-captcha.php</strong> i około linijki <em>193</em> znaleźć:</p>
<pre class="brush: php;">else if ($option['rca_engine'] ==3) // phpBB3 no-gd bw png engine
{
	require_once(&quot;engines/phpbb-nogd.php&quot;);
	$captcha = new captcha();
	$password=gen_rand_string(mt_rand(5, 8));
	$captcha-&gt;execute($password, time());
	$_SESSION['raz_captcha_gen']=md5($password);
	exit();
}</pre>
<p>Kod ten odpowiada za inicjalizację funkcji, metod i przypisywanie zmiennych odpowiedzialnych za końcowe wyświetlenie tokena w opcji którą opisuję. I tutaj pojawia się błąd. Domyślnie autor modyfikacji najpierw odwołuje się do metody <em>execute</em>, a dopiero później przypisuje do danej sesji zahashowany wygenerowany token (dokładniej jego znaki).</p>
<pre class="brush: php;">$captcha-&gt;execute($password, time());
$_SESSION['raz_captcha_gen']=md5($password);</pre>
<p>Jeśli otworzymy teraz plik <strong>phpbb-nogd.php</strong> to około linijki <em>134</em> możemy zobaczyć, że po wykonaniu metody <strong>execute</strong> tej klasy i po wyświetleniu wyniku następuje brutalne zatrzymanie skryptu i wszystko co ma dziać się dalej np. w pliku <strong>raz-captcha.php</strong> zostaje przerwane.</p>
<pre class="brush: php;">	header('Content-Type: image/png');
	header('Cache-control: no-cache, no-store');
	echo $image;
	exit;
}</pre>
<p>I tu jest nasz bug. W pliku który otwieraliśmy na początku wystarczy zamienić linijkami wywołanie metody z przypisaniem do sesji naszego ciągu znaków, tak aby cały warunek wyglądał tak:</p>
<pre class="brush: php;">else if ($option['rca_engine'] ==3) // phpBB3 no-gd bw png engine
{
	require_once(&quot;engines/phpbb-nogd.php&quot;);
	$captcha = new captcha();
	$password=gen_rand_string(mt_rand(5, 8));
	$_SESSION['raz_captcha_gen']=md5($password);
	$captcha-&gt;execute($password, time());
	exit();
}</pre>
<p>Nasz problem powinien zniknąć. Adekwatnie na poniższym warunku możemy też poprawić błąd programisty.</p>
<pre class="brush: php;">else if ($option['rca_engine'] ==4) // phpBB3 Advanced
{ </pre>
<p>Zaznaczam, że problem testowany był na Wordpressie w wersji 2.2.3.</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2007/09/26/raz-captcha-wordpress-anti-spambot-plugin/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Edycja wpisów w ShoutBox &#8211; phpBB by Przemo</title>
		<link>http://m1chu.eu/2007/09/07/edycja-wpisow-w-shoutbox-phpbb-by-przemo/</link>
		<comments>http://m1chu.eu/2007/09/07/edycja-wpisow-w-shoutbox-phpbb-by-przemo/#comments</comments>
		<pubDate>Thu, 06 Sep 2007 22:29:15 +0000</pubDate>
		<dc:creator>m1chu</dc:creator>
				<category><![CDATA[Bugtrack]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[phpBB]]></category>
		<category><![CDATA[cgi]]></category>
		<category><![CDATA[gzip]]></category>
		<category><![CDATA[phpbb by przemo]]></category>
		<category><![CDATA[shoutbox]]></category>
		<category><![CDATA[zlib]]></category>

		<guid isPermaLink="false">http://m1chu.eu/informatyka/bugtrack/edycja-wpisow-w-shoutbox-phpbb-by-przemo/</guid>
		<description><![CDATA[Pierwszy wpis w tej kategorii. Pierwszy opisywany przeze mnie bug. Przyznaję, nie jest on żadnych wysokich lotów &#8211; nie mniej jednak tak jak zawsze z tego typu lub cięższymi sprawami dzieliłem się bezpośrednio z danymi osobami, tak teraz postanowiłem je pisać. Może dlatego, że mam gdzie.
Sprawa jest na tyle nieskomplikowana, że dłużej dociekałem przyczyny, niż [...]]]></description>
			<content:encoded><![CDATA[<p>Pierwszy wpis w tej kategorii. Pierwszy opisywany przeze mnie bug. Przyznaję, nie jest on żadnych wysokich lotów &#8211; nie mniej jednak tak jak zawsze z tego typu lub cięższymi sprawami dzieliłem się bezpośrednio z danymi osobami, tak teraz postanowiłem je pisać. Może dlatego, że mam gdzie.</p>
<p>Sprawa jest na tyle nieskomplikowana, że dłużej dociekałem przyczyny, niż ją naprawiałem. Błąd wykryłem przypadkiem, dzięki użytkownikom mojego forum. Wiem, że znany był on wcześniej, a nawet niektórzy próbowali go naprawiać, ale jednoznacznego rozwiązania nie widziałem nigdzie. Na czym polega bug? <strong>Na tym, że w przypadku jeśli <a href="http://pl.wikipedia.org/wiki/PHP"  onclick="this.target='_blank'" title="PHP">PHP</a> wspomagane jest obsługą <a href="http://pl.wikipedia.org/wiki/CGI"  onclick="this.target='_blank'" title="CGI">CGI</a> z wyłączonym <strong>zlib.output_compression</strong> w czasie edycji wpisów w shoutboxie jest wysyłany tekst przed wysłaniem nagłówków powodujący błąd skryptu</strong>. Problem ten dotyczy wersji <em>1.12.5</em>, z tego co wiem podobne problemy były zauważane w wersjach <em>1.9.x</em>.</p>
<p><span id="more-16"></span></p>
<p>Jak wygląda to od strony technicznej? W <a href="http://przemo.org"  onclick="this.target='_blank'" title="phpBB by Przemo">phpBB by Przemo</a> takie akcje jak edycja, czy usuwanie wpisów z <a href="http://pl.wikipedia.org/wiki/Shoutbox"  onclick="this.target='_blank'" title="Shoutbox">shoutboxa</a> są wykonywane w pliku <strong>shoutbox_view.php</strong>. W momencie kiedy w Panelu Administracyjnym ustawimy, aby skrypt korzystał z kompresji <a href="http://pl.wikipedia.org/wiki/Gzip"  onclick="this.target='_blank'" title="gzip">gzip</a> w pliku w zależności od typu przeglądarki ustawiane jest standardowe buforowanie wyjścia, wysyłany nagłówek szyfrowania treści strony, wyliczana suma kontrolnej i w końcu kompresowanie lub po prostu ustawienie buforowania wyjścia z atrybutem kompresji gzipa.</p>
<pre class="brush: php;">// Gecko
@ob_start('ob_gzhandler');</pre>
<pre class="brush: php;">// Opera
$do_gzip_compress = TRUE;
@ob_start();
@ob_implicit_flush(0);

@header('Content-Encoding: gzip');</pre>
<pre class="brush: php;">$gzip_contents = @ob_get_contents();
@ob_end_clean();

$gzip_size = strlen($gzip_contents);
$gzip_crc = @crc32($gzip_contents);

$gzip_contents = @gzcompress($gzip_contents, 9);
$gzip_contents = substr($gzip_contents, 0, strlen($gzip_contents) - 4);

echo &quot;x1fx8bx08x00x00x00x00x00&quot;;
echo $gzip_contents;
echo pack('V', $gzip_crc);
echo pack('V', $gzip_size);</pre>
<p>W tym drugim przypadku <strong>dotyczącym przeglądarek opartych na silniku Gecko</strong> każda próba edycji jakiegokolwiek wpisu kończy się wyświetleniem białej strony, w przypadku pierwszym <strong> dotyczącym Opery</strong> edycja jest możliwa, ale zamiast listowania wiadomości otrzymujemy ciąg skompresowanych danych, w postaci różnorodnych znaków. Co najdziwniejsze przynajmniej na Internet Explorerze w wersji siódmej wszystko działa dobrze ;]</p>
<p>Jak już napisałem prawie na początku problem stwarza fakt, że przy podanej wcześniej przeze mnie konfiguracji parsera PHP wysyłanie tekstu przed wysłaniem nagłówków powoduje automatyczne zatrzymanie i zerowanie zawartości sparsowanego pliku. Jeśli posiadamy własny serwer lub po prostu mamy możliwość konfiguracji naszego konta np. poprzez zmianę php.ini sprawa jest stosunkowo prosta. Możemy dla przykładu ustawić <strong>zlib.output_compression</strong> i <strong>zlib.output_compression_level</strong> na <strong>1</strong>. Na przykład poprzez użycie PHP w wersji co najmniej <em>4.3</em>:</p>
<pre class="brush: php;">ini_set('zlib.output_compression', true);
ini_set('zlib.output_compression_level', '1');</pre>
<p>Natomiast jeśli nie mamy takich możliwości konfiguracyjnych wystarczy, że znajdziemy poniższy kod.</p>
<pre class="brush: php;">$do_gzip_compress = FALSE;
if ( $board_config['gzip_compress'] &amp;&amp; !@headers_sent() )
{
	$phpver = phpversion();
	$useragent = (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) ? $HTTP_SERVER_VARS['HTTP_USER_AGENT'] : getenv('HTTP_USER_AGENT');
	$is_ob_gzhandler_started = false;
	if ( @ini_get('zlib.output_compression') &amp;&amp; (int)@ini_get('zlib.output_compression') != 0 &amp;&amp; strtolower(@ini_get('zlib.output_compression')) != 'off' )
	{
		$is_ob_gzhandler_started = true;
	}
	else if ( @ini_get('output_handler') &amp;&amp; strtolower(@ini_get('output_handler'))=='ob_gzhandler' )
	{
		$is_ob_gzhandler_started = true;
	}
	if ( $phpver&gt;= '4.0.4pl1' &amp;&amp; ( strstr($useragent,'compatible') || strstr($useragent,'Gecko') ) )
	{
		if ( extension_loaded('zlib') &amp;&amp; !$is_ob_gzhandler_started )
		{
			@ob_start('ob_gzhandler');
		}
	}
	else if ( $phpver&gt; '4.0' )
	{
		if ( strstr($HTTP_SERVER_VARS['HTTP_ACCEPT_ENCODING'], 'gzip') )
		{
			if ( extension_loaded('zlib') &amp;&amp; !$is_ob_gzhandler_started )
			{
				$do_gzip_compress = TRUE;
				@ob_start();
				@ob_implicit_flush(0);
				@header('Content-Encoding: gzip');
			}
		}
	}
}</pre>
<p>I przeniesiemy go powyżej następującego kodu.</p>
<pre class="brush: php;">// ShoutBox auth
$is_jr_admin = ($userdata['user_jr']) ? true : false;
$is_mod = ($userdata['user_level'] == MOD) ? true : false;</pre>
<p>W takim wypadku niezbędne do kompresji gzip nagłówki zostaną wysłane przed wyświetleniem tekstu i wszelkie związane z tą przypadłością błędy zostaną zaniechane.</p>
]]></content:encoded>
			<wfw:commentRss>http://m1chu.eu/2007/09/07/edycja-wpisow-w-shoutbox-phpbb-by-przemo/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
