Formuláře III.

Jiří Kosek ml.

Dnes budeme pokračovat v našem přehledu základních prvků použitelných při tvorbě formulářů. Podíváme se na to, jak se dají pomocí formulářů posílat soubory na server ke zpracování.

Upload souborů

Někdy v našich aplikacích potřebujeme, aby uživatel mohl na server odeslat soubor. Praktických příkladů je mnoho -- uživatel pošle svoji fotografii jako obrázek, který se bude zobrazovat u jeho příspěvků ve virtuální diskusní síni; autor HTML stránek odešle vytvořenou stránku ke kontrole syntaktické správnosti na server, který tuto službu nabízí; redaktor webzinu odešle pomocí formuláře na webovské stránce aktuální příspěvek.

Na tyto potřeby HTML pamatuje, a tak u elementu INPUT můžeme použít atribut TYPE=FILE. Takto vytvořené vstupní pole umožní zadat jméno souboru. Při odesílání formuláře je pak celý takto zadaný soubor odeslán s ostatními daty z formuláře. Velikost vstupního pole a maximální délku jména souboru můžeme ovlivňovat pomocí atributů SIZE a MAXLENGTH stejně jako u textových vstupních polí (TYPE=TEXT).

Některé prohlížeče umožňují u vstupního pole pro zadání jména souboru použití atributu ACCEPT. Jako jeho hodnota se uvádí čárkami oddělený seznam MIME typů souborů, které je možno zadat. Tak například použití ACCEPT="image/*" prohlížeči říká, že uživatel může poslat jakýkoliv obrázek.

My si upload souborů ukážeme na jednoduché aplikaci, která bude sloužit k prohlížení HTML souborů. Uživatel bude moci zvolit jméno souboru a typ zobrazení. Skript pak podle jeho požadavků stránku zobrazí buď ve zdrojovém tvaru včetně všech HTML tagů nebo zobrazí pouze samotný nezformátovaný text stránky. Formulář pro určení jména souboru, který se bude odesílat na server:

<HTML>
<HEAD>
<TITLE>Zobrazovač HTML stránek</TITLE>
</HEAD>
<BODY>
<H1>Zobrazovač HTML stránek</H1>
<FORM ACTION=10-01.php3 METHOD=POST
      ENCTYPE="multipart/form-data">
<TABLE BORDER=0>      
<TR>
    <TD>Jméno souboru:
    <TD><INPUT TYPE=FILE NAME=Soubor>
<TR VALIGN=TOP>
    <TD>Typ zobrazení:
    <TD><INPUT TYPE=RADIO NAME=Typ VALUE=HTML
               CHECKED> HTML<BR>
        <INPUT TYPE=RADIO NAME=Typ VALUE=PLAIN>
        Pouze text
<TR>
    <TD><INPUT TYPE=SUBMIT VALUE="    OK    ">
</TABLE>
</FORM>
</BODY>
</HTML>
U formuláře, který má odesílat soubor na server, musíme použít atribut ENCTYPE, který určuje metodu použitou při kódování dat formuláře. Standardně používaná metoda pro přenos dat z formuláře má označení application/x-www-form-urlencoded. Při odesílání souborů však musíme použít metodu kódování multipart/form-data.

Pokud odesíláme soubory, můžeme používat pouze metodu POST -- metoda GET je pro tyto účely zcela nevhodná.

Obr. 1: Vyplněný formulář pro odeslání souboru
Formulář pro odeslání souboru

Skript PHP, který zpracovává formuláře sloužící k odeslání souboru, obdrží o každém odeslaném souboru informace ve čtyřech proměnných. Jména těchto proměnných začínají stejně jako jméno formulářového pole pro zadání jména souboru. V našem případě tedy půjde o proměnné začínající na $Soubor....

Po přenesení souboru na server jej PHP uloží pod dočasným jménem do dočasného adresáře. Jméno, pod kterým je přenesený soubor uložen, v našem případě obsahuje proměnná $Soubor. Proměnná $Soubor_size obsahuje velikost přeneseného souboru v bajtech. Typ přeneseného souboru je uložen v proměnné $Soubor_type. Původní jméno odesílaného souboru získáme v proměnné $Soubor_name.

Nyní se tedy můžeme ukázat zdrojový kód obslužného skriptu (10-01.php3), který si dále ještě podrobněji vysvětlíme:

<HTML>
<HEAD>
<TITLE>Soubor: <?echo $Soubor_name?></TITLE>
</HEAD>
<BODY>
<H1>Soubor <?echo $Soubor_name?></H1>
Délka: <?echo $Soubor_size?><BR>
Typ: <?echo $Soubor_type?>
<PRE>
<? 
  if (file_exists($Soubor)):// přenesl se soubor ?
  
    $fp = fopen($Soubor, "r");  // otevření souboru

    if ($Typ=="HTML"):      // typ zobrazení HTML

      while (!feof($fp)):
        echo ereg_replace(" ", "&nbsp;", 
             htmlspecialchars(fgets($fp, 1024)));
        echo "<BR>";
      endwhile;  

    else:                   // typ zobrazení PLAIN

      while (!feof($fp)):
        echo ereg_replace(" ", "&nbsp;", 
             fgetss($fp, 1024));
        echo "<BR>";
      endwhile;  

    endif;

    fclose($fp);            // zavření souboru
    unlink($Soubor);        // smazání souboru
    
  else:                     // soubor se nepřenesl
  
    echo "Došlo k chybě při přenosu souboru!";
    
  endif;
?>
</PRE>
</BODY>
</HTML>
Skript do názvu stránky a do nadpisu vyplní jméno zobrazované stránky. Poté skript pomocí funkce file_exists() zjistí, zda existuje soubor, ve kterém je přenášený soubor dočasně uložen. Pokud soubor neexistuje, vypíše se chybové hlášení a skript končí.

Pokud soubor existuje, můžeme s ním dělat spoustu věcí. V PHP máme k dispozici několik funkcí pro práci se soubory jako s celkem (přesouvání, kopírování, mazání souborů apod.) nebo pro přístup k samotnému obsahu souboru.

Pokud chceme číst obsah souboru, musíme si soubor nejprve otevřít pro čtení. K tomu slouží funkce fopen(). Prvním parametrem je jméno souboru a druhým způsob přístupu k souboru -- r značí přístup pro čtení. Funkce fopen() vrací hodnotu, která pak otevřený soubor identifikuje v ostatních funkcích pro práci se soubory.

Následně se skript dělí na dvě větve, podle požadovaného formátu zobrazení stránky. První větev zobrazuje stránku včetně HTML tagů, druhá pouze samotný text stránky.

Pokud chceme nějakým způsobem zpracovat celý soubor, musíme jej číst tak dlouho, dokud nenarazíme na jeho konec. K testování zda jsme na konci souboru slouží funkce feof(). Ta vrací hodnotu true, pokud jsme již na konci specifikovaného souboru. Cyklus while(!feof($fp)) nám tedy umožní zpracovat celý soubor. (Vykřičník v podmínce znamená negaci -- cyklus se bude provádět tak dlouho, dokud nebude dosažen konec souboru.)

Naši analýzu si nyní zaslouží následující část skriptu:

echo ereg_replace(" ", "& ", 
     htmlspecialchars(fgets($fp, 1024)));
Funkce fgets($fp, 1024) čte ze souboru $fp jednu řádku, nejvýše však 1024 znaků. Výsledkem funkce je znakový řetězec. Tento řetězec vstupuje jako parametr do funkce htmlspecialchars(). Tato funkce nahradí všechny výskyty znaků '<', '>' a '&' odpovídajícími znakovými entitami '&lt;', '&gt;' a '&amp;'. Tím docílíme toho, že znakový řetězec již neobsahuje žádné HTML tagy, které by se snažil prohlížeč interpretovat.

Nakonec v získaném řetězci nahradíme všechny mezery pevnou mezerou (&nbsp;). Zůstane tedy zachováno odsazení jednotlivých řádek HTML kódu. K nahrazení mezer jsme použili funkci ereg_replace(). První parametr je řetězec, který se bude nahrazovat, druhý parametr je řetězec, kterým se budou nahrazovat všechny výskyty prvního řetězce v řetězci zadaném jako poslední parametr.

Výsledkem našeho snažení je řádka, kde jsou všechny speciální HTML znaky a mezery nahrazeny příslušnými entitami. Takto získaný řetězec vypíšeme pomocí příkazu echo. Následně pomocí příkazu echo "<BR>" ukončíme právě vypsanou řádku.

Pokud chceme vypsat pouze text stránky bez HTML tagů, postupujeme obdobně. Nyní však používáme funkci fgetss(), která narozdíl od fgets() ze svého výsledku vynechává všechny HTML tagy. Výsledkem je tedy výpis stránky oproštěné od HTML tagů.

Nakonec uzavřeme otevřený soubor pomocí fclose() a smažeme dočasný soubor pomocí funkce unlink(). Pokud bychom soubor nesmazali, zbytečně by se nám zaslané soubory hromadily v adresáři pro dočasné soubory.

Obr. 2: Výsledek skriptu pro zobrazování HTML stránek
Skript pro zobrazování HTML stránek

Pokud používáme ASP a chceme zpracovávat odeslané soubory, máme situaci trošku složitější. ASP totiž neobsahují přímo podporu pro upload souborů. S některými verzemi IIS se však dodává aplikace Posting Acceptor, která umožňuje snadnou práci se soubory zaslanými na server.

Obr. 3: Druhý formát výstupu skriptu
Skript pro zobrazování HTML stránek


Příště se podíváme na zbývající prvky formulářů -- seznamy a víceřádkový text. Ukážeme si, jak vytvářet formuláře, se kterými se bude uživatelům pohodlně pracovat.

© Jiří Kosek 1999