V posledním článku této série si ukážeme, jakým způsobem vyřešit přidávání nových článků a mazání a úpravu článků již napsaných. Dozvíte se, jak ošetřit uživatelské vstupy tak, aby uživatelé nemohli narušit design ani funkčnost stránek, ale přitom mohli vkládat některé elementy a dlouhé odkazy. Na závěr si budete moci kompletní zdrojové kódy weblogu stáhnout.

Funkční ukázku weblogu najdete na webu Czechie.

Vkládání a mazání článků (index.php)

K rozlišení toho, zda se bude článek vkládat či mazat, použijeme proměnnou $action. Obsahuje-li „post“, pak článek vložíme. Nejprve však musíme zkontrolovat, zda byly vyplněny oba povinné údaje (nadpis – title a text článku – article_text) a zda datum vydání není menší než aktuální datum, přičemž necháváme rezervu patnácti minut (lze samozřejmě změnit) na napsání článku. Je-li vše v pořádku, upravíme pomocí funkce Text_Modify(), která bude popsána v závěru, oba vstupní údaje. Následně zjistíme datum prvního dne v týdnu, ve kterém článek vyjde a všechny údaje vložíme do tabulky article. Nakonec, pomocí funkcí popsaných již dříve, vygenerujeme úvodní stránku a příslušnou archivní stránku.

// byla odeslana promenna „action“ ?
if(IsSet($_REQUEST[‚action‘])) {
  switch($_REQUEST[‚action‘]) {
    // vlozi clanek
    case „post“:
      // byly vyplneny oba povinne udaje ?
      if($_POST[‚title‘]==““ || $_POST[‚article_text‘] ==““) {
        $error = 4;
      // neni datum vydani mensi nez aktualni datum (rezerva 15 min) ?
      } elseif(MkTime($_POST[‚from_hour‘], $_POST[‚from_minute‘]+15, 0, $_POST[‚from_month‘], $_POST[‚from_day‘], $_POST[‚from_year‘]) < Time()) {
        $error = 5;
      } else {
        // uprava vstupu
        $title = Text_Modify($_POST[‚title‘]);
        $article_text = Text_Modify($_POST[‚article_text‘]);
        $publish_date = MkTime($_POST[‚from_hour‘], $_POST[‚from_minute‘], 0, $_POST[‚from_month‘], $_POST[‚from_day‘], $_POST[‚from_year‘]); // datum vydani
        $day_number = Date(„w“, $publish_date);
        if($day_number == 0) $day_number = 7;
        $first_day_of_week = MkTime(0,0,0, $_POST[‚from_month‘], $_POST[‚from_day‘]-$day_number+1, $_POST[‚from_year‘]); // datum prvniho dne v tydnu, ve kterem clanek vychazi
        $query = @MySQL_Query(„INSERT INTO article VALUES (“, ‚$title‘, ‚$article_text‘, ‚$publish_date‘, ‚$user_id‘, ‚$first_day_of_week‘)“) or Weblog_Error(2);
        $message = 1;
        
        // vygeneruje staticke stranky
        require „archive.php“;
        Create_Archive($first_day_of_week);
        Create_Index(„static“);
        
        MySQL_Close();
        Header(‚Location: http://‘. $_SERVER[‚HTTP_HOST‘] . ‚/weblog/admin/index.php?message=‘ . URLDecode($message) .’&‘ . SID);  // navrat na uvodni stranku
        exit;
      }
      break;

Pokud proměnná $action obsahuje „delete“, příslušný článek se smaže. Ještě než článek smažeme, musíme zjistit, zda přihlášený autor ($user_id) má k danému článku ($article_id) práva. Mohlo by se totiž stát, že by někdo do odkazu vložil id jiného článku a smazal by tak cizí článek. V případě, že přihlášený autor je autorem daného článku nebo je přihlášený autor administrátorem (má práva ke všem článkům), článek smažeme a vygenerujeme statické stránky.

    // smaze clanek
    case „delete“:
      $article_id = $_GET[‚article_id‘];
      $query = @MySQL_Query(„SELECT author FROM article WHERE id = $article_id“) or Weblog_Error(2);  // autor clanku
      $result = MySQL_Fetch_Array($query);
      // ma prihlaseny autor prava k tomuto clanku ?
      if($result[„author“] == $user_id || $user_type == „A“) {
        $query = @MySQL_Query(„SELECT archive_date FROM article WHERE id = $article_id“) or Weblog_Error(2);  // tyden, ve kterem clanek vysel
        $result = MySQL_Fetch_Array($query);
        
        $query = @MySQL_Query(„DELETE FROM article WHERE id = $article_id“) or Weblog_Error(2);
        $message = 2;
    
        // vygeneruje staticke stranky
        require „archive.php“;
        Create_Archive($result[‚archive_date‘]);
        Create_Index(„static“);
      } else {
        $message = 4;
      }
      MySQL_Close();
      Header(‚Location: http://‘. $_SERVER[‚HTTP_HOST‘] . ‚/weblog/admin/index.php?message=‘ . $message .’&‘ . SID);  // navrat na uvodni stranku
      exit;
      break;
  }
}

Úprava článku (update.php)

K úpravě napsaných článků použijeme soubor update.php. V úvodu načteme všechny potřebné soubory a do proměnné $article_id vložíme id daného článku.

ini_set(‚session.use_trans_sid‘, 1); // zajisti prenos session id
require „checklogin.php“; // je autor prihlasen ?
require „../db.php“; // pripoji k databazi
require „../function.php“; // nacte soubor s dulezitymi funkcemi
require „msg.php“; // chybove hlasky a zpravy
$article_id = $_REQUEST[‚article_id‘]; // id clanku

Následně z databáze vybereme nadpis a text daného článku a oba údaje vložíme do poměrně jednoduchého formuláře. Ke zpětné úpravě údajů, které byly modifikovány funkcí Text_Modify(), použijeme funkci un_Text_Modify(), o které bude řeč v závěru.

<?php
// vybere prislusny clanek a zobrazi formular
$query = @MySQL_Query(„SELECT title, message FROM article WHERE id = $article_id“) or Weblog_Error(2);
$result = MySQL_Fetch_Array($query);
$title = un_Text_Modify($result[‚title‘]);
$article_text = un_Text_Modify($result[‚message‘]);
?>
<h2 class=“heading“>Weblog – administrace</h2>
<h3 class=“heading“>Upravit článek</h3>
<?php
// chybova hlaska
if(IsSet($_GET[‚error‘])) $error = $_GET[‚error‘];
if(IsSet($error) && IsSet($msg_error[$error])) echo  ‚<p class=“error“>‘ . $msg_error[$error] . ‚</p>‘;
?>
<form action=“update.php“ method=“post“>
<input type=“hidden“ name=“sent“ value=““>
<input type=“hidden“ name=“article_id“ value=“<?php echo $article_id; ?>“>
<div class=“form“>
  <div class=“formrow“>
    <div class=“formdesc“>Nadpis</div><div class=“forminput“><input type=“text“ name=“title“ size=“30″ value=“<?php echo $title; ?>“ maxlength=“150″></div>
  </div>
  <div class=“formrow“>
    <div class=“formdesc“>Text</div><div class=“forminput“><textarea cols=“20″ rows=“5″ name=“article_text“><?php echo $article_text; ?></textarea></div>
  </div>
  <div class=“formrowsubmit“>
    <input type=“submit“ name=“send“ value=“Upravit“ class=“submit“>
  </div>
</div>
</form>

Pokud byl formulář odeslán, zkontrolujeme, zda byly vyplněny oba údaje a zároveň je upravíme funkcí Text_Modify(). Podobně jako u mazání článku, musíme zkontrolovat, zda-li má přihlášený autor práva k danému článku. Následně provedeme aktualizaci údajů v databázi a vygenerujeme statické stránky.

// byl odeslan formular ?
if(IsSet($_POST[‚sent‘])) {
  // uprava vstupu
  $title = Text_Modify($_POST[‚title‘]);
  $article_text = Text_Modify($_POST[‚article_text‘]);
  // byly vyplneny oba povinne udaje ?
  if($title==““ || $article_text ==““) {
    $error = 4;
  }
  
  // vse je v poradku
  if(!IsSet($error)) {
    $query = @MySQL_Query(„SELECT author FROM article WHERE id = $article_id“) or Weblog_Error(2);  // autor clanku
    $result = MySQL_Fetch_Array($query);
    
    // ma prihlaseny autor prava k tomuto clanku ?
    if($result[„author“] == $user_id || $user_type == „A“) {
      $query = @MySQL_Query(„UPDATE article SET title = ‚$title‘, message = ‚$article_text‘ WHERE id = $article_id“) or Weblog_Error(2);
      $message = 3;
      
      $query = @MySQL_Query(„SELECT archive_date FROM article WHERE id = $article_id“) or Weblog_Error(2);  // tyden, ve kterem clanek vysel
      $result = MySQL_Fetch_Array($query);
  
      // vygeneruje staticke stranky
      require „archive.php“;
      Create_Archive($result[‚archive_date‘]);
      Create_Index(„static“);
    } else {
      $message = 5;
    }
        
    MySQL_Close();
    Header(‚Location: http://‘. $_SERVER[‚HTTP_HOST‘] . ‚/weblog/admin/index.php?message=‘ . URLDecode($message) .’&‘ . SID);  // navrat na uvodni stranku
    exit;
  }
}

Úprava vstupních údajů

Doposud jsem již několikrát zmínil o funkci Text_Modify(), která provádí úpravu vstupních údajů tak, aby neposlušný uživatel nemohl narušit vzhled ani layout stránky, ale přitom mohl používat některé elementy a vkládat odkazy. Funkci tedy můžete použít v diskusních fórech, návštěvních knihách a podobně.

Postupně se odstraní mezery z obou konců řetězce, nebezpečné znaky se převedou na HTML entity, konce řádků na elementy <br />. S povolením některých elementů, především těch párových, je to o něco složitější. Aby uživatel mohl vložit například text „<em>kurziva <strong>tucna kurziva</strong></em> normal <em>kurziva</em>“ a dosáhl požadovaného výsledku „kurziva tucna kurziva normal kurziva„, musíme použít regulární výraz podle normy Perl, kde sekvence znaků .*? zajistí, že se funkce zastaví hned u prvního výskytu „</em>“. Při použití klasických regulárních výrazů a funkce EregI_Replace() bychom tohoto efektu nedosáhli a v kurzívě by byl celý řetězec. Důležité jsou ještě znaky si, které zajistí to, že funkce nebere ohled na nové řádky a malá a velká písmena. Další podrobnosti týkající se tohoto druhu regulárních výrazů najdete v manuálu PHP. S nepárovými elementy je to o poznání jednodušší, takže můžeme použít známou funkci EregI_Replace().

Dalším problémem jsou dlouhá slova, která dokáží „velmi dobře“ narušit vzhled celé stránky. PHP nám sice nabízí funkci Wordwrap(), ale chceme-li uživatelům umožnit vkládání odkazů, které jsou velmi často delší než únosná hranice, musíme použít trošku složitější postup. Celý text nejprve rozdělíme na jednotlivá slova, poté jimi postupně procházíme a testujeme, zda odpovídají tvaru odkazu. Pokud ano, pak obsah elementu <a> rozdělíme, ale parametr href ponecháme nerozdělený. Pokud slovo není odkazem, rozdělíme ho a jednotlivá slova spojíme dohromady.

function Text_Modify($text) {
  $text = Trim($text);  // odstrani mezery z obou koncu retezce
  $text = HTMLSpecialChars($text, ENT_QUOTES);  // prevede nebezpecne znaky
  // nahradi konce radku na tagy <br />
  $text = Str_Replace(„\r\n“,“ <br /> „, $text);
  $text = Str_Replace(„\n“,“ <br /> „, $text);
  
  // umozni vkladat nektere parove tagy
  $tags = Array(„b“, „u“, „i“, „small“, „big“, „strong“, „em“);
  while(Current($tags)) {
    $tag = Current($tags);
    $text = Preg_Replace(‚\'<‚ . $tag . ‚>(.*?)</‘ . $tag . ‚>\“. „si“, ‚ <‚ . $tag . ‚>\\1</‘ . $tag . ‚> ‚, $text);
    Next($tags);
  }
  
  // umozni vkladat nektere neparove tagy
  $tags2 = Array(„br“, „hr“);
  while(Current($tags2)) {
    $text = EregI_replace(„<“ . Current($tags2) . „( /)?>“, „<“ . Current($tags2) . “ />“, $text);
    Next($tags2);
  }
  
  $words = Split(„[[:blank:]]+“, Trim($text));    //rozdeleni textu na slova
  $connect_text = “;
  while(Current($words)) {
    $word = Trim(Current($words));  //odstraneni mezer na konci slova
    if(EregI(„http://[^ ]+\.[^< ]+“, $word, $part)) {
      $word = Str_Replace($part[0], ‚<a href=“‚ . $part[0] . ‚“>‘ . Wordwrap($part[0], 25, “ „, 1) . ‚</a>‘, $word);
    } elseif(EregI(‚www\.[^ ]+\.[^< ]+‘, $word, $part)) {
      $word = Str_Replace($part[0], ‚<a href=“http://‘ . $part[0] . ‚“>‘ . Wordwrap($part[0], 25, “ „, 1) . ‚</a>‘, $word);
    } else {
      $word = Wordwrap($word, 25, “ „, 1);
    }
    $connect_text .= $word . “ „;
    Next($words);
  }
  return Trim($connect_text);
}

Abychom uživatelům zajistili komfortní úpravu napsaných článků, zpracujeme údaje modifikované funkcí Text_Modify() opačnou funkcí un_Text_Modify. První tři řádky této funkce, které jsou vlastně opakem k funkci HTMLSpecialChars() můžeme klidně vypustit. Entity i původní znaky se totiž ve formuláři zobrazí identicky. V další části pak elementy <br /> nahradíme řádky a elementy <a> pouze vlastními odkazy.

function un_Text_Modify($text) {
  $trans_tbl = Get_HTML_Translation_Table(HTML_SPECIALCHARS);
  $trans_tbl = Array_Flip($trans_tbl);
  $text = StrTr($text, $trans_tbl);
  $text = EregI_Replace(“ <br /> „,“\n“, $text);
  $text = EregI_Replace(‚<a href=“([^“]+)“>[^<]+</a>‘, „\\1“, $text);
  return $text;
}

Instalace weblogu

  1. Staženíaplikační balík
  2. Vytvoření databáze – například pomocí příkazu mysqladmin create weblog
  3. Nastavení databáze – upravte soubor db.php
  4. Vytvoření databázových tabulek – pomocí příkazu mysql weblog spusťte klienta, v něm zapište příkaz \. vase_cesta\weblog.sql; (např. \. c:\lokal\weblog\weblog.sql;), můžete však použít i phpMyAdmin
  5. Administrátor – administrátora můžete vytvořit buď přímo v souboru weblog.sql, kde do příslušného SQL příkazu vložíte dané údaje nebo úpravou daného záznamu v tabulce author tak, že do položky user_type vložíte „A“

Případnou kritiku či náměty na vylepšení weblogu pište, prosím, do diskuse pod článkem.

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

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

3 Příspěvků v diskuzi

  1. co s tím je pokažde když chci přidat nějaký článek tak mi to napíše: Nastala chyba při generování statické stránky.

  2. no me to vubec nejede. pokazde prazdna obrazovka. zkousel jsem do index.php na zacatku napsat obycejne Ahoj a ani to se mi nezobrazi. co s tim? to budu muset projit cely kod? hruza… :o$

Odpovědět