Ohlas čitateľov k môjmu poslednému článku ma motivoval k napísaniu ďalších pokračovaní jednoduchého chatu. Predchádzajúci skript si doplníme o zobrazenie online užívateľov opäť bez použitia databázy a ešte pridáme pár vylepšení. Samozrejme nebude chýbať ukážka (už v tomto článku) a možnosť stiahnutia zdrojových súborov v niektorom z budúcich pokračovaní.

Pár úvodných riadkov by som rád venoval poslednému článku o jednoduchom chate. Viacerým čitateľom sa po nakopírovaní zdrojových súborov na server objavila chybová hláška podobná tejto Warning: fopen(„./data.txt“,“w“) – Permission denied in index.php on line 7. Čo znamená, že php skript nemá právo vytvoriť súbor data.txt na serveri. Vtedy stačilo tento súbor vytvoriť „ručne“ (na serveri, alebo nakopírovať cez ftp klienta) a nastaviť správne prístupové práva. Samozrejme musel byť tento súbor prázdny (0 bajtov), inak by sa narušil výpis posledných N odkazov. Súbor „data.txt“ musel mať nastavené rovnaké práva ako www server bežiaci ako užívateľ nobody, alebo httpd. Okrem nastavení prístupových práv som sa v jednom prípade stretol s problémom, že po odoslaní formuláru sa nevykonal skript „form.php“. Pomohlo doplnenie tagu form o parameter action: <form method=“post“ name=“f“ action=“form.php“>

Mnohí čitatelia si chat iba stiahli a rovno ho umiestnili na svoj server, tu by som chcel upozorniť na to, že ak ste nezmenili názov súboru, kde sa budú zapisovať odkazy, súbor „data.txt“, ľahko sa k nemu môže niekto dostať. Ak napríklad taktiež zhliadol článok na Intervale, predpokladá, že sa súbor volá rovnako a jednoduchým spôsobom sa dopracuje ku všetkým odkazom, ktoré boli doteraz napísané. Stačí ak do prehliadača namiesto „index.php“ zadá „data.txt“, prípadne si tento súbor stiahne a premenuje na html a uvidí odkazy v čitateľnejšej forme. Tento odkaz (pravé tlačítko myši – Uložiť cieľ ako… – premenovať na html) smeruje na súbor data.txt z ukážky prvého článku o jednoduchom chate, kde sú všetky vaše doposiaľ napísané odkazy. Kde som si (okrem iných:) prečítal pripomienku, že nové odkazy by sa mohli zobrazovať hore. Mne sa zdalo logickejšie zobrazovať staršie hore – keď sa niekto prihlási na stránku číta postupne riadok po riadku, o čom sa doteraz ostatní bavili (takto sa napr. zobrazujú odkazy aj v irc). Navyše funkcia FPassThru() sa k tomu výborne hodila, ale doplnil som chat aj o túto možnosť.

Pustime sa teda do tvorby nového chatu. Rozmiestenie rámcov bude podobné ako v prvom chate, iba napravo pribudne nový rámec pomenovaný online. Poriadok musí byť, preto si všetky potrebné konštanty definujeme v jednom súbore „define.php“. Za dôležité považujem spomenúť, že pribudla konštanta znovu načítania rámca „head“, teda ako často sa urobí kontrola, či nepribudol nový odkaz, alebo nepribudol nový online užívateľ. Zmena nastala aj pri práci so súbormi, keďže napr. do súboru „data.txt“ sa v jeden časový okamih môže pokúšať zapísať viacero užívateľov, je potrebné ošetriť tento súbor na zápis iba pre jedného užívateľa v jednom okamihu. Napadlo mi nasledovné riešenie, ak sa chystám pracovať (čítanie, zápis) so súborom, na začiatku si ho premenujem, čím dám ostatným navedomie, že so súborom pracujem práve ja a keď prácu dokončím premenujem ho na pôvodný, čím je k dispozícii ďalšiemu užívateľovi, ktorý naň čakal. Z tohoto dôvodu sú definované pre súbor, kde sa budú zapisovať odkazy dva názvy súborov SHOW_OLDNAME a SHOW_NEWNAME. Rovnako je tomu aj pri súbore, kde sa zapisujú online užívatelia.

// subor, kde sa budu zapisovat odkazy
define(SHOW_OLDNAME, „./show.txt“);
define(SHOW_NEWNAME, SHOW_OLDNAME.“2″);
// subor, kde sa budu zapisovat online „chatari“
define(ONLINE_OLDNAME, „./online.txt“);
define(ONLINE_NEWNAME, ONLINE_OLDNAME.“2″);

Každý, kto príde na stránku chatu, sa považuje za online chatujúceho, až keď pridá prvú správu. Neurobil som to tak, že najskôr sa musí užívateľ prihlásiť a až potom uvidí ostatných prihlásených, jednoducho ich môže sledovať aj keď nie je online. Samozrejme pridať kúsok kódu tak, aby sa užívateľ najskôr prihlásil a až potom chatoval by nemal byť pre skúsenejších problém. Potom sa užívateľ môže sám odhlásiť, alebo bude automaticky odhlásený po uplynutí AUTO_LOGOUT_TIMER sekúnd, ak za tento čas nepridá žiadnu novú správu. Ja som v ukážke nastavil tento čas na 2 minúty.

// po kolkych sekundach odhlasi uzivatela z chatu automaticky
define(AUTO_LOGOUT_TIMER, 2*60);

Online chatujúcich zapisujeme do textového súboru, kde okrem mena pridávame aj čas v sekundách od 1.1.1970, do doby, kedy bola pridaná posledná správa. Formát zápisu do súboru je nasledovný:

meno>1002391673

Meno a čas sú od seba oddelené znakom „>“. Každý ďalší online užívateľ je zapísaný na novom riadku.

Aby sa na chat nemohli prihlásiť dve rovnaké mená, je vo formulári form.php input hidden, ktorý sa naplní až vtedy, ak také meno, ako sa zadá po zobrazení stránky, neexistuje. To nám neskôr poslúži na identifikáciu, či bola do chatu pridaná iba nová správa, alebo sa chce niekto nový prihlásiť na chat. Princíp je nasledovný (zjednodušený formulár):

<?
if(!$chatar){
  if( /* ak taketo $meno uz chatuje */ )
    $meno=““;
  else
    // pridaj $meno do online chatujucich
  }
?>
<form method=“post“ name=“f“ action=“form.php“>
  <input type=“text“ name=“meno“>
  <input type=“hidden“ name=“chatar“ value=“<?echo $meno?>„>
</form>

Vždy, keď bude premenná $chatar prázdna, je potrebné urobiť kontrolu, či takéto $meno už nechatuje. Jednoduché a účinné. To, že premenné nám nikto nenastaví cez URL si zabezpečíme kontrolou veľkosti poľa count($HTTP_GET_VARS). Na základe toho, či $meno bolo zaradené medzi online chatujúcich pracuje input meno nasledovne:

<input type=“text“ name=“meno“ size=“8″
maxlength=“<?echo MENO_MAX?>“ value=“<?echo $meno?>
<?if($meno):?>readonly onFocus=“this.blur()“<?endif?>>

Ak $meno nie je prázdne, input meno bude iba na čítanie, pretože takýto užívateľ sa pokladá za online chatujúceho a nemôže meniť svoje meno počas toho, ako je online. Musí sa najskôr odhlásiť. Ak by sa niekomu podarilo prinútiť prehliadač, aby sa dalo zapisovať do inputu meno, urobíme ešte jednoduchú kontrolu, či sa $meno zhoduje s premennou $chatar, ak $chatar nie je prázdny.

// porusena ochrana readonly alebo udalost onFocus
if($chatar && $chatar != $meno){
  JSAlert(„Zmena mena je zakázaná !“);
  $meno = $chatar;
  }

Okrem premennej $chatar typu hidden máme ešte jednu:

<input type=“hidden“ name=“old_online“ value=“<?echo $new_online?>„>

V ktorej sa uchovávajú všetky mená online chatujúcich v jednom reťazci. Mená sú od seba oddelené znakom „>“. Na základe tohto reťazca testujeme, či nastala zmena v online užívateľoch po odoslaní formulára. Napríklad načítame stránku chatu, zadáme svoje $meno, $správu a odošleme formulár, ak takéto $meno ešte neexistuje, prihlásime sa týmto na chat. To zabezpečuje funkcia OnLineForm, ktorá vráti reťazec online prihlásených, oddelených znakom „>“. Tento reťazec si uložíme do premennej $new_online a porovnáme ho s $old_online. Ak nie sú totožné, znamená to, že nastala zmena v online užívateľoch a je potrebné obnoviť rámec online.

Predtým treba otestovať, či má zmysel volať funkciu OnLineForm. Vo formulári máme 3 vstupné polia a jeden hidden input $chatar, ktorý ak nie je prázdny hovorí o tom, že už je medzi online chatujúcimi. Na základe týchto hodnôt sa rozhodneme, či spracovať skript, alebo nie:

Tabuľka pravdivostných hodnôt vstupov formulára form.php

Nula znamená nevyplnený vstup, jednotka vyplnený. Stav č. 1 až 4 zahŕňa prípad, kedy je premenná $meno prázdna, preto je zbytočné sa týmito stavmi zaoberať. Nasledovná podmienka ošetruje nevhodné vstupy:

// kontrola na serveri pomocou PHP
if(
  // pokusa sa niekto nastavit premenne cez URL ?
  count($HTTP_GET_VARS) ||
  // vyhovuje $meno regularnemu vyrazu ?
  !Ereg(„^[0-9a-zA-Z]+$“,$meno) ||
  // vyhovuje $sprava regularnemu vyrazu ?
  !Ereg(„^[^&<>\“]*$“,$sprava) ||
  // je splnena podmienka c. 7 alebo c. 11 pravdivostnej tabulky ?
  ($odhlasit && !$chatar) ||
  // je splnena podmienka c. 5 alebo c. 6 pravdivostnej tabulky ?
  (!$sprava && !$odhlasit)
  )

$meno sa môže skladať iba zo znakov, ako sú určené regulárnym výrazom, teda zo znakov anglickej abecedy a čísiel. $sprava sa môže skladať z ľubovoľných znakov, okrem &,<,>,“. Premennej $meno sa priradí prázdny reťazec iba, ak $chatar obsahuje prázdny reťazec, pretože inak ak by niekto prihlásený zadal správu, ktorá obsahuje nepovolené znaky, zrušilo by jeho meno.

// $meno=““ iba ak $chatar==““
// inak by mohol nastat pripad $meno=““ ak napr. $sprava=““
// teda vymazanie mena chatujuceho uzivatela

if(!$chatar) $meno=““;

Zbytočne by sme však odosielali formulár na spracovanie serveru, keď už u klienta vieme, že nevyplnil správne vstupy. Preto rovnaké podmienky stanovíme pomocou JavaScriptu. Do tagu form vložíme udalosť onSubmit=“return Kontrola(this)“. Funkcia Kontrola() nám vráti true – ak vstupy vyhovujú (formulár sa odošle na server), false – ak nevyhovujú (nič sa neodošle).

// kontrola u klienta pomocou JavaScriptu
function Kontrola( form ){
  // regularny vyraz, akemu musi vyhovovat premenna „meno“
  var regexp_meno = /^[0-9a-zA-Z]+$/
  // regularny vyraz, akemu musi vyhovovat premenna „sprava“
  var regexp_sprava = /^[^&<>\“]*$/
  // premenne z formulara
  var meno = form.meno.value
  var sprava = form.sprava.value
  var odhlasit = form.odhlasit.checked
  var chatar = form.chatar.value
  if (
    // vyhovuje „meno“ regularnemu vyrazu „regexp_meno“ ?
    meno.search(regexp_meno)==-1 ||
    // vyhovuje „sprava“ regularnemu vyrazu „regexp_sprava“ ?
    sprava.search(regexp_sprava)==-1 ||
    // je splnena podmienka c. 7 alebo c. 11 pravdivostnej tabulky ?
    (odhlasit && !chatar.length) ||
    // je splnena podmienka c. 5 alebo c. 6 pravdivostnej tabulky ?
    (!sprava.length && !odhlasit)
    ) {
    window.status = „Chybné vstupné hodnoty !“
    return false
    }
  else {
    window.status = „“
    return true
    }
  }

Čo sa stane, ak vstupy vyhovujú si povieme v ďalšom pokračovaní. Už teraz si však môžete nový jednoduchý chat vyskúšať. Zdrojové kódy si budete môcť stiahnuť až v čtvrtom pokračovaní. Dovtedy sa vám pokúsim objasniť spôsoby riešení, aké som použil.

Žádný příspěvek v diskuzi

Odpovědět