PHP pro pokročilé – ICONV a RSS čtečka
Pomocí knihovny ICONV můžeme v PHP velmi snadno převádět dokument v určité znakové sadě na sadu jinou bez toho, abychom si sami psali převáděcí funkce. Různé znakové sady používají například RSS kanály a tak i RSS čtečka musí umět převést jejich znakovou sadu na znakovou sadu pro společný výstup. Jak tohoto docílit, včetně funkční RSS čtečky, si ukážeme v tomto článku.
Knihovna ICONV
Nejdůležitější funkce knihovny je iconv(), kterou si blíže popíšeme. Funkce iconv()
má tři parametry. Prvním je původní kódování dokumentu, druhý parametr udává výstupní znakovou sadu a obsahem třetího parametru je text, který se má převést.
Funkce iconv()
má ale několik nedostatků. Ten hlavní se týká znakové sady, která začíná řetězcem WIN. Místo něj musíte použít řetězec CP (například místo WIN-1250
použijete CP1250
). Druhý problém se vyskytl, pokud funkce hlásí chybu illegal input sequence. V tomto případě ještě za znakovou sadu uveďte řetězec //TRANSLIT
(například CP1250//TRANSLIT
). Tento řetězec můžete ale použít, i když se chyba nevyskytne (což je výhoda – prostě ho napíšete všude). Někdy je také dobré použít ISOXXXX-X
místo ISO-XXXX-X
. Verze knihoven se liší a tak musíte trochu experimentovat s tím, kde a jaký řetězec použít.
Příklad převodu dokumentu ze znakové sady WIN-1250 do UTF-8 bude tedy vypadat následovně:
$retezec = „ščřžýáíé“;
$retezec = iconv(„CP1250“, „UTF-8“, $retezec);
RSS čtečka
RSS kanály patří dnes ke zcela běžné výbavě internetových medií. Umožňují jednoduše zobrazit přehled aktuálních článků z časopisů, například na vašich stránkách. K tomu ale potřebujeme takzvanou RSS čtečku. Nejprve si ukážeme příklad RSS kanálu:
<?xml version=“1.0″ encoding=“iso-8859-2″?>
<rss version=“0.91″>
<channel>
<title>Můj obchod.CZ</title>
<link>http://mujobchod.cz</link>
<description>Internetový obchod</description>
<language>cs</language>
<webmaster>webmaster@mujobchod.cz</webmaster>
<image>
<title>Logo</title>
<url>http://mujobchod.cz/logo.png</url>
<link>http://mujobchod.cz </link>
<width>60</width>
<height>60</height>
<description>Internetový obchod</description>
</image>
<item>
<title>Výrobek 1</title>
<link>http://mujobchod.cz/prvni.php</link>
<description>Výrobek 1 je moderním produktem ve své kategorii</description>
</item>
<item>
<title>Výrobek 2</title>
<link>http://mujobchod.cz/druhy.php </link>
<description>Výrobek 2 plně předčí výrobek 1 v mnoha věcech</description>
</item>
</channel>
</rss>
V ukázce můžete pěkně vidět strukturu RSS zdroje. Každý RSS soubor musí obsahovat kódování (<?xml version="1.0" encoding="utf-8"?>
), verzi RSS (<rss version="0.91">
) a jeden nebo více samotných kanálů (<channel>
). Obsahem kanálu je titulek (<title>
), popis (<description>
), odkaz na web (<link>
) a jazyk (<language>
), nepovinně může obsahovat navíc logo (<image>
), copyright (<copyright>
), kontakt na webmastera (<webmaster>
) a podobně. Důležité jsou ale jednotlivé položky kanálů (<item>
), které musí obsahovat titulek položky (<title>
), odkaz na samotný článek (<link>
) a nepovinně popis (<description>
), který většinou obsahuje stručnou ukázku článku. (Podrobnější popis jednotlivých elementů RSS kanálů můžete najít v článku RSS? RSS! od Jiřího Bureše.)
RSS zdroj je XML dokument, který se dá zpracovat XML parserem. Ne na všech stanicích ale parser je k dispozici a také práce s ním je složitější. Naše čtečka RSS dokument doslova rozpitvá slovo po slovu a vrátí objekt, který obsahuje jednotlivé položky kanálů a logo zdroje. Přitom využije toho, že některé řetězce se v RSS mohou vyskytnout jen jednou (například <rss version="0.91">
), můžeme tak zjišťovat informace o RSS kanálu.
Základem naší čtečky je funkce ContentElement(). Ta vrací text mezi počátečním a koncovým tagem. Tři parametry určují celý řetězec (element), počáteční tag a koncový tag. V následujícím příkladu vypíše funkce řetězec „Nadpis“:
$retezec=“<h1>Nadpis</h1>“;
echo ContentElement($retezec, „<h1>“, „</h1>“);
Kód funkce ContentElement()
vypadá takto:
function ContentElement($string,$starttag,$endtag) {
//nejprve vypočteme délky tagů
$len_starttag=strlen($starttag);
$len_endtag=strlen($endtag);
//pozice počátečního tagu
$poz_starttag=strpos($string,$starttag);
//v části za počátečním tagem najdeme koncový tag
$poz_endtag=strpos($string,$endtag,$poz_starttag+$len_starttag);
//vnitřek obou tagů, zjišťujeme pozici prvního znaku po počátečním tagu a délku vnitřku tagů
$obsah=substr($string,$poz_starttag+$len_starttag,$poz_endtag-$poz_starttag-$len_endtag+1);
return $obsah;
}
Naši čtečku budou tvořit tři třídy:
clsRSS
– celý RSS zdrojclsImage
– logo kanálu (podtřída třídy clsRSS)clsItem
– jednotlivá položka (podtřída třídy clsRSS)
Nejprve si ukážeme kód posledních dvou tříd. Třída clsImage popisuje logo RSS kanálu:
//třída popisující obrázek (logo) RSS kanálu
class clsImage {
var $imagestring; //obsah elementu obrázku
//konstruktor, parametr je vnitřek elementu <image> vytáhnutý z RSS souboru
function clsImage($str) {
$this->$imagestring=$str;
//titulek obrázku (max 100 zn.)
$this->Title=ContentElement($this->$imagestring,“<title>“,“</title>“);
//URL obrázku (max 500 zn.)
$this->Link=ContentElement($this->$imagestring,“<link>“,“</link>“);
//popis obrázku
$this->Description=ContentElement($this->$imagestring,“<description>“,“</description>“);
//šířka obrázku (1-144, 88 defaultně)
$this->Width=ContentElement($this->$imagestring,“<width>“,“</width>“);
//výška obrázku (1-400, 31 defaultně)
$this->Height=ContentElement($this->$imagestring,“<height>“,“</height>“);
}
}
Třída clsItem popisuje položku RSS kanálu:
//třída popisující jednotlivé položky RSS kanálu
class clsItem {
var $itemstring;
//konstruktor, parametr je vnitřek elementu <item> vytáhnutý z RSS souboru
function clsItem($str) {
$this->$itemstring=$str;
//titulek položky (max 100 zn.)
$this->Title=ContentElement($this->$itemstring,“<title>“,“</title>“);
//link položky (max 500 zn.)
$this->Link=ContentElement($this->$itemstring,“<link>“,“</link>“);
//ukázka položky (max 500 zn.)
$this->Description=ContentElement($this->$itemstring,“<description>“,“</description>“);
}
}
Konstruktorům obou tříd se zadají obsahy elementů <image>
a <item>
, které jsou získány funkcí ContentElement()
. Vzhledem k tomu, že RSS obsahuje více položek <item>
, jednotlivé objekty clsItem
budou tvořit pole.
Celý objekt RSS
je přístupný pomocí třídy clsRSS
. Jejímu konstruktoru se zadá adresa RSS zdroje a nepovinně výstupní kódování (jestliže se nezadá, kódování se nezmění). Třída kontroluje i existenci zdroje pomocí následující konstrukce:
if (!@fclose(@fopen(„$cesta“, „r“))) {
die („RSS kanál „.$cesta.“ nelze otevřít.“);
}
Soubor se otevře a zavře. Pokud vše proběhlo v pořádku, soubor existuje, jinak neexistuje. Funkci file_exists()
nelze v tomto případě použít, protože neumí přistupovat ke vzdáleným souborům.
Kód třídy clsRSS vypadá takto:
class clsRSS {
var $rsssoubor;
//do konstruktoru se nastaví cesta k RSS souboru; vytvoříme proměnnou, jejímž obsahem je obsah RSS kanálu
function clsRSS($cesta,$vystupnikodovani=““) {
//kontrola existence souboru. Nelze použít file_exists() – neumí přistupovat ke vzdáleným souborům
if (!@fclose(@fopen(„$cesta“, „r“))) {
die („RSS kanál „.$cesta.“ nelze otevřít.“);
}
$this->$rsssoubor=implode(„“,@file($cesta));
//verze XML a kódování
$xmlcontent=ContentElement($this->$rsssoubor,“xml“,“>“);
$this->XMLver=ContentElement($xmlcontent,“version=\““,“\““);
$this->Encoding=ContentElement($xmlcontent,“encoding=\““,“\““);
//verze RSS
$rsscontent=ContentElement($this->$rsssoubor,“<rss“,“>“);
$this->RSSver=ContentElement($rsscontent,“version=\““,“\““);
//převod do zadaného kodování
if ($vystupnikodovani!=““) {
$r=iconv($this->Encoding.“//TRANSLIT“, $vystupnikodovani.“//TRANSLIT“, $this->$rsssoubor);
//když se převedlo, změníme, jinak původní kódování ponecháme
if ($r) {
$this->$rsssoubor=$r;
}
}
//titulek RSS kanálu
$this->Title=ContentElement($this->$rsssoubor,“<title>“,“</title>“);
//cesta ke zdroji RSS kanálu
$this->Link=ContentElement($this->$rsssoubor,“<link>“,“</link>“);
//popis RSS kanálu
$this->Description=ContentElement($this->$rsssoubor,“<description>“,“</description>“);
//jazyk RSS kanálu
$this->Language=ContentElement($this->$rsssoubor,“<language>“,“</language>“);
//copyrigh RSS kanálu
$this->Copyright=ContentElement($this->$rsssoubor,“<copyright>“,“</copyright>“);
//den RSS kanálu
$this->Day=ContentElement($this->$rsssoubor,“<day>“,“</day>“);
//hodina RSS kanálu
$this->Hour=ContentElement($this->$rsssoubor,“<hour>“,“</hour>“);
//datum poslední modifikace RSS kanálu
$this->LastBuiltDate=ContentElement($this->$rsssoubor,“<lastbuiltdate>“,“</lastbuiltdate>“);
//email daného webu
$this->ManagingEditor=ContentElement($this->$rsssoubor,“<managingeditor>“,“</managingeditor>“);
//objekt logo webu
$str=ContentElement($this->$rsssoubor,“<image>“,“</image>“);
$this->Image=new clsImage($str);
//nyní zbývá vytvořit pole položek
//to provedem tak, ža vždy odtrhneme část před <item>
$pocetitemu=substr_count($this->$rsssoubor,“<item>“);
$odriznuto=$this->$rsssoubor;
for ($p=1; $p<=$pocetitemu; $p++){
$str=ContentElement($odriznuto,“<item>“,“</item>“);
$pole[$p] = new clsItem($str);
$pozitemu=strpos($odriznuto,“<item>“)+6;
$odriznuto=substr($odriznuto,$pozitemu);
}
$this->Item=$pole;
}
}
Vypsání obsahu RSS zdroje pomocí naší čtečky je již velmi jednoduché:
<?
//vložíme třídy potřebné pro čtečku
include („rssreader.php“);
//adresa RSS zdroje
$zdroj=“rss.xml“;
//vytvoříme objekt čtečky
$rss = new clsRSS($zdroj,“CP1250″);
//napíšeme nadpis zdroje, link na něj a popis
$obsah.=“<h1><a href=\““. $rss->Link .“\“ title=\““. $rss->Description .“\“>“. $rss->Title .“</a></h1>\n“;
//vypíšeme jednotlivé příspěvky a vložíme je do stránky
foreach ($rss->Item as $item) {
$obsah.=“<h2><a href=\““. $item->Link .“\“>“. $item->Title .“</a></h2>\n“;
$obsah.=“<p>“.$item->Description.“</p>\n“;
}
?>
<html>
<head>
<meta http-equiv=“Content-Language“ content=“cs“ />
<meta http-equiv=“Content-Type“ content=“text/html; charset=windows-1250″ />
</head>
<body>
<?echo $obsah;?>
</body>
</html>
Na závěr se můžete podívat na funkční RSS čtečku (čte se RSS soubor ze začátku článku), případně si stáhnout knihovnu, ve které je kód čtečky. Upozorňuji však, že pokud máte funkční XML parser, je samozřejmě výhodnější používat parser než naši čtečku, která navíc neumí například rozlišit více kanálů v jednom RSS dokumentu. I když takovou drobnost si jistě zvládnete dopsat sami.
Odkazy, zdroje
- RSS Interval.cz – hlavní kanál s nejnovějšími články
- RSS? RSS! – základní článek o RSS na Interval.cz
- PHP: iconv Functions – PHP manuál
- libiconv – GNU projekt knihovny
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Thunderbolt 4 vs. OCuLink: Přišel čas na upgrade?
27. května 2024 -
Landing page: Jak vytvořit landing page s vysokým CTR
7. května 2024 -
Nejlevnější VPS: To je nový Cloud Server Mini od ZonerCloud
4. června 2024 -
Jak zabezpečit váš chytrý telefon před kybernetickými hrozbami
30. listopadu 2023
Nejnovější
-
Výkonný a kompaktní: ASOME Max Studio s výjimečným poměrem cena/výkon
11. listopadu 2024 -
Šokující data od Microsoftu: Kyberútoky rostou o stovky procent!
8. listopadu 2024 -
Chcete jedinečnou doménu? Objevte koncovky FOOD, MEME a MUSIC!
7. listopadu 2024 -
OpenAI představilo novou funkci ChatGPT Search
6. listopadu 2024
Nemeji
Čvn 17, 2010 v 10:33Nepoužitelné – je zde hromada chyb volání fonkce ve třídě!!! např.
$this->$rsssoubor namísto $this->rsssoubor
a také zíškání kódování souboru:
$this->Encoding=ContentElement($xmlcontent,“encoding=\““,“\““);
je nedostatečně ohraničeno, lze to upravit takto:
$this->Encoding=ContentElement($xmlcontent,“encoding=\““,“\“?\>“);
Miroslav Kucera
Čvn 17, 2010 v 11:24Vám přijde alespoň trochu smysluplné reagovat na šest let starý článek? ;-)
Wolwino
Zář 14, 2010 v 18:55Mi osobně ten komentáš užitečný byl .)
Miroslav Kučera
Zář 15, 2010 v 9:12Wolwino: ono to spise bylo zamysleno tak, ze ctenari se casto v diskusi vyjadruji vecem, ktere uz dnes treba nefunguji (protoze vyvoj vseho mozneho jde prudce kupredu), ale ktere byly poplatne a funkcni v dobe vydani clanku.
urso
Pro 6, 2010 v 13:36Po 6 letech je to již jinak. Lze velmi pohodlně použít v PHP5 simplexml:
if ($xml = @simplexml_load_file(„http://www.efekta.cz/rss.php“)) {
$ck = 0; // cislo komentáře
foreach ($xml->channel->item as $item) {
$odkaz = „zpravy_podr.php?ck=“.$ck.“&adresa=“;
$nazev = htmlspecialchars($item->title);
echo „“;
echo „„.$nazev.“„;
$ck++;
}
}
jenna.cz
Lis 8, 2014 v 11:51:-)