Zvýraznenie syntaxi PHP uprostred textu

2. října 2001

Máte web, na ktorom publikujete články o PHP, ale chceli by ste, aby bol zdrojový kód jasne odlíšený od ostatného textu? Samozrejme, že môžete už pri písaní článku začať formátovaním, ale prečo sa trápiť, keď PHP môže odviesť prácu za vás?

V tomto článku vám ukážem, že to nieje nič zložité. Budete si musieť vytvoriť vlastné tagy pre vyznačenie zdrojového kódu v texte. Ja som použil <zdrojovy_kod> </zdrojovy_kod>. Na záver vám vysvetlím, prečo si nevystačíme len s oddelovačmi <??>. Funkcia pracuje s funkciami, ktoré sú dostupné len v  PHP > 4.

 Vytvorím si súbor func.php do ktorého si napíšem dve funkcie. Tá prvá bude formátovať normálny text, a druhá bude zaobchádzať so všetkým čo je uzavreté v tagu <zdrojovy_kod> ako so zdrojovým kódom.

Prvú funkciu pomenujem format_text(). Bude mať dva vstupné parametre: text, ktorý upravuje a maximálnu dĺžku slova. V prípade, že je slovo dlhšie ako $dlzka znakov, bude predelené medzerou práve po $dlzka znakoch.

<?PHP //func.php
Function format_text($text, $dlzka){ 
$text = Trim($text);
$text = HTMLSpecialChars($text); //prevedieme špeciálne znaky na ich entity
$text = Str_Replace(„\r“,““,$text); //Win systemy používajú ako konce riadkov znak \n ale \r\n (\r tu nieje podstatné, a preto ho odstránim)
$text = Ereg_Replace(„\n{3,}“,“ \n\n „, $text);
//ak sa v článku nachádza viac ako 3 súvislé konce riadkov nahradíme ich dvomi
$text = Str_Replace(„\n“,“ <br> „,$text); //vlastná NL2BR()
$novyText = „“;
$slovo = Split(„[[:blank:]]+“, $text);
//z textu si vytvorím pole, ktorého prvkami budú jednotlivé slová
for ($i=0;$i<Count($slovo);$i++):
    // v tomto cykle si zistíme, či dané slovo nieje odkaz, a či má každé povolenú dĺžku
  $slovo[$i] = Trim($slovo[$i]); //najprv odstránim prípadné medzery
  if (Eregi(„^www\.[a-z0-9]+[a-z0-9\._=/&\?~]*$“, $slovo[$i])):
       //slovo je odkaz typu www.nieco.sk 
    if (StrLen($slovo[$i]) > $dlzka): 
          //ak je odkaz dlhší, ako je povolené
       $noveSlovo = „<a href=\“http://“.$slovo[$i].“\“>“ . SubStr($slovo[$i], 0, $dlzka-3) . „…</a>“; //zobrazím z odkazu len $dlzka znakov a zvyšné nahradím (…)
    else: //odkaz má povolenú dĺžku a môžem ho zobraziť celý
       $noveSlovo = „<a href=\“http://“.$slovo[$i].“\“>“ . $slovo[$i] . „</a>“;
    endif;
  elseif (Eregi(„^http://[a-z0-9]+[a-z0-9\._=/&\?/~]*$“, $slovo[$i])):
      //odkaz je typu http://nieco.sk
    if(StrLen($slovo[$i]) > $dlzka): //a znova to isté
       $noveSlovo = „<a href=\““.$slovo[$i].“\“>“ . SubStr($slovo[$i],0,$dlzka-3) . „…</a>“;
    else:
       $noveSlovo = „<a href=\““.$slovo[$i].“\“>“ . $slovo[$i] . „</a>“;
    endif;

  elseif (Eregi(„^[a-z0-9]+[a-z0-9\._-]*[a-z0-9]+@[a-z0-9]+[a-z0-9\._-]*[a-z0-9]+\.[a-z]{2,3}$“, $slovo[$i])):
     //a môže to byť ešte emailová adresa. Regulárny výraz pochádza z článku Regulárne výrazy II z www.interval.cz */
    if(strlen($slovo[$i]) > $dlzka): //do tretice všetko dobré
         //nie som si istý, či emailová adresa môže mať maximálne 40 znakov.
       $noveSlovo = „<a href=\“mailto:“.$slovo[$i].“\“>“ . SubStr($slovo[$i],0,80) . „…</a>“;
    else:
       $noveSlovo = „<a href=\“mailto:“.$slovo[$i].“\“>“ . $slovo[$i] . „</a>“;
    endif;

  else:
      //nejedná sa o židny odkaz, ale o normálne slovo
    if (StrLen($slovo[$i]) > $dlzka): //ak je dlhšie…
       $noveSlovo = Chunk_Split($slovo[$i], $dlzka, “ „);  /*funkcia chunk_split(retazec, dlzka , lep) rozdelí reťazec vždy po dĺžka znakov na menšie, a spojí ich lepom*/
    else:
       $noveSlovo = $slovo[$i]; //normálne slovo do povolenej dĺžky
    endif;
  endif;
  $novyText .= $noveSlovo . “ „; //nakoniec slová znovu pospájame do textu
endfor;

Možno si kladiete otázku, prečo nepoužijem na nahradenie netlačiteľného konca riadku \n na <br> funkciu NL2BR, ale str_replace. Odpoveď je jednoduchá. Pretože funkcia nl2br nahrádza v reťazci \nTEXT za <br />\nTEXT. TEXT môže byť kľudne URL, ktorá sa bude hľadať regulárnymi výrazmi. Keďže na začiatku by obsahovala znak \n, nenašli by ju.

Zatiaľ sa v novom texte nachádzajú všetky špeciálne znaky ako HTML entity, pretože sme ich prekladali na začiatku funkciou HTMLSpecialChars(). Pokiaľ nechceme v texte povoliť žiadne HTML tagy, ani entity, môžete na toto miesto umiestniť „return $novyText“;. Tento príkaz predčasne ukončí funkciu a vráti hodnotu $novyText. Naopak, ak ste si istý, že text, ktorý prejde funkciou ste skontrolovali a neobsahuje žiadne HTML chyby, môžete tieto kroky vynechať. V takom prípade odstráňte 2 riadok funkcie ($text =  HTMLSpecialChars($text); a tiež použite príkaz return namiesto toho, aby ste ďalej pokračovali.

Ukážem vám, ako je možné povoliť len niektoré. Preto si vytvorím dve polia: $povolene $entita. Dajte si pri písaní pozor, aby ste dodržali index prvku povoleného znaku s indexom prvku jeho entity.

  $povolene[0] = „>“;            $entita[0] = „&gt;“;
  $povolene[1] = „<b>“;        $entita[1] = „&lt;b>“;
  $povolene[2] = „</b>“;       $entita[2] = „&lt;/b>“;
  $povolene[3] = „<font „;      $entita[3] = „&lt;font“;
  $povolene[4] = „</font>“;    $entita[4] = „&lt;/font>“;
  $povolene[5] = „<a“;           $entita[5] = „&lt;a“;
  $povolene[6] = „</a>“;        $entita[6] = „&lt;/a>“;
  $povolene[7] = „&“;             $entita[7] = „&amp;“;
  $povolene[8] = „<i>“;          $entita[8] = „&lt;i>“;
  $povolene[9] = „</i>“;         $entita[9] = „&lt;/i>“;
  $povolene[10] = „\““;           $entita[10] = „&quot;“;

Ak sa rozhodnete touto funkciou formátovať text napríklad v knihe návštev, viac tagov by ste už nemali povoliť, pretože by mohli poškodiť vzhľad stránky. Buďte tiež opatrní pri písaní uvodzoviek v tagoch. Takýto zápis by mohol ukryť značnú časť textu <font size=“1 face= „Arial“>. Na niektorých diskusných forách je preto použitie uvodzoviek v celom texte odstraňované.

Stačí už len vytvoriť cyklus, ktorý bude prevádzať entity späť na špeciálne znaky a nakoniec upravený text vrátiť.

  for ($x=0;$x<Count($povolene);$x++):
     $novyText = Eregi_Replace($entita[$x], $povolene[$x], $novyText);
  endfor;
  return $novyText;
} //nezabudnite funkiu zavrieť

Teraz pristúpim k  hlavnej časti tohto článku – formátovanie (a farbenie) textu so zdrojovým kódom. Prv, než začnete s tvorbou samostatnej funkcie, pripravte si CSS súbor, ktorý nazveme style.css. Do tohto súboru si napíšeme triedy, ktoré budú farbiť kód.

.h {color:#ffffff;} /*HTML – white*/
.s {color:#c0c0c0;} /*reťazce – silver*/
.c {color:#ffcc99;} /*komentáre orange*/
.d {color:#33ccff;} /*premenne funkcie – skoro aqua*/
.k {color:#33cc99;} /*podmienky, operátory – zelený odtieň*/
.zdroj_kod {background: #000000; /*pozadie – čierne*/
                 font-size: 9pt; /*veľkosť 9 bodov*/}

Funkciu nazveme format_zdroj(). Opäť budú vstupné parametre funkcie $text a $dlzka. S premennou dlzka ďalej nepracuje, iba ju predáva funkcii format_text(). Prv, než sa pustím do písania zdrojového kódu, vysvetlím vám 2 funkcie, s ktorými tu budem pracovať.

StrPos(text, hladane[, začiatok hľadania])

Funkcia „StrPos“ hľadá v  texte reťazec string, a spočíta na koľkom znaku v texte začína. Ak chcem vedieť pozíciu reťazca $hladane = „PHP“; v reťazci $text =“pomocou PHP vytvoríme“, použijem $start = StrPos($text, $hladane);. Funkcia vráti hodnotu 8, pretože hľadaný reťazec začína po ôsmom znaku. Ak chceme zistiť, na ktorej pozícii hľadaný znak končí, musíme k tejto hodnote pripočítať aj dĺžku hľadaného reťazca + StrLen($hladane). Nepovinný parameter začiatok hľadania sa udáva, ak nechcete uskutočniť hľadanie v texte od nultého znaku. Bližšie o tejto funkcii nájdete v PHP manuáli

SubStr(reťazec, start[, dlzka])

Táto funkcia už bola vysvetľovaná v článku Práce s řetězci v PHP podruhé. Funkcia vracia časť reťazca, ktorý je vymedzený číslami start a nepovinnym parametrom dĺžka. Parameter start určuje, z ktorej pozície reťazca sa začne vyberať. Pokiaľ je zadaný parameter dĺžka, začne sa na pozícii start, a skončí sa po dĺžka znakoch. Ak bude start záporné číslo, počítať sa bude od posledného znaku. Podrobnejšie o tejto funkcii nájdete tiež v  manuáli.

Tieto dve funkcie budú zohrávať dôležitú rolu pri získavaní zdrojového kódu z textu. Ešte bude treba zvýraznť syntax tohto kódu a zaradiť ho späť do textu. Na zvýraznenie syntaxe použijem funkciu „void highlight_string(reťazec)“. Táto funkcia vytlačí obsah reťazca so zvýraznenou syntaxou PHP podľa farieb nastavených v php.ini. Bude treba donútiť funkciu highlight_strng, aby nevytlačila obsah reťazca, ale aby sme ho načítali do premennej. Poslúžia k tomu výstupné funkcie.

Function format_zdroj($celok, $dlzka){

  $TAG = „zdrojovy_kod“; //sem si napíšte váš vlastný tag
  $pocet_zk = SubStr_Count($celok, „<$TAG>“); //počet otváracích tagov <$TAG>
  $pocet_end_zk = SubStr_Count($celok, „</$TAG>“); //počet uzatváracích tagov </$TAG>

  if ($pocet_end_zk != $pocet_zk OR $pocet_zk == 0)
      return format_text($celok, $dlzka); //ak nie je rovnaký počet otváracích a zatváracích tagov, fcia vráti celok ako text.
  $koniec = StrRPos ($celok, „</$TAG>“) + StrLen(„</$TAG>“); //pozícia posledného tagu </$TAG>. StrRPos hľadá prvú pozíciu od konca
  $koniec = SubStr($celok, $koniec); //odrezanie poslednej časti z celku (jedná sa o normálny text) do premennej koniec
  $table = "<table align=center width=\"90%\">\n\t<tr><td class=\"zdroj_kod\">";
  $table_end = "</td></tr></table>"; //pripravím si začiatok a koniec tabuľky, ktorá bude obklopovať zdrojový kód
  $NovyCelok = "";

  for ($i=0;$i<$pocet_zk;$i++):
  //tento cyklus vykonáme toľko krát, koľkokrát je použitý <$TAG>

    $start = StrPos($celok,"<$TAG>") + StrLen("<$TAG>"); //pozícia prvého použitia <$TAG> v reťazci $celok, ku ktorej je pripočítaná dlĺžka tagu
    $dlzka_ZK = StrPos($celok,"</$TAG>") – $start; //dlzka zdrojoveho kodu
    $text = SubStr($celok, 0, $start – StrLen("<$TAG>")); //text ktory sa nachadza pred prvym pouzitim <$TAG>
    $zdroj = SubStr($celok, $start, $dlzka_ZK); // "odrežeme" zdrojový kód

    $zdroj = StripSlashes($zdroj); //ešte musím  zo zdroja odstrániť spätné lomítka, ktoré sa (ne)dosadili v závislosti od nastavenia magic_quotes_runtime v php.ini

    OB_Start(); //zapnem bufferovanie výstupu – to znamená všetko čo sa bude mať odoslať, sa neodošle, ale sa uloží do bufferu, až pokým sa nenarazí na funkciu, ktorá buffer vypne.
    Highlight_String(Trim($zdroj)); //odstránenie prebytočných medzier z koncov a zvýraznenie syntaxe výstup funkcie sa uloží do bufferu
    $zdroj = OB_Get_Contents(); //načítanie bufferu do premennej zdroj
    ob_end_clean(); //vypnutie bufferu a vymazanie jeho obsahu

    $farby = Array("h"=>"highlight.html",
                          "c"=>"highlight.comment",
                          "s"=>"highlight.string",
                          "k"=>"highlight.keyword",
                          "d"=>"highlight.default");
/*farby je asociatívne pole, kde idex pola znamená triedu CSS, ktorá sa použije pre daný prvok zdrojového kódu*/

    while (List($class, $color) = Each ($farby)): //každý index načítam do premennej $class a prvok do $farba. Každú farbu nahradím príslušnou CSS triedou, čím samozrejme šetrím bajty vo výstupe
      $farba = "color=\"" . Get_Cfg_Var($color) . "\""; //zistím, aká farba je nastavená v php.ini pre daný element
      $zdroj = Str_Replace("$farba", "class=$class", $zdroj); //nahradím farbu za mnou vytvorenú triedu CSS. Toto je výhodné napríklad vtedy, ak nemôžte zasahovať do hp.ini
    endwhile;

  $zdroj = Str_Replace("<code>“,$table, $zdroj); //tag code dosadzuje funkcia Hightlight_String na začiatok a na koniec. Ja ho nahradím tabuľkou
  $zdroj = Str_Replace("</code>“,$table_end, $zdroj);
  $zdroj = Str_Replace("&nbsp;“,“ „, $zdroj); //každá aj jednoduchá medzera je nahradená nedelitelnou. Ja ju prevediem späť na jednoduchú aby som zašetril bajty.
  $zdroj = Str_Replace("  „,“&nbsp; „, $zdroj); //dve medzery za sebou už nahrádzam jednou non breaking a jednou normálnou

  $NovyCelok .= format_text($text, $dlzka) . $zdroj; //sformátovaný text a zdrojový kód pripojím k NovémuCelku
  $celok = SubStr($celok, $dlzka_ZK + $start + StrLen("</$TAG>“)); //a od starého odrežem už sformátovanú časť

endfor;

$NovyCelok .= format_text($koniec, $dlzka); //a nesmiem zabudnúť pridať poslednú časť textu

return $NovyCelok;
}

A funkcia je na svete. Asi k nej netreba nič dodávať, pretože je dostatočne komentovaná. Keby ste predsa len niečomu nerozumeli, môžete to napísať do diskusie pod článok. Teraz môžete funkciu použiť vo svojich skriptoch či už pred zobrazovaním článku, príspevku v diskusnom fóre… Vytvorím vám ešte ukážkový skript kod.php, aby ste videli, ako ju môžete jednoducho použiť.

<html><head>
<title>Zvýraznena syntax</title>
<SCRIPT LANGUAGE=“JavaScript“ TYPE=“text/javascript“>
<!–
function dosad_tagy(ktory){
var clanocek;
var otaznik = „?“;
clanocek = ktory.clanok.value; 
clanocek = clanocek + „<zdrojovy_kod>“+“<“ + otaznik +“\n\n“ + otaznik + „>“ + „</zdrojovy_kod>“;
ktory.clanok.value = clanocek;
}
//–>
</SCRIPT>
<LINK REL=“StyleSheet“ HREF=“style.css“ type=“text/css“>
</head>
<body bgcolor=“#c0c0c0″>
<?if($REQUEST_METHOD==“POST“):
include(„./func.php“);
echo StripSlashes(format_zdroj($clanok, 50));
echo „<p><a href=\“kod.php\“>Znova</a>“;
else:?>
<form action=“kod.php“ method=“post“>
<textarea name=“clanok“ cols=“80″ rows=“20″></textarea>
<input type=“Button“ onclick=“dosad_tagy(this.form)“ value=“Pridať tagy pre ZK“> 
<input type=“Submit“ value=“Formátuj text“>
</form>
<?endif;?>
</body>
</html>

V úvode som sľúbil, že vám poviem, prečo som musel zaviesť vlastné tagy <zdrojovy_kod> a nestačilo zdrojový kód len vymedziť do <??>. Funkcia Highlihhgt_String pracuje so všetkým čo je uzavreté v oddelovačoch <??> ako so zdrojovým kódom PHP a všetko mimo nich berie ako HTML. Keďze často vkladáte PHP do HTML, moja funkcia by v tom prípade hľadala znaky (a formátovala medzi znakmi) <? a ?> a samostatný HTML kód by brala ako normálny text. HTML.

Zdrojové kódy k funkcii si samozrejme môžete stiahnúť, alebo vyskúšať.

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

Nejnovější

Napsat komentář

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