Práce se sdílenou pamětí v PHP – ukázková aplikace

1. února 2005

V předchozím článku jsme si ukázali způsob, jak pomocí PHP obsluhovat sdílenou paměť. Teorie však již bylo více než dost, a proto si tentokrát ukážeme, jak vytvořit jednoduchou aplikaci chatu, která bude tohoto druhu ukládání dat využívat.

Na internetu máme možnost najít nespočet návodů na vytvoření vlastního chatu v PHP, i zde na Intervalu se nějaký chat najde. Ačkoli se musí uznat, že samotný princip fungování PHP není pro chaty příliš vhodný, ukážeme si, jak si můžeme trochu pomoci a zvýšit (urychlit) výkon naši aplikace. Předem bych však chtěl poznamenat, že následující článek nemá za cíl vytvořit kompletní funkční chat, nýbrž pouze ukázat, jakým způsobem se dají data ukládat bez využití souborů či databáze. Případnou implementaci tohoto jednoduchého příkladu musí provést každý čtenář dle vlastního uvážení.

Naše ukázka se bude skládat ze dvou skriptů, z nichž první bude mít za úkol vždy načíst obsah chatu z paměti a výsledek vypsat uživateli na stránku, druhý skript pak bude sloužit pro samotné vkládání textu do paměti.

V první řadě si vytvoříme základní stránku index.html, ve které si nadefinujeme dva rámy, z nichž jeden bude obsahovat výpis chatu a druhý formulář pro odesílání textu:

<!DOCTYPE HTML PUBLIC „-//W3C//DTD HTML 4.01//EN“>
<html>
 <head>
  <meta http-equiv=“Content-Language“ content=“cs“>
  <meta http-equiv=“Content-Type“ content=“text/html; charset=utf-8 „>
  <title>Chat pomoci sdilene pameti</title>
 </head>
 <frameset rows=“*,50″ border=“0″ frameborder=“0″>
  <frame name=“chat“ scrolling=“auto“ src=“chat.php“>
  <frame name=“textbox“ scrolling=“no“ src=“textbox.php“>
 </frameset>
 <noframes>Chat pomoci sdilene pameti – prijdte si pokecat</noframes>
</html>

Protože není v tomto případě na definici rámů nic podstatného, přesuneme se hned ke druhému skriptu, který bude zajišťovat zobrazení vstupního formuláře a uložení textu do paměti. Rád bych ale ještě upozornil na dost častý omyl, který se stává zejména začátečníkům používajcím nástroje typu FrontPage. Tyto editory, a následně i sami lidé, totiž přidávají často text, který se zobrazí v případě, že prohlížeč nepodporuje rámy. Na tom by nebylo nic špatného, kdyby tento text neobsahoval sdělení typu „Tvůj prohlížeč nepodporuje rámy, sežeň si novej.“ Tato hláška se totiž neukazuje jen prohlížečům, ale i fulltextovým vyhledávačům, které přes rámy neprojdou a tak zaindexují text, který se právě nachází v elementu <noframes />. Je proto více než vhodné tuto část doplnit i o nějaký smysluplný text. Nicméně to jsem mírně odbočil od tématu, a proto se hned podíváme na náš další skript textbox.php:

<?php
# <textbox.php>
$save=array();
$max_msgs=50;
$reserved=500; // uvadime v kB
$time=date(„H:i:s“,time());
if(strlen(trim($_POST[‚msg‘]))!=0) {
$shmid=shm_attach(98374,$reserved*1024,0644);
$semid=sem_get(98374,1);
// Nacteme data
sem_acquire($semid);
$result=@shm_get_var($shmid,2);
sem_release($semid);
// odstranime nepotrebna data z pole
if($result) $num_msgs=count($result);
else $num_msgs=0;
if($num_msgs>$max_msgs) {
  array_shift($result);
  –$num_msgs;
}
// pridame novou zpravu
$save=$result;
$msg=htmlspecialchars($_POST[‚msg‘]);
$save[$num_msgs]=array(„time“ => $time,“msg“ => $msg);
// Ukladame data
sem_acquire($semid);
$result=shm_put_var($shmid,2,$save);
sem_release($semid);
// Uzavreme aktualni segment
shm_detach($shmid);
}
?>
<!DOCTYPE HTML PUBLIC „-//W3C//DTD HTML 4.01//EN“>
<html>
 <head>
  <meta http-equiv=“Content-Language“ content=“cs“>
  <meta http-equiv=“Content-Type“ content=“text/html; charset=utf-8″>
  <title>chat-addtext</title>
 </head>
 <body bgcolor=“#3366CC“ onLoad=“document.userinput.msg.focus();“>
   <form name=“userinput“ action=“textbox.php“ method=“post“>
   Text: <input type=“text“ name=“msg“ size=“60″ value=““ >
        <input type=“submit“ name=“send“ value=“Odeslat“>
   </form>
 </body>
</html>

V první řadě si nadefinujeme potřebné proměnné. První $max_msgs určuje maximální počet zobrazených zpráv (maximální počet prvků uložených v poli). Zde musíme volit rozumný údaj, aby nedošlo k přetečení velikosti vymezeného segmentu paměti. Další v pořadí $reserved určuje, jak velký paměťový segment si přejeme zarezervovat pro použití.

Nyní následuje už samotná výkonná část skriptu. Nejprve provedeme kontrolu, zda je vůbec nějaký text odesílán, abychom neukládali text nulové délky, k čemuž by mohlo dojít například při prvním načítání celé stránky a následných pokusech odeslat formulář bez zadání textu. Pokud je vše v pořádku, můžeme pokračovat a provést načtení dat z paměti.

Druhý parametr u funkce shm_attach() násobíme číslem 1024, protože musíme zadávat hodnotu v bytech, kdežto $reserved je uvedeno v kilobytech. Po úspěšném načtení dat z paměti zjistíme pomocí funkce count(), kolik prvků obsahuje dané pole. Pokud se nám z nějakého důvodu nepodařilo uložená data z paměti získat, nastavíme počet prvků na nulu. Zároveň také, pokud pole obsahuje více prvků, než určuje proměnná $max_msgs, odstraníme pomocí funkce array_shift() prvek s nejmenším indexem a zároveň snížíme index všech prvků o jeden.

Nyní se už konečně dostáváme k samotnému uložení textu do paměti. Uživatelský vstup pouze očistíme od nežádoucích znaků pomocí funkce htmlspecialchars() a přidáme jej k již předchozím uloženým ve formě pole. Provedeme zápis aktualizovaných dat do paměti. Celý tento postup se opakuje vždy při odesílání textu uživatelem.

<?php
# <chat.php>
// Otevreme blok
$shmid=@shm_attach(98374,0,0);
// Nastavime semafor pro dany segment
$semid=@sem_get(98374);
// Nacteme data
sem_acquire($semid);
$result=@shm_get_var($shmid,2);
sem_release($semid);
// Vypiseme data
$result=@array_reverse($result);
for($i=0;$i<count($result);$i++)
  $text.= „<b>“.$result[$i][‚time‘].“</b>>: „.$result[$i][‚msg‘].“<br>“;
// Uzavreme aktualni segment
@shm_detach($shmid);
?>
<!DOCTYPE HTML PUBLIC „-//W3C//DTD HTML 4.01//EN“>
<html>
 <head>
  <meta http-equiv=“Refresh“ content=“10″>
  <meta http-equiv=“Content-Language“ content=“cs“>
  <meta http-equiv=“Content-Type“ content=“text/html; charset=utf-8″>
  <title>chat-addtext</title>
 </head>
 <body bgcolor=“#DEDCDC“>
   <?=$text;?>
 </body>
</html>

I u skriptu chat.php bude počáteční postup totožný. Pomocí funkce shm_attach() otevřeme segment paměti s daným ID. Jak bylo již řečeno, není v tomto případě nutné uvádět velikost segmentu či přístupová práva, neboť oba tyto údaje jsou již nastavené z dřívějška.

Pomocí funkce shm_get_var() načteme data z paměti, uložíme je do proměnné $result a přistoupíme k samotnému zpracování dat, kdy pomocí funkce array_reverse() obrátíme pořadí prvků v poli. Nejstarší zprávy tedy budou mít nejvyšší index a nejnovější nejnižší. Docílíme tak toho, že nové zprávy budou ve výsledku vypisovány nahoře. Pokud bychom nechtěli vypisovat zprávy tímto způsobem, můžeme tuto funkci jednoduše vynechat. Nakonec uzavřeme spojení s daným ID a provedeme výpis stránky včetně „chat“ textu a hotovo.

Záměrně jsem se pokoušel vytvořit skripty pro tento chat co nejjednodušší, aby nebyl problém pro případné zájemce vybrat a libovolně aplikovat části, které provádějí ukládání a načítání dat. Vezměte prosím na vědomí, že zde chybí celá řada ošetření chyb a u některých funkcí je zabráněno výpisu chybových hlášek. Jedná se především o funkce shm_attach(), sem_get(), shm_get_var(), shm_detach(), které mají ve zvyku dosti neotřelým způsobem upozorňovat na neexistující segment a podobně. Tyto hlášky se objevují pouze, když se spouští daný skript poprvé a v paměti nejsou uložena žádná data.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *