Elastic search – nastavení v PHP

Nikdy jsem pořádně nevěděl, co a jak nastavit, aby mi fungovalo dobře  vyhledávání v elasticsearch. Píši si to tady, abych to třeba zase za rok pochopil, když budu něco někde na nějakém webu upravovat.

V rámci PHP používám knihovnu ruflin/elastica

Ze všeho nejdříve je třeba trošku pochopit konfiguraci Indexu. Mějme například takovou to konfiguraci:

$index->create(array(
    "number_of_shards" => 2,
    "number_of_replicas" => 0,
    "analysis" => array(
        "filter" => array(
            "my_ngram" => array(
                "type" => "nGram",
                "min_gram" => 3,
                "max_gram" => 50
            )
        ),
        "analyzer" => array(
            "analyzer_for_indexing" => array(
                "type" => "custom",
                "tokenizer" => "standard",
                "language" => "czech",
                "filter" => (array("lowercase", 'asciifolding', "my_ngram"))
            ),
            "analyzer_for_queries" => array(
                "type" => "custom",
                "tokenizer" => "standard",
                "language" => "czech",
                "filter" => (array("asciifolding", 'lowercase'))
            )
        )
    )
), true); // oprions true -- delete the previous index

Tímto se pouze nastavují filtry a analyzery pro konkrétní index. Dále je pak můžeme používat pro vkládání do indexu, a nebo pro pokládání  query (vyhledávání).

Pro ukládané  dokumenty si nastavím toto mapování:

        $elasticaType = $index->getType('product');

        $mapping = new Mapping();
        $mapping->setType($elasticaType);

        $mapping->setProperties(array(
            'id' => array('type' => 'integer', 'include_in_all' => false),
            'title' => array('type' => 'text', 'analyzer' => 'analyzer_for_indexing', 'include_in_all' => true, 'boost' => 6),
            'ean' => array('type' => 'text', 'analyzer' => 'standard', 'include_in_all' => true, 'boost' => 4),
            'catalog_number' => array('type' => 'text', 'analyzer' => 'standard', 'include_in_all' => true, 'boost' => 3),
            'text' => array('type' => 'text', 'analyzer' => 'analyzer_for_indexing', 'include_in_all' => true),
        ));

        $mapping->send();

Jinými slovy říkám jednotlivým “sloupcům”, že mají používat určitý analyzer, který je nastavený pro tento index.

V rámci ukládání do  indexu používám tyto filtry:

  • lowercase
  • asciifolding – převádí diakritiku na nediakritiku
  • ngram – rozděluje jednotlivé slova po skupinách písmen a vytváří tím různé sloučeniny pro lepší vyhledávání

Pro vyhledávání v indexu pak používám toto:

$index = $this->elasticaClient->getIndex($this->indexName);

$boolQuery = new BoolQuery();
$elasticaQueryString = new MultiMatch();
$elasticaQueryString->setQuery($q);
$elasticaQueryString->setType(MultiMatch::TYPE_PHRASE_PREFIX);
$elasticaQueryString->setFields(['title', 'text']);
$elasticaQueryString->setAnalyzer('analyzer_for_queries');
$boolQuery->addShould($elasticaQueryString);

$elasticaQuery = new Query;
$elasticaQuery->setQuery($boolQuery);
$elasticaQuery->setFrom(0);
$elasticaQuery->setSize(50);

$response = $index->search($elasticaQuery);

Někde jsem se dočetl, že MATCH query používá před vložením do hledání analyzér – tedy před konečným hledáním v indexu zadané query změní  dle nastaveného analyzeru, a teprve potom s touto změnou začne vyhledávat.

Abych se nemusel starat o to, jak je položen dotaz, a třeba v PHP ho nějak upravovat, použiji analyzer, který využívá tyto filtry:

  • asciifolding
  • lowercase

Záměrně zde nepoužívám filter NGRAM, protože tak by vyhledával naprosté nesmysly (např. slovo  tričko by rozdělil na “tri”, “rič”, “čko”, atd – a tím by vyhledával i hodně nerelevantní věci)

Výborná věc je testovat analyzér, jaké hodnoty vyhazuje. To jde tímto příkazem:

dump($index->analyze('Rukávř', ['analyzer' => 'analyzer_for_queries']));

Tímto můžu v pohodě testovat, jak se zdeformuje dotaz, pokud na něj aplikuji nějaký analyzer.

 

 

 

Něco o mě – znalosti a dovednosti – programátor a webový analytik

Weby a PHP

S weby jsem začal experimentovat již na vyšší odborné škole, nějakých 20 let zpátky. Tehdy to byly sice jen takové testování, jak to funguje a díky tomu, že vývoj vysokorychlostního internetu byl ještě v plenách, tak s připojením na internet přes modem byly možnosti z části omezené.

Ze začátku jsem testoval různé technologie, PHP, .NET, JAVA a k tomu přidružené technologie, jako javascript, css, atd. Zjišťoval jsem, co jaká technologie nabízí a v čem budu dále pracovat a rozvíjet své zkušenosti a dovednosti.

Již v té době, řekněme po 2 letech zkoušení, jsem si našel první zakázku – vytvoření objednávkového systému pro nákup CD disků pro jednoho vokalistu, který si svá CD sám nahrával a sám vydával. Zakázka celkem za 3000,- (pro studenta dost peněz pro začátek) obsahovala nákup na internetových stránkách s možností platby bankovní kartou a jednoduchou administrací. Byla napsána v PHP za použití jednoduchého javascriptu a dnes již zastaralého vkládání designových značek přímo do kodu HTML (tedy bez CSS).

Předtím neexistovaly žádné platební systémy, jako GoPay, či PayU. Vše se muselo projednávat s bankou (tuším s Českou spořitelnou) a napojení bylo přes, v tu dobu, nové API 3D Secure.

Tato zakázka se vydařila a zároveň byla pro mě odrazovým můstkem v PHP. Od té doby pracuji nejen v  PHP.

Nette

S Nette jsem přišel do styku nedávno, asi tak před 6-ti lety, kdy se rozhodovalo, na čem se bude stavět nové jádro eshopu pro firmu, ve které jsem pracoval. Zajistil jsem si školení přímo u profesora Nette Davida Grudla, kde jsem teprve poznal kouzlo Nette frameworku a od té doby experimentuji s jeho nasazením všude, kde je to jen možné. Ještě nyní se mi někdy zdá, že je to až moc “magic” a některé metody úplně nechápu, ale je to přirozený vývoj a mám takový pocit, že i pan Profesor Grudl někdy tápe a zjišťuje, jak daná věc vlastně funguje.

Mým prvním výsledkem Nette eshopu je http://www.vyfuky-pema.cz . Zakázka, která byla mimo standardní pracovní proces, se vlivem mnoha změn trošičku protahovala a nakonec jsem práci odevzdal zdarma, neboť mým hlavním cílem bylo naučit se fungovat a zvládat první krůčky a nástrahy, které mě povedou k dokonalému vývoji webů v Nette frameworku. 

S Nette jsem pokračoval také v práci, kterou jsem vykonával pro firmu Religis, kde je na něm postaveno celé nové jádro e-shopů. Byl jsem u zrodu tohoto jádra, pomáhal jsem vymýšlet moduly a vůbec funkčnost celého systému. Celý systém má pak na starosti kolega, ale často jsem se k němu vracel a dodělávál k němu nové moduly.

Můj nový počin v eshopech na Nette je vytvořený soukromý projekt https://www.domaci-nakupy.cz. (projekt uzavřen, ale kody mohu ukázat).

Laravel

Nějaký ten rok si hraju s tímto skvělým frameworkem, v Moraviu jsme na něm vytvořili několik webů a informačních systémů. Jeví se mi daleko lepší, než Nette a to díky široké dokumentaci a také mnoha uživatelů tohoto frameworku – daleko lépe se hledají případné moduly a rozšíření.

Soukromý projekt https://www.nakupy-detem.cz (starší jádro projektu je nyní na https://www.nakupy-detem.sk) je v Laravelu vytvořen. V něm používám i React JS (Košík a nějaké drobnůstky).

Docker

Výborná technologie, která dala základ tomu, že se již nemusí pokaždé nastavovat localhost na spuštění projektu. Stačí si jej pullnout z Gitu, nastartovat Docker a může se testovat, programovat, prostě cokoliv. Samozřejmě je nutné jej nejprve pro daný projekt nastavit, ale již jsem jich dělal tolik, že to dnes již není žádný problém.

Dockerem jsem se začal zabývat tak před 4-mi lety, od té doby mě jej používám pro každý projekt, který vytvářím.

Databáze – Mysql

Kde by byl vývoj PHP, kdyby nebylo pořádného a rychlého databázového enginu, jako je MySQL. Jasně, je to v celku jednoduchá databáze, oproti například Oracle, či PostgreSql, ale pro weby absolutně vyhovující. Tak, jako jsem se zabýval PHP, tak jsem se i zabýval MySQL. Jsem zručný ve vytváření i složitých dotazů s výbornou indexací a tedy i rychlostí. Často důmám nad dotazama a zjišťuji, jakým způsobem by šlo dotaz předělat tak, aby byl ještě o malinko rychlejší. Obecně totiž zjišťuji, že MySQL má největší podíl na rychlosti jak stránek, tak hlavně i serveru jako takového (ono to jde krásně vidět na vytíženém serveru, kdy proces mysql zabírá na 6 procesorů a např. Apache s PHP sotva procesor jeden).

Čím lépe jsou dotazy vytvořeny, tím rychleji fungují stránky (i když jsou používány různé keše, tak databázové dotazy musí běhat rychle) a server obecně dokáže přijímat více požadavků.

Ze začátku jsem pracoval pouze s enginem MyISAM, nyní již vše řeším s INNODB a plně využívám jeho potenciálu na poli cizích klíčů a zamykání řádků namísto celé tabulky. Nyní, když od verze 5.6 je možné v INNODB vytvořit fulltext (který jsem předtím řešil krkolomně přes jinou tabulku v MyISAM), je možné již zcela zavrhnout zastaralý engine MyISAM.

Apache

Webový server Apache je samozřejmou součásti mého webového vývoje. Snad jednou jsem zkoušel i IIS (informační internetovou službu systému Windows), bleskurychle jsem přešel zpět na Apache, který je, dle mého názoru, o mnoho jednodušší a navíc jej využívá většina serverů na světě. 

Zkušenosti s rozběháním a nastavením běhu serveru mám dlouholeté, i když mě vlastně stačí znát jen pár konfiguračních direktiv, které nutně potřebuji pro nastavení funkčnosti Apache a PHP. Další moduly Apache, pokud jsou potřeba pro funkčnost webu, vetšinou řeším nakouknutím do dokumentace a testováním uvedených příkladů.

Důležitou součástí webového serveru je možnost přesměrování webové stránky na jinou, kterou Apache řeší modulem mod_rewrite, který často využívám pro přesměrování například pěkných URL adres a nebo pro vytváření obrázkové keše.

Dalším modulem, který využívám, je mod_headers, kterým dokáži automaticky posílat hlavičky pro nakešování požadavků na straně klienta dle typu souboru.

NGINX

I když pro přímý přístup na web používám Apache, tak Nginx mi slouží jako proxy a to i mezi https a http na lokálním serveru. Nginx mám také spuštěn na lokálním developerském počítači a přes něj se snadněji napojuji na spuštěné dockery. Základní nastavení nginxu umím provést i pro weby, ale zřídka kdy jej použiji.

Javascript

Tak jako jsem spjatý s PHP na straně serveru, tak stejně využívám i možnosti JavaScriptu na straně klienta. Vlastně celou svou administraci pro https://www.nakupy-detem.cz se snažím vytvářet tak, aby byla co nejkomfortnější pro administrátory a tím pádem se bez Javascriptu, a hlavně JQUERY knihovny, neobejdu. Dnes již JQuery není tak markantní, když se dají krásně používat JS funkce od verze 6 a případně i Classy.

Často využívám knihovny třetích stran, jako fancybox (pro vyskakovací okna), nebo Caroufredsel (pro pěkné posuvníky obsahu), tak i základní knihovnu pro JQUERY – UI pro lepší vzhled a funkčnost webu.

A co AJAX (nebo raději AJAJ?). Ano, i toto je mým denním chlebem. Snad vše, co lze, provádím nyní AJAXem a to jak v administraci, tak i na frontové části webů. Vlastně Nette s AJAXem pracuje velmi dobře, proto jej mám rád a často jej využívám.

Dalším mým přáním je vyzkoušet si Web Sockets – ale prozatím jsem nenašel vhodný projekt, na kterém by to mělo smysl dělat.

ReactJS

Je to již nějaký čas, co jsem s tímto skvostem přišel do styku a hned na to naprogramoval (tedy byl jsem součástí týmu) počasí pro jeden portál (pocasi.centrum.cz). Od té doby jsem udělal ještě asi 3 aplikace (například interní aplikace pro kontrolu strojů v hale) a dnes, kdy pracuji na redesignu svého eshopu nakupy-detem.cz, ho používám taktéž.

V rámci reaktu zvládám jak react samotný, tak i se spojením s Reduxem či React Routerem.

Fulltextové enginy – elastic search a Sphinx

S těmito fulltextovými enginy jsem se již setkal dávno a s oběma nadále experimentuji.

Sphinx se mi zdá trošičku horší na konfiguraci, kdy indexy je nutné zadávat do konfiguračního souboru a poté engine restartovat. Kdežto elastic search dovoluje vkládat index pěkně za chodu.

Oba enginy se ukázaly jako velmi rychlé a dobře tak nahrazují MySQL fulltext. Navíc díky použití těchto enginu klesá zátěž na databázi, která je na produkčních serverech velmi vytížená.

Co se týká experimentace ohledně fulltextových filtrů a možností – já jsem si prozatím vždy vystačil se základy. Prozatím jsem se nemusel pouštět do složitějších dotazů na fulltextové enginy tak, aby mi vyhazovaly „zvláštní“ výsledky, vždy mi stačily jednoduché dotazy, které mi ve výsledku vracely Idečka, které jsem obratem poslal do databáze.

Pro fulltext na nový nakupy-detem.cz již používám různé filtry a mapování (ngram a podobné) – testuji lepší vyhledávání.

Linux a server obecně

V Religisu jsem měl na na starost chod všech serverů, i když byly menežované, tak je nutné zajistit a hlídat jejich chod a v případě přetěžování z jakéhokoliv důvodu, najít příčinu a snažit se o co nejrychlejší odstranění příčiny pomalosti serveru. K tomu mi pomáhá znalost základních příkazů Linuxu a často pracuji v SSH přimo na serverech.

Někdy je nutné přenést weby ze serveru na server, což je pro mě již rutinní záležitost (včetně přenostu databáze, DNS záznamů a přenos případných emailů). Dále, zakládání FTP účtů, vytváření databází v MySQL, či jiné přímo serverově věci mi nejsou v žádném případě cizí.

Mimo to mám vlastní server, který je menežovaný a umístěn u firmy VSHOSTING. I když veškeré služby spojene s instalací serveru, či softwaru na něj, provádí zmíněný VSHOSTING a jeho administrátoři, i já často chodím na server přes SSH a pracuji přímo tam. 

S tímto souvisí i správa certifikátu. Spravuji server, který není menežovaný a všechno si tedy musím obstarávat sám, včetně přidávání certifikátu. Proto mám i s tímto zkušenosti. Navíc si spravuji i vlastní certifikáty pro mé soukromé eshopy, takže nákup, vytvoření a použití certifikátů pro zapnutí HTTPS na webu je maličkostí.

Nyní, co mám Ubuntu na svém vývojovém notebooku, tak je nyní používaní linuxu hračkou, i když někdy nastavení opravdu bolí, vždy pomůže Stackoverflow.

Navíc, jelikož používám pro develop Docker, tak základem každého dockeru je správné nastavení běhového prostředí a to právě v linuxu za použití i některých skriptů psaných v SH.

Verzovací systémy – Git (svn)

Bez verzovacího systému se nedá vyvíjet, to je přece jasné. SVN jsem používal dříve v začátcích, avšak jeho nutnost být neustále napojen na Internet, když chci něco commitnout, mě přinutila začít používat GIT. A dobře jsem udělal, rychlý, bezpečný, perfektní. Díky tomu se vývoj v mém působišti mnohonásobně zpřesnil a zrychlil, jelikož nemusíme řešit věci jako “Kdo to smazal z toho kodu?”. Já jsem si na něj navykl tak, že když si zakládám nějakou složku, kde si budu jen psát třeba jen nějaké zápisky z výletu, tak ihned ji dávám do GITu.

Pro své projekty navíc používám službu www.bitbucket.com – takže vše mám ihned všechny kody z jakéhokoliv místa k dispozici.

Jen poznámka pro mne: trošku mě mrzí, že jsem si ještě nepřivykl používat funkci Stash – možná  někdy konečně na to najdu důvod …..

Styly – CSS

Pro své projekty si sám vytvářím HTML šablony (ne grafiku, tu přenechávám grafikovi), proto vím a umím používat CSS. Také se snažím nalézat rozdíly v prohlížečích ( i když např. IE verze statečně ignoruji) a přizpůsobit tak web všem. Rovněž  mám nemalé zkušenosti s vytvářením responzivních webů.

CSS jako takové se mi jeví nějak moc neohrabané, proto raději používám jazyk SASS (http://sass-lang.com/) což je software, napsaný v RUBY, který zavádí lepší organizaci a psaní souborů CSS a zpříjemňuje tak práci se styly.

Ruckus

Tak jako pro zdrojové soubory existuje GIT (nebo SVN), pro databáze existuje Ruckus.

Jde o verzovací nástroj pro databázi, napsaný v PHP, a používá se hlavně pro práci v kolektivu a hlavně pro Deploy projektů. I když jej pro své soukromé projekty nepoužívám (na projektech pracuji pouze já, takže prozatím nemám důvod jej použít), tak ve firemním prostředí je shledávám velmi účinným řešením databázových verzí projektu. Jelikož jsou soubory pro vytvoření, změny databáze uložené v souborech, tak spolu s využitím verzovacího nástroje (GIT či SVN) je pak zaručena určitá bezpečnost a rychlost vývoje projektu v týmu v oblasti změn v databázi.

Testy – testování softwaru

Testování jsem pro sebe zavedl celkem nedávno. Již kdysi jsem testoval za pomocí PHPUnitu, ale až s příchodem Nette testeru jsem se testování naučil mnohem líp. I když zase, své soukromé projekty ještě pod testem nemám (kde vzít na to čas, že?), ale nové projekty, které vytvářím, se již snažím vždy testovat a to za pomocí právě zmíněného Nette testeru.

Ještě mám v hledáčku testování přímo ve vebovém prohlížeči za podpory Selenium testů, také jsem zkoušel, dokonce i některé testy mám vytvořeny pro projekt www.nakupy-detem.cz, ale bojím se, že již jsou testy zastaralé a nefunkční. Mám však v plánu se k nim co možná nejdříve vrátit.

Další znalosti na poli pozice programátora webových projektů:

Souhrně zde uvedu další mé znalosti, které snad nepotřebují širší popis.

– správa DNS – mám vlastní stránky, proto si také sám spravuji k nim DNS

– hardware počítačů – každý správný ajťák si musí umět vytvořit svůj vlastní počítač (samozřejmě ze zakoupených komponent)

– nastavení routerů a síťových služeb – znám problematiku, starám se o síť ve firmě + o domácí routery

– znalostí produktů Atlasianu – Jira, bamboo, wiki, …  – např. přes Bamboo ve firmě deployujeme všechny projekty – výborný software.

– Photoshop – na stříhání grafiky a občasné vytváření bannerů apod.

Analýza

V nadpisu píšu „Programátor a webový analytik“, co to pro mě vlastně ta analýza znamená?

Před tím, než vůbec začnu cokoliv psát, si musím dobře rozmyslet, jakým způsobem kód povedu, jaké jsou případné překážky, zádrhele, jaké k tomu potřebují další nástroje. To všechno musím analyzovat a snažit se najít všechny možné problémy a nedostatky, které daná specifikace/projekt obsahuje.

Z minulosti vím, že se ne úplně na 100% dají předpovídat všechny problémy, které při vývoji mohou nastat, ale z analýzy vyplynou ty hlavní a důležité věci, na které si dát pozor a kterým se bezprostředně při realizaci vyhnout. Z těchto analýz také v závěru vzniká kalkulace a nacenění zadané práce.

imagecreatefromjpeg() : gd-jpeg : JPEG library reports unrecoverable error

Chyba, která se objevuje u nových verzí PHP. Objevuje se, pokud se pokoušíme vytvořit obrázek z JPG funkcí imagecreatefromjpeg(), avšak soubor není typu jpeg.

Dle dokumentace PHP má funkce imagecreatefromjpeg() vrátit false, ale v tomto případě vyhodí fatální chybu “JPEG library reports unrecoverable error” a skript skončí. Zřejmě je někde chyba v GD2 knihovně, nevím. V každém případě takto se chyba alespoň dá obejít.

function getImageFromFile($filePath)
{
   switch(exif_imagetype($filePath))
   {
      case IMAGETYPE_JPEG:
         return @\imagecreatefromjpeg($filePath);
         break;
      case IMAGETYPE_PNG:
         return @\imagecreatefrompng($filePath);
         break;
      case IMAGETYPE_GIF:
         return @\imagecreatefromgif($filePath);
         break;


   }

   return null;
}

Vlastně se tato funkce hodí pro každý load obrázků 🙂

Problémy s autentifikací přes CURL digest v PHP 5.6.8

Zrovna jsem zjistil, že PHP ve verzi 5.6.8 pro Windows má problém se autorizovat na weby přes curl, které používají ověření pravosti přístupu digest. Přesněji po použití hlaviček generovaných Windows SSPI vráti autentifikační mechanismus za použití funkce CURL nesprávný obsah hlavičky, čímž znemožní přihlášení na daný server.

Zjednodušeně se autorizace digest provádí tak, že si nejprve ze severu vyžádáme hlavičku http code 401, jejíž obsahem jsou informace o druhu autorizace a také důležité hodnoty pro výpočet HASH hodnoty, která se pak zpět zasílá pro ověření správné autorizace. Jedním z těchto hodnot je hodnota REALM, která má být podle specifikace zaslána v druhém požadavku nezměněna, nicméně PHP tuto hodnotu zasílá v tom druhém požadavku prázdnou a vzdálený server tak nemůže autorizaci provést. Uvedu to na příkladu:

Hlavička prvního dotazu na server vypadá následovně:

HTTP/1.1 401 Unauthorized
Content-Length: 0
Server: Microsoft-IIS/8.5
WWW-Authenticate: Digest qop="auth",algorithm=MD5-sess,nonce="afdasd",charset=utf-8,realm="Digest"
X-Powered-By: ARR/2.5
Date: Thu, 25 Feb 2016 09:25:55 GMT

 

PHP v tomto případě nastaví a vypočítá příslušné hodnoty a odešle hlavičku:

GET /Feed/feedcz.xml HTTP/1.1
Authorization: Digest username="...",realm="",nonce="afdasd",uri="some.xml",cnonce="565sdf",
nc=00000001,algorithm=MD5-sess,response="25651sadf",qop="auth", ....
Host: somehost.sk
Accept: */*

Všimněte si, že hodnota realm je v tomto případě prázdná – a to je ta chyba, která zapřičiní chybnou autorizaci.

Není to ani tak chyba PHP, ale přímo modulu CURL, který tuto chybu opravuje v pozdějších verzích. Je možné, že PHP ve verzi vyšší než 5.6.8 již tímto neduchem netrpí, ale nevím. Co jsem zkoušel tak verzi PHP 5.4.36 na linuxu – tam to funguje, a poté na Windowsech až verzi PHP 7 a tam to již také funguje správně.

Jak na nedoručitlné emailové zprávy na seznamu?

Anamnéza:

Emailová služba na seznam.cz zažívá převratné změny. Pro většinu vlastníků emailových účtu jsou tyto změny ke prospěchu, avšak pro eshopy a marketingové společnosti se změny stávají noční můrou. Nejenže seznam.cz nyní umí detekovat hromadné emaily a automaticky je dává uživateli do složky “Hromadné” (jenž většina uživatelů přehlíží a newslettery tak ztrácejí význam), ale že nyní k tomu i přidali kontrolu na úrovní zabezpečeného podpisu emailů pomocí DKIM, které je nutné pro hromadné emaily mít.

To, že seznam automaticky dává emaily do složky Hromadné, může ovlivnit pouze uživatel (a to tím, že email ze složky “Hromadné” přesune do doručených a pak by i všechny ostatní emaily daného odesílatele měly automaticky padat do složky “Doručené”), tak u problém s podpisem emailu musí zajistit sám odesílatel emailu.

Hodně jsem se divil, když při posílání posledního newsletteru z e-shopu nám zpět chodily zprávy o nedoručitelnosti emailů na účty u Seznam.cz. Nejedná se přitom pouze o účty na doméně @seznam.cz, ale i jeho přidružených domén, tedy i @email.cz, @post.cz a možná i dalších. Vždy to bylo zdůvodněno tím, že Massmail (tedy hromadný email) musí být podepsán DKIMem.

1

 

Diagnóza:

Anamnézu tedy již máme, zkusíme nyní diagnostikovat a ošetřit problém posílání hromadných emailů na emailové účty seznamu. Nejprve si vysvětlíme, co ten DKIM vůbec je, k čemu se používá, a proč jej implementoval seznam.cz do svého systému.

DKIM (DomainKeys Identified Mail) je technologie, která za pomocí asymetrického šifrování dokáže zaručit, že email tímto způsobem poslaný je po své cestě v internetu nezměněn a že opravu pochází z domény, kterou má ve své hlavičce určenou. Doručovateli tedy dává jistotu, že email nebyl poslán nikým jiným, jak se obvykle u hromadných emailů stává.
Tato jistota je zabezpečena privátním klíčem, který je umístěn pouze na serveru, ze kterého jsou odesílány emaily a pak veřejným klíčem, který pro ověření používají emailoví klienti. Ten je umístěn veřejně v záznamech DNS domén.

Na straně příjemce není třeba žádných nastavení, emailoví klienti jsou na tuto technologii připraveni a díky ní taktéž upravují své spamové filtry a emaily takto podepsané vyhodnocují jako ověřené a tudíž je zde nižší (avšak ne úplná) pravděpodobnost, že email skončí ve spamové složce (nebo jej dokonce úplně smaže). Navíc, většina klientů tyto maily zvýrazňuje určitým symbolem, že jsou od prověřeného odesílatele.

Z hlediska seznam.cz je to vhodná technika pro zabezpečení uživatelských účtů před množstvím spamů, které se na ně valí.

Vyléčení:

Informace tedy již máme, nyní si řekneme, jakým způsobem DKIM ve svých odesílaných emailech aktivovat.

Jak už jsem psal, jedná se o technologii, která používá privátní a veřejné klíče. Nebudu zde popisovat, jakým způsobem vytvořit tyto klíče, to je práce serverových techniků. Nám bude stačit vědět, že pro aktivaci této technologie na svém serveru stačí uvědomit administrátory serveru. Ti na server přidají privátní klíč pro generování a Vám pošlou veřejný klíč, který se pak musí dát do DNS záznamu, přesně do do TXT záznamu, který následně může vypadat nějak takto:
domena._domainkey IN TXT “v=DKIM1; t=s; k=rsa; p=djlkaQ/563156asdkljKLKLD7mks&k0$DFASffjlkhakljsf44”

Pro většinu eshopů bude stačit, když se na serveru nastaví pouze jedna, tzv. hlavní doména, která bude svým jménem (a svými klíči) podepisovat odeslané emaily. Například u VS hostingu mi to nastavili přímo na doménu serveru (jmeno.vshosting.cz) a sami také nastavili DNS záznamy.

U tohoto nastavení přímo na doménu serveru je třeba pouze zabezpečit, že na serveru, ze kterého jsou odesílány emaily, není nějaký “záškodník” web, jehož hlavní činností bude posílat hromané SPAMy v ohromném množství na všechny možné emaily. Musíme si uvědomit, že po nastavení je jakýkoliv email, odeslaný z tohoto serveru, přesně identifikovaný a zpětně se dá dohledat, kdo, kdy a jaký web či služba email zaslala a může se klidně stát, že se tato doména objeví na blacklistu a všechny tyto emaily najednou budou označeny jako spamové.

Pro ověření funkčnosti si po aktivaci zašlete nějaký email a v hlavičce emailu uvidíte např. toto:

2

Nyní je email zabezpečený a jsme si jistí, že je to opravdu ten odesílatel, za koho se email vydává. A to je přesně to, co seznam.cz vyžaduje.

Mám sám ověřeno, neboť po aktivaci na svém serveru a po spoštění odesílání newsletteru se mi již žádné emaily nevracely. (Ano, sice asi stále padají do složky “Hromadné”, ale s tím, jak už jsem psal, může něco udělat pouze uživatel emailové schránky)

Jen pro zajímavost, v hlavičce emailu je možné si všimnout i druhého zabezpečovacího mechanismu, který standardě používám a sice SPF. Je to další technologie na ověření emailu. Není však tak bezpečná a účinná, protože jen zjišťuje přijatý email jen na základě IP adresy a nedokáže tedy garantovat integritu emailu. O této technologii se rozepíšu někdy u příštího článku.

Vhodný editor pro PHP

Každý programátor, ať již programuje v C , C++, či právě v PHP potřebuje pro svůj vývoj vhodný editor zdrojového kódu. I když pro PHP nám stačí jakýkoliv editor, který dokáže uložit čistý text, je přece jenom vhodné používat kvalitní editory, můžeme jim také říci vývojové prostředí, které dokáží zdrojový kód nejen barevně odlišit, ale také nám různými funkcemi pomáhají při např. hledání syntaktických chyb ve zdrojovém kódu. Osobně jsem měl tu možnost pracovat ve čtyřech editorech, které mohu specifikovat asi takto:

PSPad

Mé začátky v programování směřovaly k nějakému jednoduchému editoru, kterým je právě PSPad. Jedná se o rychlý, nenáročný jak na instalaci tak v používání, volně stažitelný, editor nejen PHP zdrojových kódů, ale i všech ostatních jazyků přes značkovací jazyky jako HTML, XML, až po JAVA a C/C++. Nejedná se o žádné vývojové prostředí, a proto podpora všech těchto jazyků je jen na úrovni rozpoznání zdrojového kódu a barevné odlišení funkčních příkazů od jednoduchých textů pro proměnné, navíc však umí také rozpoznávat metody a funkce jednotlivých objektů pro sestavení jednoduchého průzkumníka zdrojového kódu.
I když se jedná o v celku nenáročný editor, disponuje celkem solidní zásobou funkcí a nástrojů pro rychlou editaci textů, zarovnávání a automatického dokončování závorek, řetězců a uvozovek. Dodnes ho používám jakožto prohlížeč a pro jednoduchou úpravu všech možných textů a zdrojových kódu.
(http://www.pspad.com/)

Zend studio

Dříve bylo tohle vývojové prostředí samostatné, nyní již vychází z vývojového prostředí Eclipse, který však není volně ke stažení, ale existuje pod placenou licenci firmy Zend. Editor je plně postaven pro PHP a využívá veškeré možné funkce a nástroje pro podporu programování, lazení a spouštění PHP skriptů. Instalace programu je jednoduchá a nevyžaduje zvláštní instalaci debuggeru, tak jako je tomu u jiných editorů, ten je již totiž v rámci instalace nastaven a při spuštění skriptu plně využit.
Při psaní zdrojového kódu samozřejmě používá všechny standardní funkce, jako automatické doplňování závorek, uvozovek, barevné odlišení kódu, avšak oproti PSPadu má samozřejmě mnoho funkcí navíc, které zpříjemňují editaci programového kódu, jako např:
Code folding – jde o možnost si „zavírat“ funkce, metody a případné komentáře tak, aby zbytečně nerozptylovaly a zkrátili tak editovaný text na stránce
Oprava chyb v realtime – velice dobrá věc, kdy ihned vidíme, že jsme provedli syntatickou chybu, avšak nejen to, editor dokáže rozeznávat i chyby jako např. nedefinovaných proměnných, či proměnná není v kontextu kódu využitá a dalších.
Asistence při psaní kódu – automaticky tak napovídá a doplňuje právě psaný název funkce, proměnné,  rezervované slovo atd.
Chytré přejití na definici funkce/proměnné – automaticky lze přecházet na definici funkce, či proměnné a to i v rámci různých souborů
Automatický popis funkcí PHP – zobrazuje popis PHP funkcí při najetí kurzorem
Automatické formatování obsahu textu
Verzování kódu pomocí CVS či SVN
A mnoho dalších funkcí…

S tímto editorem jsem pracoval cca. 3 měsíce v jeho trial verzi a mohu říci že se s ním  pracuje jakž takž dobře. Avšak, nevím jestli to bylo trial verzi, kterou jsem měl k dispozici, ale mnoho těchto výše popsaných funkcí fungovalo tak na 60 %. Hodně krát se mi stávalo, že se funkce najednou nedokázaly zavřít pomocí funce Code folding, nebo naopak zase nešly otevřít. Někdy se také editor zavřel bez sebemenšího důvodu a vůbec celé prostědí mi připadalo takové nestabilní. Jelikož se jedná o licencovaný software, doufal jsem v jakousi menší chybovost programu, opak je však pravdou. Doufám, že se již Zenďáci zlepšili a nová verze již mnoho těchto chyb neobsahuje.
(http://www.zend.com/)

Eclipse

Velmi známé vývojové prostředí pro všechny platformy a snad i všechny programovací jazyky a je volně ke stažení, tedy žádné licenční poplatky jako u Zend studio. Přímo pro PHP je určen projekt Eclipse PDT, což je zkratka pro PHP Development Tools, jež je jakýsi framework pro Eclipse, který zajišťuje vše potřebné pro vývoj PHP aplikací.
Po instalaci PHP debuggeru (není součástí instalace) pak PDT nabízí prakticky stejnou funkcionalitu jako Zend studio (avšak mnohem stabilnější) plus navíc se může dále rozšiřovat o další nástroje.
(http://www.eclipse.org/)

NetBeans

Vývojové prostředí NetBeans existuje, stejně jako Eclipse, pro všechny platformy a pro řadu programovacích jazyků a je taktéž volně stažitelný bez licenčních poplatků. Funkcionalitou je shodný s výše uvedenými editory Eclipse a Zend studio, kdy jde navíc dále rozšiřovat pomocí různých doplňků.
Mezi hlavní výhody oproti konkurenci je hlavně v rychlosti. I když jsou všechny tyto vývojové prostředí naprogramovány v Java, je podle mého soudu tento editor, co se týče rychlosti zobrazení, funkcí a doplňků, nejrychlejší. Za další obsahuje již mnoho vestavěných doplňků, jako například výborný editor CSS stylů (s náhledy), HTML editor a mnoho jiných. Co se týče chybovosti, ještě se mi nestalo, že by nějaká funkce najednou nefungovala, jako se to často stávalo u Zend studia potažmo i u Eclipsu, právě naopak, vše je krásně rychle (jenž se možnosti hardwaru týče) a svižné (až na otevírání projektu, neboť si NetBeans po otevření projektu indexuje všechny soubory a tím si vytváří přístup ke všem zdrojům projektu).
(http://www.netbeans.org/)

PS: aktualizace 2015 – nyní už používám jedině PHP STORM – excelentní to editor.

Vypršení životnosti relace – vyřešení pomocí AJAX

V předchozím článku o vypršení životnosti relace jsem popisoval dvě možnosti, jak tento problém řešit. První možnost byla prodloužit životnost relace přímo v nastavení PHP, avšak tato možnost se zdá bytí neschůdná, neboť zbytečně zatěžuje server a může vést až k výpadku serveru. Druhá možnost se opírá o prodlužování relací. V této části článku vytvořím službu s využitím AJAX, která nám bude automaticky prodlužovat relace a tím uchovávat data aktivního uživatele na serveru.
Nekončící relace pomocí dvou skriptů

function sessionHolderStart()
{
 if (HTTP_PATH) url = HTTP_PATH+'session_holder.php';
 else url = '/session_holder.php';
 if (window.XMLHttpRequest) {
 self.HTTPrequest = new XMLHttpRequest();
 } else if (window.ActiveXObject) {
 try {
 self.HTTPrequest = new ActiveXObject("Msxml2.XMLHTTP");
 } catch (eror) {
 self.HTTPrequest = new ActiveXObject("Microsoft.XMLHTTP");
 }
 }

 self.HTTPrequest.open("GET", url, true);
 self.HTTPrequest.send(null);
}
sessionHolderInterval = window.setInterval(sessionHolderStart, 10 * 60 * 1000);

Za prvé bude nutné vytvořit soubor sessionHolder.js, který obsahuje funkce pro komunikaci se serverem:

Jak vidíme, jedná se o celkem jednoduchý skript, který obsahuje funkci, pomocí níž AJAX navazuje spojení se serverem a zavolá skript session_holder.php. Tato funkce je následně předána do intervalu, který probíhá co 10 minut. Jediný zmatek v souboru může způsobovat proměnná HTTP_PATH , která je ve funkci použita. Vězte, že se jedná o proměnou, kterou standardně používám při vývoji na localhost. Jelikož na localhostu nedefinuji DOMAIN NAME pro každý projekt, tak by:

url = '/session_holder.php';

odkazoval do ROOTu neexistujícího webu/adresy. Proto si na začátku HTML definuji HTTP_PATH, který směřuje přímo do ROOTu určitého projektu.

Dále musíme vytvořit PHP skript session_holder.php, který je právě díky AJAXu volán:

<?php
session_start();
?>

kupodivu v něm volám pouze jednu funkci session_start. Pokud se podíváte na článek o vypršení životnosti relace, kde vysvětluji implementaci relací do PHP, tak je Vám zcela jasné, co daný skript provede. Ano, tento skript zaktualizuje soubor relace a tím pádem prodlouží jeho platnost a díky tomu, že je neustále volán co 10 minut, nemůže se stát, že by relace kdykoli vypršela.

Sumarizace

Díky těmto skriptům, které jsou z hlediska náročnosti na webový server velmi jednoduché, lze účelově vytvořit nikdy nekončící relaci a tím uspokojit uživatelé internetu, kteří již nebudou nadávat na samoúčelné vymazání Jejich objednávky z košíku.

Session – Vypršení životnosti relace – problém a řešení

Vypršení životnosti relace – problém a řešení

Relace („sessions“) se ve webových aplikacích používají k uchování stavu aplikace zpuštěné na webovém prohlížeči uživatele. Jelikož je HTTP protokol standardně bezstavový, tak je tímto dána možnost uchovat si na serveru určitá data, která nám pomáhají uchovat si požadavky na stránku odeslané uživatelem a při následném zobrazení stránky tyto informace použít.

Kde je problém?

Každá vytvořená relace má však svou určenou životnost. Vždy končí při zavření prohlížeče, avšak také končí při uplynutí doby, na kterou je nastavena. Ztráta relace na stránkách může být někdy nepříjemná. Pokud pomineme nepříjemné emaily od zákazníků, kterým se ztrácejí vložené produkty do košíku, jelikož si při nákupu v internetovém obchodu odskočili na oběd (čímž se po určitém čase session zneplatnila), tak velmi flustrující může být ztráta session v době, kdy například píšeme dlouhý článek přímo ve webovém editoru na určitém webu a při uložení nám server odpoví tím, že bychom se měli znovu přihlásit, čímž jsme samozřejmě přišli o celý napsaný článek (nesmějte se, tato situace se mi doopravdy stala na nějakém blogu). Jak tedy zabezpečit webové aplikace, aby se relace neztrácela?
Navýšení hodnoty životnosti relace
Jednou z možností je navýšení hodnoty životnosti relace přímo v nastavení PHP.INI (hodnota session.gc_maxlifetime). Tuto operaci však nedoporučuji a to z tohoto důvodu: Relace jako taková je vlastně soubor proměnných, případně i objektů, které jsou PHP strojem serializovány (rozuměj převedeny do stavu, kdy lze hodnoty bez obtíží uložit na disk) a uloženy do souboru adresáře relací na serveru. Jelikož je pro každého návštěvníka stránky vytvořená nová relace, tak při návštěvnosti např. 4000 lidí denně je nutno vytvořit 4000 souboru v adresáři (pokud teda nastavíme životnost na 24 hodin).  A pokud navíc na serveru provozujeme více webových aplikací a všechny tyto aplikace ukládají své relace do jediného adresáře (standardní situace), tak máme hned v adresáři několik tisícovek souborů. I selský rozum nám napovídá, že následné hledání jediného souboru v této změti souborů při načtení každé další webové stránky, nám server znatelně zpomalí ne-li přímo celý server shodí.
Druhou, a mnohem lepší možností, je vytvořit si službu, která nám bude životnost relace neustále prodlužovat.

Prodlužování relace

Pokud si přestavíme, jakým způsobem PHP pracuje s relací, tak je velmi jednoduché vytvořit si skript, který nám bude automaticky, po nějakém daném čase, životnost relace prodlužovat.

Jak už jsem psal výše, relace v PHP je serializovaný soubor, který obsahuje soubor proměnných nebo objektů, a je uložen v adresáři pro relace. Název tohoto souboru je shodný s hodnotou cookie SESID, která je zasílána v požadavku od uživatele. V PHP kódu po zavolání funkce session_start() (nebo pokud je zapnutá v PHP.INI direktiva session.auto_start)  se v adresáři pro relace začne hledat soubor s tímto názvem. Pokud je nalezený a je platný (jeho životnost ještě nevypršela), tak si jej „odserializuje“  (převede zpět do podoby proměnné či objektu) a uloží si veškerý obsah do globální proměnné SESSION. Při skončení skriptu PHP automaticky zavolá funkci session_write_close, která serializuje všechny hodnoty v proměnné SESSION a uloží je do adresáře pro relace pod názvem SESID.
Důležité je zde zmínit, že životnost se v nových verzích PHP (od verze 4.2.3) zjišťuje pomocí funkce MTIME, která vrací čas modifikace souboru (ve starších verzích se používala funkce ATIME, tedy čas, kdy byl soubor naposledy otevřen, která způsobovala problémy na systému WINDOWS, který tuto funkci nepodporoval) .
Pokud tedy víme, jak relace pracují, je možné vytvořit dva jednoduché soubory, které nám budou po určitém intervalu volat funkci session_start na serveru a tím neustále prodlužovat životnost relace.

Maskování políčka pro hesla

Našel jsem zajímavý věcičku na stránkce lab.arc90.com pro pohodlné zadávání hesel do formulářu typu „password“.

Asi každý má problém s tím, že i když zná správně heslo k přihlášení na určité stránky, tak se občas překlikne a samozřejmě pak nadává, proč se sakra pod správným heslem neumí k webu dostat. Zajímavým způsobem, jak uživateli dát vědět, že jeho heslo je nesprávně zadané, je formou různě barevného grafu spočítaného ze zadaného hesla, čímž může uživatele ihned vizuálně upozornit, že heslo, které zadává, není tím, které zde zadává normálně. Samozřejmě záleží na tom, jak často se přihlašujeme na stránky se stejným heslem a můžeme si tak zapamatovat vizuální informaci o správnosti hesla, ale i tak se jedná o opravdu pěkné zpestření.

Jedinou výtku bych snad měl pro implementaci. Utilita je vytvořena pro JavaScriptiovou knihovnu JQUERY, která již sama o sobě má nějakou tu velikost, ale k ní musí být ještě přidány další dvě knihovny, které přímo s tímto skriptem spolupracují. Jedná se o pluginy jquery.sparkline pro kreslení barevných grafů a také plugin jquery.sha1 pro výpočet hashe, ze kterého se graf provádí. Dohromady všechny tyto knihovny zabírají 200Kb, tudíž se jedná o dost velký balík na takovou blbůstku. Nicméně při dnešní rychlosti internetu by tato věc neměla moc vadit (ještě když správně používáme cache prohlížeče).
Co vy na to. Dali by jste si tuhle celkem vychytanou věc na své stránky?

AJAX

Co je AJAX

AJAX (Asynchronous JavaScript And XML) je nestandardní rozšíření skriptovacího jazyka JavaScript, který se používá v dynamicky generovaných webových aplikacích.
Jedná se o JavaScriptový objekt, s jehož pomocí je možné zasílat a přijímat z webového serveru různé formáty dat, zahrnující XML, HTML, nebo jen čistý text. Tato operace je prováděná asynchronně a tímto způsobem je možné vytvářet opravdu dynamické webové stránky, kde se obsah stránky mění jakoby v pozadí aplikace a na žádost klienta (uživatele), bez nutnosti znovu nahrávat celou stránku.

V čem je háček?

Protože je AJAX rozšířením JavaScriptu, tak je samozřejmě možné jej použít pouze u internetových prohlížečů, které jej podporují. Proto je nevhodné všechny informace na stránkách prezentovat uživatelům jen přes AJAX, jednak ne všichni uživatelé (zhruba 1% uživatelů má JavaScript deaktivovaný) a ne všechny internetové prohlížeče (hlavně internetové prohlížeče v mobilních telefonech) JavaScript podporují. Nakonec i vyhledávací roboti (jako např: googlebot, seznambot)  s JavaScriptem neumí pracovat a tedy neumí indexovat informace prezentované uživateli JavaScriptem. Proto je nutné, aby byly stránky přístupné i bez JavaScriptu a JavaScript a AJAX používat jen jakožto rozšíření stávajících stránek, poskytující uživatelům větší komfortnost a přístupnost.
Ovšem u některých projektů je AJAX přímo nutností, jako například u Google maps, či mapy seznamu. Tyto aplikace neustále komunikují se serverem a bylo by dosti obtížné tuto funkci provádět načtením stránky pokaždé, kdy uživatel změní polohu bodu na mapě.

Aplikace používající AJAX

Mimo výše uvedené aplikace pro zobrazení map, se také AJAX velmi často používá u tzv. našeptávače, který je k vidění například u vyhledávače na seznam.cz. Kdykoliv se do vyhledávacího políčka zadá vyhledávací výraz, tak se ihned aktivuje funkce, která posílá napsané znaky serveru. Ten následně pošle zpět možné klíčové slova, která zřejmě chce zřejmě uživatel do políčka zadat. Vše se tak děje na pozadí aplikace a uživatel nemá vůbec ponětí, že prohlížeč neustále komunikuje se serverem a posílají si vzájemně data.
Dalšími aplikacemi, používající AJAX, jmenujme také např. IceWarp webmail.

Implementace

Jelikož je AJAX nestandardním rozšířením, tak jej jednotlivé firmy, vytvářející internetové prohlížeče, implementovaly do JavaScriptu pod různými objekty.  Microsoft a jeho prohlížeče Internet Explorer do verze 6 používají k přístupu prvek ActiveX Objektu “Microsoft.XMLHTTP”, kdežto ostatní prohlížeče (Mozzila, Firefox, Safari, Internet Explorer 7 a vyšší) používají přímo třídu XMLHttpRequest. Jejich jedlotlivé metody jsou již shodné a proto se mohou vytvářet například tímto způsobem:

var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
 httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
 httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}

Tímto je vytvořen objekt httpRequest. Následně je nutno metodou open() definovat požadavek, který má být odeslán na server. Metoda open() má tento tvar:
httpRequest.open(metoda požadavku, URL, typ požadavku);
kde jednotlivé parametry znamenají:
metoda požadavku – GET nebo POST
URL – např. “http://www.priklad.cz/ajax.php”
typ požadavku – zda se jedná o synchronní (false), nebo asynchronní (true) přenost dat

Jak už býlo uvedeno výše, AJAX je zkratou pro asynchronní přenos dat. Proto musí existovat způsob, který zajistí, že data budou odeslána na server, avšak uživatel zároveň bude moci nadále pracovat s prohlížečem, bez nutnosti čekat na výsledek odeslaný serverem. Pro tento účel je vytvořena metoda onreadystatechange, ke které je nuto přiřadit akci, která se má provést při každé změně stavu zasílání dat.
Existují celkem 4:
0: (uninitialized) dosud neinicializovano metodou send()
1: (loading) nahrává se
2: (loaded) nahráno
3: (interactive)
4: (complete)  kompletní dokončení požadavku

Stavy zasílání dat je možné získat vlastností readyState, a se spojení s metodou onreadystatechange lze přesně určit, kdy byla dat v pořádku ze serveru přijata, například takto:

httpRequest.onreadystatechange = function () {
if (httpRequest.readyState == 4) {
 // data přijata, můžu zpracovat
} else {
 // data stále nepřijata
}
}

Pokud je vytvořen objekt httpRequest a jsou definovány funkce a metody pro zasílání a přijímání dat, je možné odeslat celý požadavek na server pomocí metody send():
httpRequest.send(null);

Po úspěšném přijetí dat je možné si tato data vyzvednout metodou httpRequest.responseXML, pokud je zaslán validní XML, nebo pomocí httpRequest.responseText v jakémkoli jiném případě.

Více informací o implementaci a všech metodách objektu httpRequest je možné získat na webu Mozilla Developer Center.

Závěrem

Použití AJAXu znamená zvýšení použitelnosti a přívětivosti webových aplikací. Webové aplikace se tak přizpůsobují aplikacím desktopovým, kdy na požadavek klienta jsou data ihned k dispozici, aníž by bylo nutno načítat znova celou stránku. Tímto se taktéž zvyšuje rychlost aplikace, neboť jsou zasílány pouze ta data, která jsou v daný moment potřebná. Je však vždy nutno počítat s tím, že daná data zasílána AJAXem nejsou viditelná pro vyhledávací roboty, proto je nutno zajistit jejich nalezení i bez použití AJAXu.

A ještě úplně závěrem, tento článek jsem psal někdy v roce 2009 – dnes se už vše řeší pomocí JQUERY.