<?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>&#60;?blog</title>
	<atom:link href="https://blog.visionsoftware.pl/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.visionsoftware.pl</link>
	<description>...nie tylko o programowaniu</description>
	<lastBuildDate>Sun, 23 Mar 2014 19:23:43 +0000</lastBuildDate>
	<language>pl-PL</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>Indeksy TTL w MongoDB</title>
		<link>https://blog.visionsoftware.pl/bazy-danych/indeksy-ttl-w-mongodb.html</link>
		<comments>https://blog.visionsoftware.pl/bazy-danych/indeksy-ttl-w-mongodb.html#comments</comments>
		<pubDate>Sun, 23 Mar 2014 19:22:43 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[Bazy danych]]></category>
		<category><![CDATA[index]]></category>
		<category><![CDATA[mongo]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[time to live]]></category>
		<category><![CDATA[ttl]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=643</guid>
		<description><![CDATA[MongoDB posiada bardzo ciekawą funkcjonalność w postaci automatycznego usuwania danych po upłynięciu określonego czasu. Wystarczy w tym celu utworzyć w kolekcji indeks TTL (ang. time to live). Dzięki temu można w niezwykle prosty sposób zaimplementować wygasające dane. Indeksy TTL możemy tworzyć na dwa różne sposoby. Możemy spowodować usunięcie  dokumentu po określonej liczbie sekund lub o określonym przez nas czasie. Usuwanie dokumentów po upłynięciu określonego czasu W tym przypadku należy utworzyć indeks na polu zawierającym datę, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>MongoDB posiada bardzo ciekawą funkcjonalność w postaci automatycznego usuwania danych po upłynięciu określonego czasu. Wystarczy w tym celu utworzyć w kolekcji indeks TTL (ang. <em>time to live</em>). Dzięki temu można w niezwykle prosty sposób zaimplementować wygasające dane.<span id="more-643"></span></p>
<p>Indeksy TTL możemy tworzyć na dwa różne sposoby. Możemy spowodować usunięcie  dokumentu po określonej liczbie sekund lub o określonym przez nas czasie.</p>
<h3>Usuwanie dokumentów po upłynięciu określonego czasu</h3>
<p>W tym przypadku należy utworzyć indeks na polu zawierającym datę, podając czas w sekundach, po jakim dokument zostanie usunięty.</p>
<p>Wyobraźmy sobie następującą, uproszczoną sytuację: w naszej aplikacji chcemy udostępniać jakieś zasoby, jednak wprowadzamy limit dla adresu IP. Powiedzmy, że użytkownik może coś pobrać raz na 10 minut. W naszej bazie informacje o fakcie pobrania będziemy przechowywali w następującej kolekcji:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
use downloads;
db.waiting.insert({createdAt: new Date(), ip: &quot;111.222.333.444&quot;});
db.waiting.insert({createdAt: new Date(), ip: &quot;555.666.777.888&quot;});
</pre>
<p>Jeśli chcemy aby nasze rekordy były kasowane z niej po 10 minutach wystarczy, że nałożymy następujący indeks TTL na pole z datą:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
db.waiting.ensureIndex( { &quot;createdAt&quot;: 1 }, { expireAfterSeconds: 600 } )
</pre>
<p>Po upłynięciu 600 sekund rekord zostanie automatycznie skasowany.</p>
<h3>Usuwanie dokumentów o określonym czasie</h3>
<p>Indeks TTL możemy także skonfigurować odwrotnie, tj. podając dokładny czas, w jakim dokument ma zostać skasowany. W tym celu należy na pole z datą ustawić indeks z wartością <code>expireAfterSeconds</code> ustawioną na 0:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
db.premium.ensureIndex( { &quot;expireAt&quot;: 1 }, { expireAfterSeconds: 0 } )
</pre>
<p>Jeśli data ustawiona w polu <code>expireAt</code> minie, to dokument zostanie automatycznie skasowany.</p>
<h3>Kilka dodatkowych informacji</h3>
<p>W przypadku korzystania z opisanej funkcjonalności, warto pamiętać o tym, że:</p>
<ul>
<li>Nie można nałożyć indeksu TTL na pole <code>_id</code>.</li>
<li>Indeks TTL nie może być ustawiony na pole, które posiada już inny indeks.</li>
<li>Dokument nie zostanie usunięty, jeśli nie będzie on posiadał zaindeksowanego pola (nie będzie w nim istniało pole z datą).</li>
<li>Dokument nie wygaśnie, jeśli zaindeksowane pole nie będzie pojedynczą datą lub tablicą dat w formacie BSON.</li>
<li>Indeksy TTL mogą być tylko proste (muszą składać się z jednego pola).</li>
<li>Jeśli indeks TTL został nałożony na tablicę, w której są daty, to dokument wygaśnie po uwzględnieniu najwcześniejszej z nich.</li>
<li>Nie można nałożyć indeksu TTL w <em>capped collection</em> (specjalna kolekcja, w której dane nadpisują się automatycznie).</li>
<li>Nie można użyć <code>ensureIndex()</code> w celu zmiany parametru <code>expireAfterSeconds</code>.</li>
<li>W przypadku tworzenia indeksu TTL typu <em>background</em>, dokumenty mogą być kasowane już w trakcie jego budowania. Jeśli będziemy go tworzyć jako <em>foreground</em>, dokumenty będą kasowane po jego zbudowaniu.</li>
<li>W przypadku używania indeksu TTL na zreplikowanych bazach, zostanie on uaktywniony tylko na <em>primary</em>. Dane zostaną usunięte z serwerów <em>secondary</em> podczas synchronizacji.</li>
</ul>
<h3></h3>
<h3>Dlaczego dane nie kasują się od razu?</h3>
<p>Przeprowadzając testy indeksów TTL z ustawionymi krótkimi czasami usunięcia dokumentów (np. kilkadziesiąt sekund) można dojść do wniosku, że nie wygasają one tak jak powinny. Dzieje się tak dlatego, że proces kasujący dane jest wywoływany co 60 sekund. Z tego względu dokumenty mogą zostać usunięte w krótkim czasie po upłynięciu terminu (działanie nie rozpoczyna się natychmiastowo).</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/bazy-danych/indeksy-ttl-w-mongodb.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GIT i patche: tworzenie i ładowanie</title>
		<link>https://blog.visionsoftware.pl/roznosci/git-i-patche-tworzenie-i-ladowanie.html</link>
		<comments>https://blog.visionsoftware.pl/roznosci/git-i-patche-tworzenie-i-ladowanie.html#comments</comments>
		<pubDate>Sat, 14 Dec 2013 18:17:41 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[Różności]]></category>
		<category><![CDATA[cherry-pick]]></category>
		<category><![CDATA[format-patch]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[repozytorium]]></category>
		<category><![CDATA[wersjonowanie]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=631</guid>
		<description><![CDATA[Zdarza się czasem, że potrzebujemy do aplikacji z użyciem GITa dodać jakąś funkcjonalność, jednak z pewnych powodów nie możemy posłużyć się normalnym commitem. Być może nie chcemy komuś przyznać prawa zapisu w repozytorium, lub nakładamy poprawkę na zewnętrzną aplikację, będącą pod kontrolą systemu wersjonowania. W takim przypadku pomocne będzie stworzenie patcha, a następnie załadowanie go do aplikacji. Tworzenie patcha Tworzenie patcha w GIT jest niezwykle proste. Powiedzmy, że chcemy wprowadzić pewną zmianę w działającą, zewnętrzną [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Zdarza się czasem, że potrzebujemy do aplikacji z użyciem GITa dodać jakąś funkcjonalność, jednak z pewnych powodów nie możemy posłużyć się normalnym commitem. Być może nie chcemy komuś przyznać prawa zapisu w repozytorium, lub nakładamy poprawkę na zewnętrzną aplikację, będącą pod kontrolą systemu wersjonowania. W takim przypadku pomocne będzie stworzenie patcha, a następnie załadowanie go do aplikacji.<span id="more-631"></span></p>
<h1>Tworzenie patcha</h1>
<p>Tworzenie patcha w GIT jest niezwykle proste. Powiedzmy, że chcemy wprowadzić pewną zmianę w działającą, zewnętrzną aplikację, a następnie przesłać te zmiany innemu programiście. Na początek powinniśmy stworzyć osobny branch na nasze zmiany:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git checkout -b fix-example master
</pre>
<p>Powyższe polecenie stworzy nowy branch o nazwie fix-example na podstawie gałęzi master i przełączy się na nią.</p>
<p>Następnie wprowadzamy wymagane poprawki i wykonujemy commit:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git add .
git commit -m &quot;My fixes&quot;
</pre>
<p>Teraz pozostaje już tylko wygenerowanie patcha z naszymi zmianami:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git format-patch master --stdout &gt; fix-example.patch
</pre>
<p>Powyższe polecenie wygeneruje plik z wszystkimi zmianami w stosunku do gałęzi master.</p>
<h1>Tworzenie patcha dla pojedynczego commita</h1>
<p>Jeśli chcemy stworzyć osobne patche dla każdego commita, możemy to zrobić w następujący sposób:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git format-patch -2 0c4b265151e8de7416d16d447d7ac89043c75481
</pre>
<p>Pierwszy parametr oznacza, ile patchy chcemy stworzyć, a drugi początkowego commita,. Poszczególne pliki zostaną nazwane na podstawie opisu commita, np:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
0001-My-fix-example.patch
0002-My-fix-examlple-2.patch
</pre>
<h1>Załadowanie patcha</h1>
<p>Ładowanie patcha jest równie proste, co jego tworzenie. Na początek możemy sprawdzić, co nowego wnosi przygotowana poprawka:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git apply --stat fix-example.patch
</pre>
<p>Wynikiem tego działania będzie lista wszystkich plików wraz z podsumowaniem zmian:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
myfile1.php | 4
myfile2.php | 2
2 files changed, 3 insertions(+), 3 deletions(-)
</pre>
<p>W następnym kroku warto sprawdzić, czy załadowanie patcha uda się przeprowadzić bez konfliktów. W końcu w aplikacji mogły się już pojawić jakieś zmiany dokonane przez inne osoby:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git apply --check fix-example.patch
</pre>
<p>W przypadku konfliktów, zostaną one wyświetlone na liście, na przykład:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
error: patch failed: myfile1.php:29
error: myfile1.php: patch does not apply
</pre>
<p>Natomiast w przypadku, gdy wszystko będzie możliwe do załadowania, nie powinniśmy zobaczyć żadnego komunikatu. W takim przypadku pozostaje już tylko faktyczne załadowanie naszej poprawki. Można to zrobić przy pomocy dwóch komend: git apply oraz git am. Druga z nich będzie jednak lepsza, gdyż umożliwia podpisanie patcha przez osobę, która go zaaplikowała:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git am --signoff &lt; fix-example.patch
</pre>
<p>Po zakończeniu operacji zostanie wyświetlona lista commitów, jakie zostały wprowadzone w patchu:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
Applying: my fix example
</pre>
<p>Przeglądając historię, będziemy mogli łatwo odnaleźć informację zarówno o autorze jak i osobie, która ją załadowała do repozytorium:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
$ git log
commit 01ed141f907ffafea6f3f0c9947c9b78dba1bb45
Author: Marcin Fliszta &lt;marcin.fliszta@...&gt;
Date: Sat Nov 30 13:13:40 2013 +0100

my fix example

Signed-off-by: Marcin Fliszta &lt;marcin.fliszta@...&gt;
</pre>
<h1>Wycofanie patcha</h1>
<p>Gdy podczas ładowania patcha coś pójdzie nie tak jak się spodziewaliśmy, możemy łatwo go wycofać. Tryb rozwiązywania problemów jest podobny do tego, z którym mamy do czynienia podczas konfliktów.</p>
<pre class="brush: plain; light: true; title: ; notranslate">
$ git am --signoff &lt; 0001-My-fix-example.patch
Applying: myfile1.php update
error: patch failed: myfile1.php:1
error: myfile1.php: patch does not apply
Patch failed at 0001 myfile1 update
The copy of the patch that failed is found in:
/var/www/patchexample/.git/rebase-apply/patch
When you have resolved this problem, run &quot;git am --resolved&quot;.
If you prefer to skip this patch, run &quot;git am --skip&quot; instead.
To restore the original branch and stop patching, run &quot;git am --abort&quot;.
</pre>
<p>W celu wycofania naszego patcha wystarczy zastosować komendę wymienioną na końcu informacji o niepowodzeniu:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git am --abort
</pre>
<h1>Przenoszenie commitów pomiędzy branchami</h1>
<p>Jeśli widzisz dodatkowe zastosowanie opisanych tutaj rozwiązań w przypadku przenoszenia wybranych commitów pomiedzy lokalnymi branchami, to nie warto zawracać sobie tym głowy. Do tego celu GIT posiada znacznie lepsze polecenie, jakim jest <a title="Dokumentacja GIT: cherry-pick" href="http://git-scm.com/docs/git-cherry-pick" target="_blank">cherry-pick</a>.</p>
<p>Jego składnia i działanie są banalnie proste i może wyglądać następująco:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
git cherry-pick 01ed141f907ffafea6f3f0c9947c9b78dba1bb45
</pre>
<p>Powyższe wywołanie spowoduje wstawienie wybranego po hashu commita do bieżącego brancha. Nie musimy oczywiście wskazywać z jakiego brancha ma być on załadowany, gdyż hash jest unikalny dla całego repozytorium. Dostępne są oczywiście różne opcje tego polecenia, można zapoznać się z nimi w dokumentacji GITa.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/roznosci/git-i-patche-tworzenie-i-ladowanie.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Method chaining w PHP</title>
		<link>https://blog.visionsoftware.pl/programowanie-php/method-chaining-w-php.html</link>
		<comments>https://blog.visionsoftware.pl/programowanie-php/method-chaining-w-php.html#comments</comments>
		<pubDate>Tue, 31 Jul 2012 20:03:08 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[fluent interface]]></category>
		<category><![CDATA[method chaining]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programowanie obiektowe]]></category>
		<category><![CDATA[wzorce projektowe]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=617</guid>
		<description><![CDATA[Zawarta  w tytule nazwa określa implementację wzorca Fluent interface, który odpowiednio zastosowany może uprościć i skrócić tworzony kod. Użycie Method chaining umożliwia cykliczne wywoływanie metod dla obiektu bez jawnego podawania go za każdym razem. Stąd właśnie wzięła się nazwa tej techniki, gdyż wygląda to jak łańcuszek. Jak wygląda uzycie Method chaining w praktyce? Jest on stosowany w wielu różnych językach, a webdeveloperzy mogą go znaleźć między innymi w jQuery lub frameworkach PHP. Upraszcza to znacznie [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Zawarta  w tytule nazwa określa implementację wzorca Fluent interface, który odpowiednio zastosowany może uprościć i skrócić tworzony kod. Użycie Method chaining umożliwia cykliczne wywoływanie metod dla obiektu bez jawnego podawania go za każdym razem. Stąd właśnie wzięła się nazwa tej techniki, gdyż wygląda to jak łańcuszek.<span id="more-617"></span></p>
<h3>Jak wygląda uzycie Method chaining w praktyce?</h3>
<p>Jest on stosowany w wielu różnych językach, a webdeveloperzy mogą go znaleźć między innymi w jQuery lub frameworkach PHP. Upraszcza to znacznie tworzenie kodu, co można zobaczyć na poniższym przykładzie:</p>
<pre class="brush: jscript; title: ; notranslate">
$(&quot;p&quot;).removeClass(&quot;class&quot;)
	.addClass(&quot;another_class&quot;)
	.css(&quot;color&quot;,&quot;red&quot;)
	.fadeOut(&quot;slow&quot;);
</pre>
<h3>Jak zaimplementować Method chaining w PHP?</h3>
<p>Bardzo podobnie możemy powyższe rozwiązanie wykorzystać w PHP. Jest to niezwykle proste do osiągnięcia, wystarczy, że poszczególne wywoływane metody będą zwracały cały obiekt. Przez to nie będzie trzeba go podawać za każdym razem, lecz utworzyć odpowiedni łańcuch.</p>
<p>Na poniższym przykładzie przedstawiono implementację Method chaining. Jest to klasa bardzo uproszczonego kalkulatora, dzięki któremu możemy wykonywać podstawowe działania matematyczne.</p>
<pre class="brush: php; title: ; notranslate">
class Calculator{
	private $_result = 0;

	public function __construct($value = 0) {
		$this-&gt;_result = $value;
		return $this;
	}

	public function add($value){
		$this-&gt;_result+=$value;
		return $this;
	}

	public function subtract($value){
		$this-&gt;_result-=$value;
		return $this;
	}

	public function multiply($value){
		$this-&gt;_result*=$value;
		return $this;
	}

	public function divide($value){
		$this-&gt;_result/=$value;
		return $this;
	}

	public function getResult(){
		return $this-&gt;_result;
	}
}
</pre>
<p>Implementacja Metchod chaining kryje się w wywołaniu <code>return $this</code> na końcu każdej metody odpowiedzialnej za działania matematyczne. Dzięki temu będzie możliwe niezwykle proste wykonanie obliczeń:</p>
<pre class="brush: php; title: ; notranslate">
$calc = new Calculator(5);
print $calc-&gt;add(2)
		-&gt;subtract(1)
		-&gt;divide(2)
		-&gt;multiply(3)
		-&gt;getResult();
</pre>
<h3>Pominięcie osobnego tworzenia obiektu</h3>
<p>Możliwe jest także zastosowanie Method chaining bezpośrednio przy wywołaniu obiektu, dzięki czemu nie będziemy musieli tworzyć go w osobnej linii. Wystarczy w tym celu dodać do klasy <code>Calculator</code> statyczną metodę <code>start()</code>, która zwróci nam utworzony obiekt:</p>
<pre class="brush: php; title: ; notranslate">
public static function start($value = 0){
	return new Calculator($value);
}
</pre>
<p>Dzięki takiemu rozwiązaniu możemy jeszcze bardziej uprościć wywołanie kalkulatora:</p>
<pre class="brush: php; title: ; notranslate">
print Calculator::start(5)-&gt;add(4)-&gt;divide(3)-&gt;getResult();
</pre>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/programowanie-php/method-chaining-w-php.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Numerowanie wierszy w MySQL</title>
		<link>https://blog.visionsoftware.pl/bazy-danych/numerowanie-wierszy-w-mysql.html</link>
		<comments>https://blog.visionsoftware.pl/bazy-danych/numerowanie-wierszy-w-mysql.html#comments</comments>
		<pubDate>Sat, 30 Jun 2012 20:17:28 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[Bazy danych]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[numerowanie wierszy]]></category>
		<category><![CDATA[raport]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=610</guid>
		<description><![CDATA[Tworząc raport zawierający określoną liczbę wierszy, dobrym pomysłem jest ich ponumerowanie. Stosując prostą sztuczkę możemy to zrobić bezpośrednio w MySQL, pomijając dodatkową obróbkę danych w edytorze tekstowym lub arkuszu kalkulacyjnym. Wystarczy w tym celu skorzystać ze zmiennych. Rozwiązanie problemu numerowania wierszy w MySQL jest niezwykle proste. Wystarczy zdefiniować zmienną globalną, która będzie przechowywać licznik i wyświetlić ją jako argument polecenia SELECT. Może to wyglądać w następujący sposób: Niestety, sytuacja zaczyna się komplikować, gdy rozbudujemy zapytanie. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Tworząc raport zawierający określoną liczbę wierszy, dobrym pomysłem jest ich ponumerowanie. Stosując prostą sztuczkę możemy to zrobić bezpośrednio w MySQL, pomijając dodatkową obróbkę danych w edytorze tekstowym lub arkuszu kalkulacyjnym. Wystarczy w tym celu skorzystać ze zmiennych. <span id="more-610"></span></p>
<p>Rozwiązanie problemu numerowania wierszy w MySQL jest niezwykle proste. Wystarczy zdefiniować zmienną globalną, która będzie przechowywać licznik i wyświetlić ją jako argument polecenia <code>SELECT</code>. Może to wyglądać w następujący sposób:</p>
<pre class="brush: sql; title: ; notranslate">
set @row = 0;
select @row := @row + 1 as &quot;Lp.&quot;,
imie,
nazwisko
from klienci
</pre>
<p>Niestety, sytuacja zaczyna się komplikować, gdy rozbudujemy zapytanie. Wzbogacając je o złączenia, klauzulę <code>WHERE</code> oraz sortowania, możemy spodziewać się błędnego numerowania wierszy. Widać to na poniższym przykładzie pobierania danych dotyczących statystyk odwiedzin strony www:</p>
<pre class="brush: sql; title: ; notranslate">
SET @a:=0;
SELECT @a:=@a+1 AS &quot;row&quot;,
IP
FROM `stats` st JOIN
`sources` so ON st.source_id = st.source_id
WHERE st.created_at BETWEEN &quot;2011-01-01 00:000:00&quot; AND &quot;2011-01-01 23:59:59&quot;
AND st.IP LIKE &quot;1%&quot;
AND st.source_id=1
ORDER BY st.IP
</pre>
<p>Wynik takiego wywołania będzie następujący:</p>
<pre>
row     IP
------  ---------------
77      100.113.10.222
50      100.113.10.222
23      100.113.10.222
60      104.87.121.89
33      104.87.121.89
6       104.87.121.89
[…]
</pre>
<p>Sposobem na rozwiązanie tego problemu będzie podzapytanie w klauzuli <code>FROM</code>. Wystarczy umieścić numerowanie wierszy w zewnętrznym zapytaniu i dodać do niego pozostałe interesujące nas kolumny, które będą pobierane z wewnętrznego zapytania, odpowiedzialnego za filtrowanie oraz sortowanie. Zapytanie SQL po modyfikacji może więc wyglądać w następujący sposób:</p>
<pre class="brush: sql; title: ; notranslate">
SET @a:=0;
SELECT @a:=@a+1, IP FROM (
SELECT st.IP
FROM `stats` st JOIN
`sources` so ON st.source_id = st.source_id
WHERE st.created_at BETWEEN &quot;2011-01-01 00:000:00&quot; AND &quot;2011-01-01 23:59:59&quot;
AND st.IP LIKE &quot;1%&quot;
AND st.source_id=1
ORDER BY st.IP
) AS sub
</pre>
<p>Numerowanie wierszy w wyniku powyższej modyfikacji będzie poprawne:</p>
<pre>
row     IP
------  ---------------
1       100.113.10.222
2       100.113.10.222
3       100.113.10.222
4       104.87.121.89
5       104.87.121.89
6       104.87.121.89
[...]
</pre>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/bazy-danych/numerowanie-wierszy-w-mysql.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zmiany algorytmu Google czyli nie taki Pingwin straszny</title>
		<link>https://blog.visionsoftware.pl/pozycjonowanie-seo/zmiany-algorytmu-google-czyli-nie-taki-pingwin-straszny.html</link>
		<comments>https://blog.visionsoftware.pl/pozycjonowanie-seo/zmiany-algorytmu-google-czyli-nie-taki-pingwin-straszny.html#comments</comments>
		<pubDate>Thu, 31 May 2012 20:10:57 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[Pozycjonowanie]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[Pingwin]]></category>
		<category><![CDATA[pozycjonowanie]]></category>
		<category><![CDATA[seo]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=602</guid>
		<description><![CDATA[Pod koniec zeszłego miesiąca Google wprowadziło zmiany w swoim algorytmie wyszukiwarki. Po poprzednim, nazwanym Panda, wielu osobom zmroził teraz krew w żyłach Pingwin. Dokonane zmiany wpłynęły szczególnie mocno na agresywnych pozycjonerów, nie dbających o jakość. Jak więc bronić się przed spadkami w SERPach? Od czasu wprowadzenia zmian w algorytmie minął już pewny okres czasu, można spotkać się jednak z różnymi zdaniami na temat jego efektów. Oczywiście SEO nie umarło, należy tylko bardziej słuchać Google i [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Pod koniec zeszłego miesiąca Google wprowadziło zmiany w swoim algorytmie wyszukiwarki. Po poprzednim, nazwanym Panda, wielu osobom zmroził teraz krew w żyłach Pingwin. Dokonane zmiany wpłynęły szczególnie mocno na agresywnych pozycjonerów, nie dbających o jakość. Jak więc bronić się przed spadkami w SERPach?<span id="more-602"></span></p>
<p>Od czasu wprowadzenia zmian w algorytmie minął już pewny okres czasu, można spotkać się jednak z różnymi zdaniami na temat jego efektów. Oczywiście SEO nie umarło, należy tylko bardziej słuchać Google i zwracać uwagę na jakość swoich poczynań.</p>
<h3>Pingwin a jakość strony, czyli on-site optimization</h3>
<p>Najważniejszą rzeczą, jaką można zauważyć po wprowadzeniu Pingwina jest to, że Google zaczyna przykładać mniejszą wagę do treści samych linków prowadzących do pozycjonowanej strony, a bardziej zwraca uwagę na ich powiązanie tematyczne oraz jakość. Wykrywanie spamu zostało znacznie poprawione, a analiza stron jest bardziej szczegółowa niż wcześniej. Warto więc jeszcze bardziej zwrócić uwagę na aspekty, które liczyły się już wcześniej:</p>
<ul>
<li>unikać powielania treści (duplicate content)</li>
<li>unikać powtarzania designu strony (duplicate design)</li>
<li>zadbać o odpowiednią ilość tekstu na podstronach</li>
<li>uzupełniać tekst o grafikę, filmy</li>
<li>wyróżniać słowa kluczowe w tekście (poprzez HTML a teraz także CSS)</li>
<li>zadbać o natężenie słów kluczowych – nie można przesadzić, liczy się naturalność</li>
<li>nie używać bloków słów kluczowych umieszczonych w stopce lub panelu bocznym, które są stworzone tylko dla Google</li>
</ul>
<p>Strony, które zostaną uznane za spamerskie lub łamią niektóre z wytycznych, mogą się narazić na obniżenie swojej pozycji. Oczywiście dotyczy to zarówno stron pozycjonowanych, jak i tych które do nich linkują. Ważne jest to, że obniżenie przez Google siły stron linkujących, wpłynie ostatecznie na docelowy serwis.</p>
<p>Dlatego najważniejszą sprawą jest dbanie o jakość treści. Powinna być tworzona z myślą o użytkownikach, a nie tylko i wyłącznie o silniku wyszukiwarki. Pingwin spowodował, że Google znacznie lepiej wykrywa spam i nieodpowiednie techniki SEO. Ważne jest więc poszukiwanie linków z wysokiej jakości stron oraz zadbanie o własne zaplecze (o czym będzie mowa później).</p>
<h3>Różnorodność linków</h3>
<p>Teoretycznie Google lepiej traktuje strony pozycjonowane w naturalny sposób, korzystające z wite hat SEO. Oczywiście nie zawsze ci, którzy łamią te zasady dostają kary, a ich przeciwnicy są wyżej w wyniku wyszukiwania. Niemniej po Pingwinie można zauważyć, że strony, które były agresywnie linkowane na małą liczbę słów kluczowych, raczej spadały w SERPach. Co można więc zrobić, aby nasze działania SEO Gogle odbierał jako naturalne?</p>
<p>Na początek główne frazy po których pozycjonujemy, należy różnicować pod względem treści linków. Cześć powinna być dokładna (np. &#8222;biura rachunkowe&#8221;), ale warto korzystać także z ich różnego rodzaju odmian (np. &#8222;tanie biura rachunkowe&#8221;, &#8222;najlepsze biura rachunkowe&#8221; itp.).</p>
<p>Dobrym rozwiązaniem jest pozycjonowanie długiego ogona (ang. long tail), czyli większej liczby mniej popularnych fraz. Dzięki temu dla Google takie budowanie pozycji jest bardziej naturalne. Oprócz wyboru większej liczby fraz należy kierować linki na różne podstrony serwisu. W uproszczeniu, zamiast pozycjonować agresywnie stronę główną sklepu interentowego na frazę „telewizory” lepiej linkować go po frazach &#8222;telewizory LCD&#8221;, &#8222;telewizory plazmowe&#8221;, &#8222;Samsung UE40D5500&#8243; itd. W dwóch pierwszych przypadkach link powinien kierować na odpowiednią kategorię, w ostatnim na konkretny produkt. Oczywiście należy zbudować odpowiednio duży i wartościowy zestaw takich fraz.</p>
<p>Warto od czasu do czasu zostawić też gdzieś link w naturalnej postaci, tak jak to robią najczęściej użytkownicy (anchor jako URL lub nazwa strony www), a nawet w postaci &#8222;kliknij tutaj&#8221; lub &#8222;odwiedź nas&#8221;.</p>
<h3>Ministrony powiązane tematycznie</h3>
<p>Dbanie o dobrej jakości linki nigdy nie było proste. Oczywiście zamiast ich szukać, możemy sami je stworzyć. Do tego celu warto zbudować własne serwisy zapleczowe, powiązane tematycznie z pozycjonowanym serwisem, które będą do niego linkowały. Nie jest to do końca zgodne z wytycznymi Google, jednak przynosi nadal korzyści.</p>
<p>Warto dobrze przyłożyć się do budowy takich serwisów z założeniem, że są one tworzone pod kątem użytkowników a nie wyszukiwarek. Należy więc zwrócić uwagę na:</p>
<ul>
<li>Unikalną, ciekawą, poprawną gramatycznie oraz stylistycznie treść</li>
<li>Różnorodność w budowie i wyglądzie poszczególnych serwisów</li>
<li>Różne rodzaje użytych CMS</li>
<li>Różne IP dla poszczególnych serwisów</li>
</ul>
<p>Takie strony powinny mieć przynajmniej około 20 podstron i co jakiś czas być aktualizowane oraz rozbudowywane o nową treść. Ogólna zasada &#8211; im bardziej naturalnie i niezwiązanie ze sobą wyglądają nasze serwisy, tym większa będzie ich siła (i mniejsza szansa na bana lub filtr). Wszyscy, którzy zastanawiają się nad budową większej sieci ministron, powinni się zapoznać ze świetnym artykułem Zgreda: <a href="http://seo.zgred.pl/sposob-linkowania-dla-100-domen-case-study-772">Sposób linkowania dla 100 domen</a>.</p>
<h3>Wysokiej jakości sieci prywatnych blogów</h3>
<p>Presell pages nie są postrzegane jako white hat SEO, jednak używanie ich w umiejętny sposób może być korzystne. Warto więc posiadać sieć prywatnych, moderowanych serwisów z dobrą jakościowo treścią. Ważne, aby linki znajdujące się w tekście były powiązane tematycznie z jak najbardziej naturalnym artykułem. W SEO liczy się często jakość a nie ilość, większą moc da kilka wysokiej jakości linków niż znacznie więcej ze spamerskich serwisów. Najlepiej by było, gdyby całe precle zostały tematycznie powiązane z pozycjonowanym serwisem. Obecnie często można spotkać takie serwisy, które przyjmują teksty tylko z określonych kategorii, na przykład zdrowie i uroda, turystyka lub komputery i Internet.</p>
<h3>Pozyskiwanie linków zgodnie z zasadami Google</h3>
<p>To naturalnie trudniejsze zadanie, ale może dać nam dużą korzyść. Będzie to wyśmienite uzupełnienie wszystkich pozostałych opisanych technik, które mogą być postrzegane przez Google jako nieodpowiednie.</p>
<p>Warto więc dbać o wysokiej jakości treści na stronach, którą użytkownicy mogą sami linkować i udostępniać innym za pośrednictwem najróżniejszych mediów. Dobrze budować pozycję eksperta, publikować teksty w branżowych serwisach lub serwisach wymiany treści. Wyśmienitym miejscem na zbieranie linków są także serwisy społecznościowe, fora dyskusyjne itp. Warto czasem samemu rozpocząć dyskusję w takich miejscach, co może dać nam nie tylko linki, ale także inne profity. Wkraczamy tu trochę w buzz marketing, niemniej jednak takie działania mogą wspomagać w dużym stopniu SEO.</p>
<p><em>Niniejszy artykuł powstał na podstawie analizy dokonanej przez serwis micrositemasters.com, Josha Bachynskiego, informacji zaczerpniętych z bloga Zgreda oraz własnych obserwacji pozycjonowanych stron.</em></p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/pozycjonowanie-seo/zmiany-algorytmu-google-czyli-nie-taki-pingwin-straszny.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 5.4.3 i PHP 5.3.13 wydane z problemami</title>
		<link>https://blog.visionsoftware.pl/programowanie-php/php-5-4-3-i-php-5-3-13-wydane-z-problemami.html</link>
		<comments>https://blog.visionsoftware.pl/programowanie-php/php-5-4-3-i-php-5-3-13-wydane-z-problemami.html#comments</comments>
		<pubDate>Wed, 09 May 2012 21:50:56 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[PHP 5.3]]></category>
		<category><![CDATA[PHP 5.4]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=591</guid>
		<description><![CDATA[W ostatnich dniach pojawiło się małe zamieszanie przy okazji aktualizacji PHP. 3 maja wypuszczono wersje 5.4.2 i 5.3.12, poprawiające niewykrytą od 8 lat lukę w bezpieczeństwie, obecną w PHP pracującym w trybie CGI. Jak się jednak szybko okazało, nie rozwiązało to problemu i niektóre systemy nadal pozostały na nią podatne. Najnowsze wersje 5.4.3 oraz 5.3.13 mają już rozwiązywać ten problem całkowicie. Na czym polega błąd CVE-2012-182 zgłoszony przez De Eindbazen&#8217;a? Jeśli PHP działa w trybie [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>W ostatnich dniach pojawiło się małe zamieszanie przy okazji aktualizacji PHP. 3 maja wypuszczono wersje 5.4.2 i 5.3.12, poprawiające niewykrytą od 8 lat lukę w bezpieczeństwie, obecną w PHP pracującym w trybie CGI. Jak się jednak szybko okazało, nie rozwiązało to problemu i niektóre systemy nadal pozostały na nią podatne. Najnowsze wersje 5.4.3 oraz 5.3.13 mają już rozwiązywać ten problem całkowicie.<span id="more-591"></span></p>
<p>Na czym polega błąd CVE-2012-182 zgłoszony przez De Eindbazen&#8217;a? Jeśli PHP działa w trybie CGI (np. Apache mod_cgid), możliwe jest przekazywanie dodatkowych parametrów wykonania skryptu. Niestety, z powodu błędnego przetwarzania parametrów w URL, które nie zawierają znaku &#8222;=&#8221;, umożliwia to potencjalnemu intruzowi wykonanie wielu niebezpiecznych czynności. Jedną z nich może być na przykład wyświetlenie kodu przetwarzanego skryptu, czego można dokonać, używając parametru <code>-s</code> w następujący sposób:</p>
<pre class="brush: xml; light: true; title: ; notranslate">

http://localhost/index.php?-s

</pre>
<p>Parametr w postaci <code>?-s&amp;=1</code> jest jednak całkowicie bezpieczny.</p>
<p>Po wydaniu poprawki 5.4.2 i 5.3.12, która miała rozwiązać problem okazało się, że część systemów bazujących na PHP w konfiguracji CGI jest nadal podatna na niebezpieczeństwo. Opublikowane 8 maja wersje PHP 5.4.3 i 5.3.13 powinny ostatecznie rozwiązywać ten problem.</p>
<p>Ci, którzy nie mogą dokonać aktualizacji, powinni do zabezpieczenia się wykorzystać odpowiednie reguły <code>mod_rewrite</code> Apache. Jak podano na php.net, można skorzystać z następującego rozwiązania:</p>
<pre class="brush: xml; light: true; title: ; notranslate">
RewriteCond %{QUERY_STRING} ^[^=]*$
RewriteCond %{QUERY_STRING} %2d|\- [NC]
RewriteRule .? - [F,L]
</pre>
<p>Należy jednak uważać, gdyż powyższe reguły mogą zablokować część poprawnych Urli (np. ?top-40). Z tego względu należy je przetestować i dopasować do swoich potrzeb.</p>
<p>Wersja PHP 5.4.3 dodatkowo rozwiązuje problem z przepełnianiem bufora w <code>apache_request_headers()</code> (CVE-2012-2329). PHP 5.3 nie jest podatne na ten błąd.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/programowanie-php/php-5-4-3-i-php-5-3-13-wydane-z-problemami.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL: grupowanie i zliczanie według dat</title>
		<link>https://blog.visionsoftware.pl/bazy-danych/mysql-grupowanie-i-zliczanie-wedlug-dat.html</link>
		<comments>https://blog.visionsoftware.pl/bazy-danych/mysql-grupowanie-i-zliczanie-wedlug-dat.html#comments</comments>
		<pubDate>Mon, 30 Apr 2012 10:59:06 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[Bazy danych]]></category>
		<category><![CDATA[count]]></category>
		<category><![CDATA[daty]]></category>
		<category><![CDATA[group by]]></category>
		<category><![CDATA[grupowanie]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=574</guid>
		<description><![CDATA[Bardzo często podczas pobierania danych z bazy, zachodzi potrzeba budowania raportu z grupowaniem na okresy: dni, tygodnie, miesiące, itd. Niekiedy dochodzi do tego potrzeba podziału na wybrane grupy. W niniejszym tekście przedstawię kilka przykładowych sposobów na takie zapytania z użyciem dat w MySQL. Do poniższych przykładów będzie wykorzystana fikcyjna, uproszczona baza danych, zawierająca statystyki wejść na stronę www. Tabela stats zawiera dane na temat wejść i jest powiązana z tabelą sources zawierającą źródła wejść (bezpośrednie, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Bardzo często podczas pobierania danych z bazy, zachodzi potrzeba budowania raportu z grupowaniem na okresy: dni, tygodnie, miesiące, itd. Niekiedy dochodzi do tego potrzeba podziału na wybrane grupy. W niniejszym tekście przedstawię kilka przykładowych sposobów na takie zapytania z użyciem dat w MySQL.<span id="more-574"></span></p>
<p>Do poniższych przykładów będzie wykorzystana fikcyjna, uproszczona baza danych, zawierająca statystyki wejść na stronę www. Tabela <code>stats</code> zawiera dane na temat wejść i jest powiązana z tabelą <code>sources</code> zawierającą źródła wejść (bezpośrednie, wyszukiwarka, odnośnik).</p>
<p><img class="aligncenter size-full wp-image-575" title="Model bazy danych: statystyki" src="http://blog.visionsoftware.pl/wp-content/uploads/2012/04/DB_model_stats_www.png" alt="Model bazy danych: statystyki strony www" width="474" height="175" /></p>
<p>Do wypełnienia tabeli fikcyjnymi danymi można użyć poniższej procedury:</p>
<pre class="brush: sql; title: ; notranslate">
DELIMITER $$

CREATE DEFINER=`root`@`%` PROCEDURE `randstats`(insertLimit INT)
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE randIP VARCHAR(15);
DECLARE randSoudce_id INT;
DECLARE randCreated_at DATETIME;

WHILE i &amp;lt; insertLimit DO
SET randIP = CONCAT_WS('.', FLOOR(1 + (RAND() * 255)), FLOOR(1 + (RAND() * 255)), 
FLOOR(1 + (RAND() * 255)), FLOOR(1 + (RAND() * 255)));
SET randSoudce_id = FLOOR(1 + (RAND() * 3));
SET randCreated_at = '2010-01-01 00:00:00' + INTERVAL FLOOR(1 + (RAND() * 60*24*7*4*12*2)) MINUTE;

INSERT INTO `stats`(source_id, created_at, IP) VALUES (randSoudce_id, randCreated_at, randIP);

SET i = i + 1;
END WHILE;
END $$

DELIMITER ;
</pre>
<pre class="brush: sql; title: ; notranslate">
call randstats(100000);
</pre>
<h3>Grupowanie względem dnia</h3>
<p>Powiedzmy, że zależy nam na wyciągnięciu statystyk wejść na stronę www z ostatniego miesiąca, z podziałem na poszczególne dni. W tym celu wystarczy skorzystać z funkcji <code>DATE()</code>, która zwraca samą datę z wyrażenia typu <code>datetime</code>.</p>
<pre class="brush: sql; title: ; notranslate">
SELECT
DATE(created_at) AS dzien,
COUNT(*) AS ilosc
FROM stats
WHERE created_at BETWEEN &quot;2011-01-01 00:00:00&quot; AND &quot;2011-01-31 23:59:59&quot;
GROUP BY dzien
ORDER BY dzien;
</pre>
<p>Wynik wywołania zapytania będzie następujący:</p>
<pre>
dzien       ilosc
----------  ------
2011-01-01  168
2011-01-02  187
2011-01-03  190
2011-01-04  201
...
</pre>
<h3>Grupowanie względem tygodnia</h3>
<p>Oczywiście sytuacja jest analogiczna do powyższego, będziemy jednak pobierali statystyki z ostatniego roku. Do odpowiedniego grupowania potrzebna będzie funkcja <code>DATE_FORMAT()</code> lub <code>YEARWEEK()</code>. Lepiej będzie skorzystać z tej drugiej, z uwagi na lepszą wydajność.</p>
<p>Funkcja <code>YEARWEEK()</code> zwraca w MySQL sześciocyfrowy ciąg, określający rok oraz numer tygodnia. Pierwszym parametrem jest data, natomiast drugim, opcjonalnym, tryb w jakim ma działać. Określa czy tydzień zaczyna się od niedzieli, czy też od poniedziałku (domyślną wartością jest zmienna systemowa <code>default_week_format</code>).</p>
<pre class="brush: sql; title: ; notranslate">
SELECT
YEARWEEK(created_at) AS tydzien,
COUNT(*) AS ilosc
FROM stats
WHERE created_at BETWEEN &quot;2011-01-03 00:00:00&quot; AND &quot;2011-04-31 23:59:59&quot;
GROUP BY tydzien
ORDER BY tydzien;
</pre>
<p>Wynik wywołania zapytania będzie następujący:</p>
<pre>
tydzien  ilosc
-------  ------
201101   1320
201102   1320
201103   1321
201104   1250
...
</pre>
<h3>Grupowanie względem miesiąca</h3>
<p>W tym przypadku najlepiej będzie skorzystać z funkcji <code>EXTRACT()</code> z odpowiednim parametrem <code>YEAR_MONTH</code>, dzięki czemu otrzymamy sześcioznakowy ciąg: połączenie roku oraz miesiąca. Pobranie pogrupowanych statystyk na dany miesiąc w roku 2011 może więc wyglądać następująco:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT
EXTRACT(YEAR_MONTH FROM created_at) AS miesiac,
COUNT(*) AS ilosc
FROM stats
WHERE created_at BETWEEN &quot;2011-01-01 00:00:00&quot; AND &quot;2011-12-31 23:59:59&quot;
GROUP BY miesiac
ORDER BY miesiac;
</pre>
<p>Wynik wywołania zapytania będzie następujący:</p>
<pre>
miesiac  ilosc
-------  ------
201101   5738
201102   5130
201103   5713
201104   5405
...
</pre>
<h3>Grupowanie względem roku</h3>
<p>W tym przypadku sprawa jest prosta &#8211; wystarczy wykorzystać funkcję <code>YEAR()</code>, która zwraca rok z przekazanej daty:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT
YEAR(created_at) AS rok,
COUNT(*) AS ilosc
FROM stats
GROUP BY rok
ORDER BY rok;
</pre>
<p>Wynik wywołania zapytania będzie następujący:</p>
<pre>
rok     ilosc
------  ------
2010    66793
2011    56547
</pre>
<h3>Grupowanie z uwzględnieniem typu</h3>
<p>Na zakończenie mała ciekawostka, czyli sposób na policzenie ilości wejść na stronę z podziałem na źródła. Do tego celu wykorzystamy pierwsze zapytanie (grupowanie na dzień), wymaga ono jednak pewnej modyfikacji, w postaci odpowiedniego wywołania funkcji <code>SUM()</code>.</p>
<p>Na początek należy przypomnieć, że źródła wejść w tabeli <code>sources</code> przedstawiają się następująco:</p>
<pre>
source_id  source_name
---------  -------------
1          bezpośrednie
2          wyszukiwarka
3          odnośnik
</pre>
<p>Tak, więc aby zliczyć wystąpienia poszczególnych źródeł w podziale na dni, należy użyć odpowiednio instrukcji <code>CASE</code> w połączeniu z <code>SUM()</code>. Widać to na poniższym przykładzie:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT
DATE(created_at) AS dzien,
SUM(CASE WHEN`source_id` = 1 THEN 1 ELSE 0 END) AS bezposrednie,
SUM(CASE WHEN`source_id` = 2 THEN 1 ELSE 0 END) AS wyszukiwarka,
SUM(CASE WHEN`source_id` = 3 THEN 1 ELSE 0 END) AS odnosnik
FROM stats
WHERE created_at BETWEEN &quot;2011-01-01 00:00:00&quot; AND &quot;2011-01-31 23:59:59&quot;
GROUP BY dzien
ORDER BY dzien;
</pre>
<p>Wynik wywołania zapytania będzie następujący:</p>
<pre>
dzien       bezposrednie  wyszukiwarka  odnosnik
----------  ------------  ------------  ---------
2011-01-01  50            69            49
2011-01-02  77            47            63
2011-01-03  61            66            63
2011-01-04  62            55            84
2011-01-05  55            57            56
2011-01-06  69            64            59
...
</pre>
<p>Artykuł został oparty na tekście ze strony http://www.techfounder.net</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/bazy-danych/mysql-grupowanie-i-zliczanie-wedlug-dat.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wydano PHP 5.4.1 i 5.3.11</title>
		<link>https://blog.visionsoftware.pl/programowanie-php/wydano-php-5-4-1-i-5-3-11.html</link>
		<comments>https://blog.visionsoftware.pl/programowanie-php/wydano-php-5-4-1-i-5-3-11.html#comments</comments>
		<pubDate>Fri, 27 Apr 2012 17:53:26 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[PHP 5.3]]></category>
		<category><![CDATA[PHP 5.4]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=568</guid>
		<description><![CDATA[Najnowsza wersja PHP 5.4 doczekała się po niespełna dwóch miesiącach swojej pierwszej poprawki. Także gałąź 5.3 została uaktualniona, lista wszystkich zmian obejmuje poprawę stabilności poprzez poprawienie ponad 60 błędów, z których część związana jest z kwestiami bezpieczeństwa. Lista poprawek odnosi się zarówno do jądra języka, jak i niektórych rozszerzeń. Pełną listę zmian, jakie zostały dokonane w wersjach PHP 5.4.1.oraz 5.3.11, można znaleźć tutaj. Oczywiście wszystkim użytkownikom zaleca się ze względów bezpieczeństwa jak najszybsze uaktualnienie do [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Najnowsza wersja PHP 5.4 doczekała się po niespełna dwóch miesiącach swojej pierwszej poprawki. Także gałąź 5.3 została uaktualniona, lista wszystkich zmian obejmuje poprawę stabilności poprzez poprawienie ponad 60 błędów, z których część związana jest z kwestiami bezpieczeństwa.<span id="more-568"></span></p>
<p>Lista poprawek odnosi się zarówno do jądra języka, jak i niektórych rozszerzeń. Pełną listę zmian, jakie zostały dokonane w wersjach PHP 5.4.1.oraz 5.3.11, można znaleźć <a title="Lista zmian w PHP 5.4.1. i 5.3.11" href="http://www.php.net/ChangeLog-5.php#5.4.1">tutaj</a>. Oczywiście wszystkim użytkownikom zaleca się ze względów bezpieczeństwa jak najszybsze uaktualnienie do najnowszej wersji.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/programowanie-php/wydano-php-5-4-1-i-5-3-11.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Zmiana algorytmu Google &#8211; stawiamy na jakość</title>
		<link>https://blog.visionsoftware.pl/pozycjonowanie-seo/zmiana-algorytmu-google-stawiamy-na-jakosc.html</link>
		<comments>https://blog.visionsoftware.pl/pozycjonowanie-seo/zmiana-algorytmu-google-stawiamy-na-jakosc.html#comments</comments>
		<pubDate>Fri, 27 Apr 2012 17:43:47 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[Pozycjonowanie]]></category>
		<category><![CDATA[algorytm]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[pozycjonowanie]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[SERP]]></category>
		<category><![CDATA[spam]]></category>
		<category><![CDATA[wyszukiwarka]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=563</guid>
		<description><![CDATA[W ciągu najbliższych dni Google zamierza dokonać zmian w algorytmie, które są ukierunkowane na zepchnięcie z wyników wyszukiwań spamu. Największą szansę na opuszczenie wysokich pozycji w SERPach będą miały strony, które naruszają wyznaczniki jakości przedstawione przez Google. Ważną zmianą, jaka ma pojawić się w najnowszej aktualizacji algorytmu Google, jest lepsze identyfikowanie spamerskich stron. Chodzi głównie o witryny, które zawierają teksty stworzone głównie pod wyszukiwarki, będące najczęściej zlepkiem słów kluczowych. Są one zazwyczaj przygotowane przez automatyczne [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>W ciągu najbliższych dni Google zamierza dokonać zmian w algorytmie, które są ukierunkowane na zepchnięcie z wyników wyszukiwań spamu. Największą szansę na opuszczenie wysokich pozycji w SERPach będą miały strony, które naruszają wyznaczniki jakości przedstawione przez Google.<span id="more-563"></span></p>
<p>Ważną zmianą, jaka ma pojawić się w najnowszej aktualizacji algorytmu Google, jest lepsze identyfikowanie spamerskich stron. Chodzi głównie o witryny, które zawierają teksty stworzone głównie pod wyszukiwarki, będące najczęściej zlepkiem słów kluczowych. Są one zazwyczaj przygotowane przez automatyczne synonimizatory, podmieniające oznaczone wyrazy w tekście czyniąc go całkowicie nieczytelnym dla normalnego użytkownika.</p>
<p>Zmiana algorytmu Google ma także wpłynąć na strony, zawierające niedopasowane linki. Chodzi o sytuację, w której w treść tekstu wstawione są zupełnie niezwiązane tematycznie z nim linki.</p>
<p>Obie powyższe sytuacje są niezwykle często spotykane w kiepskiej jakości serwisach presell page. Czy będzie to oznaczało, że po aktualizacji będą miały one problemy i stracą na sile?</p>
<p>Oczywiście zmiany w algorytmie mają prowadzić według Google do polepszenia pozycji w SERPach przez wartościowe serwisy. Jak radzą jego przedstawiciele, najlepiej stosować w tym celu white hat SEO. W skrócie główne zasady, przedstawiane przez Google, są następujące:</p>
<ul>
<li>strony powinny być tworzone dla użytkowników, a nie wyszukiwarek (np. nie należy stosować osobnej treści dla Google i odwiedzających)</li>
<li>należy unikać sztuczek mających na celu podniesienie pozycji w wyszukiwarkach (np. ukryty tekst lub linki)</li>
<li>nie powinno się korzystać z systemów wymiany linkami (SWL), unikać linkowania do spamerskich stron oraz &#8222;złego towarzystwa&#8221;</li>
<li>nie należy używać nieautoryzowanego oprogramowania do zgłaszania stron lub sprawdzania rankingów, które wysyłają automatyczne zapytania Google (np. WebPosition Gold™)</li>
</ul>
<p>Oczywiście warto pamiętać, aby treść na stronie była odpowiednio przygotowana i nie była kopią już istniejącej. Powinna stanowić wysokiej jakości źródło informacji i nie być przeładowana reklamami. Witryna musi być także bezpieczna dla użytkownika, nie może zawierać złośliwego oprogramowania. Powinna także w miarę szybko się ładować.</p>
<p>Jak zmiany w algorytmie wpłyną na wyniki wyszukiwania? Efekty będą zapewne widoczne już niebawem.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/pozycjonowanie-seo/zmiana-algorytmu-google-stawiamy-na-jakosc.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Podpowiadanie typów w PHP</title>
		<link>https://blog.visionsoftware.pl/programowanie-php/podpowiadanie-typow-w-php.html</link>
		<comments>https://blog.visionsoftware.pl/programowanie-php/podpowiadanie-typow-w-php.html#comments</comments>
		<pubDate>Sat, 31 Mar 2012 12:08:32 +0000</pubDate>
		<dc:creator><![CDATA[Marcin Fliszta]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[callable]]></category>
		<category><![CDATA[interfejs]]></category>
		<category><![CDATA[obiekt]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[podpowiadanie typów]]></category>
		<category><![CDATA[tablica]]></category>
		<category><![CDATA[type hinting]]></category>

		<guid isPermaLink="false">http://blog.visionsoftware.pl/?p=554</guid>
		<description><![CDATA[PHP nie wymaga precyzowania typu podczas definicji zmiennej. Jest on określany na podstawie kontekstu, w jakim ta zmienna została użyta, z możliwością automatycznych konwersji. Możemy także samodzielnie zmieniać typ zmiennej poprzez rzutowanie lub odpowiednie funkcje. Rodzi to problemy szczególnie przy przekazywaniu parametrów do funkcji, jednak w tym przypadku można dla niektórych stosować podpowiadanie typów (ang. type hinting). W PHP mamy do dyspozycji łącznie 9 typów zmiennych: 4 typy proste &#8211; logiczny, całkowity, zmiennoprzecinkowy i znakowy [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>PHP nie wymaga precyzowania typu podczas definicji zmiennej. Jest on określany na podstawie kontekstu, w jakim ta zmienna została użyta, z możliwością automatycznych konwersji. Możemy także samodzielnie zmieniać typ zmiennej poprzez rzutowanie lub odpowiednie funkcje. Rodzi to problemy szczególnie przy przekazywaniu parametrów do funkcji, jednak w tym przypadku można dla niektórych stosować podpowiadanie typów (ang. <em>type hinting</em>).<span id="more-554"></span></p>
<p>W PHP mamy do dyspozycji łącznie 9 typów zmiennych:</p>
<ul>
<li>4 typy proste &#8211; logiczny, całkowity, zmiennoprzecinkowy i znakowy</li>
<li>2 złożone – tablicowy i obiektowy</li>
<li>3 specjalne – identyfikator zasobu (<code>resorce</code>), pusty (<code>NULL</code>) oraz wywoływalny (<code>callable</code>)</li>
</ul>
<p>Podpowiadanie typów w PHP nie umożliwia niestety rozpoznawania wszystkich wymienionych powyżej. Od wersji 5 języka możemy to robić dla obiektów, interfejsów, tablic (od PHP 5.1), oraz parametrów wywoływalnych (PHP 5.4).</p>
<p>Podpowiadanie typów możemy stosować w zwykłych funkcjach, oraz metodach klas. Wystarczy w tym celu przed nazwą zmiennej podać oczekiwany typ (<code>array</code>, <code>callable</code>, nazwę konkretnej klasy lub interfejsu)</p>
<h3>Podpowiadanie typów &#8211; obiekty</h3>
<p>W przypadku podpowiadania typów obiektowych należy pamiętać o bardzo ważnej rzeczy: jeśli parametrem musi być konkretna klasa lub interfejs, dozwoleni są także ich potomkowie, uczestniczący w hierarchii dziedziczenia.</p>
<p>Gdy zostanie określony wymagany typu obiektu, przekazanie innego spowoduje powstanie błędu. Zostało to pokazane na poniższym przykładzie:</p>
<pre class="brush: php; title: ; notranslate">
class Factory{
	public function produce(Product $product){
		print &quot;Produkuję &quot; . get_class($product);
	}
}

class Stock{
	/* ... */
}

class Product{
	/* ... */
}

class Car extends Product{
	/* ... */
}

class Motorbike extends Product{
	/* ... */
}

$factory = new Factory();
$stock = new Stock();
$car = new Car();
$motorbike = new Motorbike();

$factory-&gt;produce($car);
$factory-&gt;produce($motorbike);
$factory-&gt;produce($stock);
</pre>
<p>Zdefiniowane zostały klasy: <code>Factory</code>, <code>Stock</code>, <code>Product</code> oraz dziedziczące po nim <code>Car</code> oraz <code>Motorbike</code>. Klasa fabryki posiada zdefiniowaną jedną metodę, odpowiadającą za produkcję. Wymaga ona przekazania obiektu typu <code>Product</code>. Na powyższym listingu przekazano do niej natomiast dozwolone parametry wywodzące się z klasy <code>Product</code>, ale na koniec omyłkowo także <code>Stock</code>. Efekt będzie następujący:</p>
<pre class="brush: xml; light: true; title: ; notranslate">
Produkuję Car
Produkuję Motorbike
Fatal error: Argument 1 passed to Factory::produce() must be an instance of 
Product, called in typehinting.php on line 31 and defined in typehinting.php 
on line 3
</pre>
<p>Jak wspomniano już wcześniej, podpowiadanie typów w przypadku obiektów działa zarówno dla utworzonych bezpośrednio, jak i dziedziczących po określonym w definicji. Poprawne będzie więc też następujące wywołanie:</p>
<pre class="brush: php; title: ; notranslate">
$factory = new Factory();
$product = new Product();

$factory-&gt;produce($product);
</pre>
<p>W powyższym przypadku może nie jest to do końca pożądane, jednak w praktyce częściej będziemy oczekiwali obiektów klas dziedziczących. Oczywiście, gdy tego chcemy, możemy zawęzić wymagany typ tylko do klasy pochodnej.</p>
<pre class="brush: php; title: ; notranslate">
class Factory{
	public function produce(Car $product){
		print &quot;Produkuję tylko samochody&quot;;
	}
}
</pre>
<p>W przypadku podpowiadania typów można stosować także wartości domyślne. Jeśli w naszej fabryce przewidujemy strajk, możemy posłużyć się następującą definicją:</p>
<pre class="brush: php; title: ; notranslate">
class Factory{
	public function produce(Product $product = null){
		print &quot;Produkuję&quot; . get_class($product);
	}
}

$factory = new Factory();
$factory-&gt;produce();
</pre>
<p>Analogicznie do powyższych informacji, podpowiadanie typów może być używane także w przypadku interfejsów. Wystarczy określić, że parametr musi implementować jeden ze zdefiniowanych. Aby zobrazować tą możliwość, dokonamy pewnych zmian klas z pierwszego przykładu. Otóż w naszej fabryce w Indiach zamierzamy wyprodukować limitowaną wersję samochodu, o zwiększonej mocy silnika. Klasa fabryki otrzyma więc dodatkową możliwość produkcji, a specyfikacja samochodu zostanie odpowiednio zmodyfikowana poprzez implementację interfejsu (pominięto tu klasy zdefiniowane w pierwszym przykładzie):</p>
<pre class="brush: php; title: ; notranslate">
interface limitedEdition{
	public function engineImprovements();
}

class carSpecial extends car implements limitedEdition{
	public function engineImprovements(){
		print &quot;Zwiększona moc silnika&quot;;
	}
}

class FactoryIndia extends Factory {
	public function produceSpecialCar(limitedEdition $car){
		print &quot;Produkuję limitowaną wersję samochodu.&quot;;
	}
}

$factoryIndia = new FactoryIndia();
$car = new car();
$carSpecial = new carSpecial();

$factoryIndia-&gt;produceSpecialCar($carSpecial);
$factoryIndia-&gt;produce($car);
$factoryIndia-&gt;produceSpecialCar($car);
</pre>
<p>Efekt wywołania kodu będzie następujący:</p>
<pre class="brush: xml; light: true; title: ; notranslate">
Produkuję limitowaną wersję samochodu.
Produkuję Car
Fatal error: Argument 1 passed to FactoryIndia::produceSpecialCar() must implement 
interface limitedEdition, called in typehinting.php5 on line 43 and defined in 
typehinting.php on line 32
</pre>
<p>Jak widać, najpierw wyprodukowano edycję limitowaną samochodu przy użyciu nowej linii produkcyjnej, a następnie powrócono do wersji zwykłej. W kolejnym kroku, w wyniku błędu pracownika, uruchomiono jednak ponownie zmodyfikowaną linię produkcyjna dla wersji podstawowej samochodu, co oczywiście zostało szybko wychwycone przez inspektorów kontroli jakości.</p>
<h3>Podpowiadanie typów &#8211; tablice</h3>
<p>Sytuacja jest analogiczna do opisywanych powyżej możliwości w przypadku obiektów. Poniższy przykład obrazuje w jaki sposób zastrzec, aby zdefiniowana funkcja akceptowała jako parametr tylko tablicę:</p>
<pre class="brush: php; title: ; notranslate">
function needArray(array $param){
	print_r($param);
}

$array = array(1, 2, 3);

needArray($array);
</pre>
<p>Możemy także określić domyślą tablicę, dzięki czemu możliwe będzie wywołanie funkcji bez żadnego parametru:</p>
<pre class="brush: php; title: ; notranslate">
function needArray(array $param = array(7, 8, 9)){
	print_r($param);
}
</pre>
<h3>Podpowiadanie typów &#8211; callable</h3>
<p>Jest to najnowsza możliwość podpowiadania typów, wprowadzona w PHP 5.4. Dzięki niej można określić, że parametr przekazywany do funkcji lub metody musi być wywoływalny. Ma to zastosowanie w przypadku stosowania callbacków oraz funkcji anonimowych.</p>
<pre class="brush: php; title: ; notranslate">
function myFunction(callable $callback) {
	echo &quot;Wywołuję callback: &quot; . $callback();
}

myFunction(function() { return 'Witaj!'; });
</pre>
<h3>Podsumowanie</h3>
<p>Jak widać na przedstawionych przykładach, wykorzystanie podpowiadania typów jest niezwykle przydatne i znacznie upraszcza tworzony kod. Nie musimy aż tak wnikliwie sprawdzać przekazywanych argumentów przy pomocy <code>is_array()</code> lub <code>instanceof</code>. Mam nadzieję, że w <em>type hinting</em> w kolejnych wersjach PHP zostanie rozszerzone o typy proste.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.visionsoftware.pl/programowanie-php/podpowiadanie-typow-w-php.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
