V předchozím článku jsem naznačil, že v některých situacích je výhodné, aby výstupem PHP skriptu, který získává data z SQL serveru, nebyla www stránka, ale soubor ve formátu DBF. O tom, jak se dá takový takový skript vytvořit, si můžete přečíst v tomto článku.

Vše si budeme pro názornost demonstrovat na konkrétním příkladu. Abych usnadnil práci alespoň těm čtenářům Intervalu, kteří sledovali seriál s názvem „Databáze kontaktů v PHP“, rozhodl jsem se použít server MySQL a tabulku TKontakty_Firmy (v první části „Databáze kontaktů…“ najdete zdrojový text SQL skriptu, který zmíněnou tabulku vytvoří). Tato tabulka obsahuje položky: Firma_ID int(11), Nazev varchar(50), Ulice varchar(50), Mesto varchar(50), PSC varchar(10), Telefon varchar(50), Fax varchar(50). Níže popsaný PHP skript bude posílat dotaz na SQL server a z výsledku dotazu vytvoří DBF soubor a nabídne jej uživateli ke stažení.

Hlavní myšlenka skriptu

Nejprve otevřeme spojení s SQL serverem a položíme SQL dotaz. Poté vytvoříme soubor ve formátu DBF a postupně do něj přidáváme jednotlivé záznamy tak, jak je získáváme pomocí funkce mysql_fetch_row. Klientovi pošleme příslušné hlavičky a poté celý obsah DBF souboru. Nakonec tento soubor smažeme. Kromě funkcí umožňujících práci s MySQL (ty jsou dobře popsány v jiných článcích na tomto serveru) využijeme také následující funkce:

  • dbase_create(string název_souboru, array položky) – vytvoří DBF soubor zadaného názvu. Jednotlivé prvky pole "položky" jsou opět pole s následujícím obsahem: první prvek obsahuje název položky, druhý prvek typ položky, třetí délku a čtvrtý přesnost. Přípustné hodnoty parametru typ jsou: "C" – textový řetězec, má délku a nemá přesnost, "N" – číslo, má délku i přesnost (ta odpovídá počtu míst za desetinnou čárkou). Všechny zbylé typy nemají ani délku, ani přesnost: "L" – logická hodnota, "D" – datum (ve formátu RRRRMMDD, PHP jej automaticky převádí na string) a "M" – memo (text libovolné délky), tento typ není v dbase_* funkcích jazyka PHP podporován. V případě úspěšného provedení funkce získáme identifikátor databáze, v ostatních případech vrací funkce false.
  • dbase_add_record(int indentifikátor_databáze, array položky) – přidá do zadané databáze záznam, jehož položky odpovídají prvkům pole, které uvedeme jako druhý parametr této funkce. Pokud se podaří záznam přidat, vrátí funkce true, v opačném případě vrátí false.
  • dbase_close(int indentifikátor_databáze) – uzavře databázi.
  • uniqid(string prefix, [int lcg]) – vrací unikátní identifikátor opatřený zadaným prefixem. Pokud je nepovinný parametr lcg rovný true, připojí se na konec ještě pseudonáhodný řetězec (tuto možnost nabízí jen novější verze jazyka PHP, dříve měla tato funkce jen jeden parametr). Tuto funkci použijeme v našem skriptu na vytvoření jména DBF souboru.
  • header(string hlavička) – zašle klientovi určenou hlavičku. V naší ukázce budeme této funkce používat v situaci, kdy budeme chtít klienta informovat o typu zasílaných dat a také když náš skript bude nabízet soubor ke stažení.
  • readfile(string název_souboru, [int include_path]) – přečte zadaný soubor a přepíše jej na standardní výstup. Použijeme-li na místě druhého, nepovinného, parametru true, bude se zadaný soubor hledat i v adresářích uvedených v direktivě include_path souboru php.ini.
  • unlink(string název_souboru) – smaže zadaný soubor.

Zde je kompletní zdrojový kód našeho skriptu

<?php
/* Tato (pomocná) funkce je volána pouze v případě, že nastane chyba */
function vypsat_zpravu($text)
{
  echo "<html>\n";
  echo "<head><title>Nastala chyba!</title></head>\n<body>\n";
  echo "<h1>Nastala chyba!</h1>\n<p>$text</p>\n</body>\n</html>";
}
 
/* Zde začíná "vlastní" skript, celý je uzavřen do cyklu do-while (false), což při použití příkazů break značně usnadní a zpřehlední zpracování chybových stavů */
do {
 
/* Vytvoříme spojení s SQL serverem a zvolíme databázi – nezapomeňte upravit tak, aby to odpovídalo Vašemu nastavení. */
$spojeni = @mysql_connect("localhost");
if (!$spojeni)
{
  vypsat_zpravu("Nepodařilo se připojit k databázi.");
  break;
}
 
//Taktéž upravte podle Vašeho nastavení:
@mysql_select_db("test", $spojeni);
 
/* Připravíme si SQL dotaz (v praxi bychom jej získali asi jinak…) */
$dotaz = "select * from TKontakty_Firmy";
 
/* Vytvoříme pole, která odpovídají jednotlivým položkám */
$polozky[] = array("Firma_ID", "N", 11, 0);
$polozky[] = array("Nazev", "C", 50);
$polozky[] = array("Ulice", "C", 50);
$polozky[] = array("Mesto", "C", 50);
$polozky[] = array("PSC", "C", 10);
$polozky[] = array("Telefon", "C", 50);
$polozky[] = array("Fax", "C", 50);
 
// Získáme unikátní název DBF souboru
$nazev_souboru = uniqid("soubor", true) . ".dbf";
 
//Vytvoříme DBF soubor
$dbf_soubor = @dbase_create($nazev_souboru, $polozky);
if (!$dbf_soubor)
{
  vypsat_zpravu("Nepodařilo se vytvořit DBF soubor.");
  break;
}
 
//Získáme výsledek SQL dotazu
$vysledek = mysql_query($dotaz, $spojeni);
if (!$vysledek)
{
  vypsat_zpravu("Zpracování SQL dotazu neproběhlo úspěšně.");
  break;
}
 
/* Postupně přidáváme jednotlivé záznamy do DBF souboru */
while ($zaznam = @mysql_fetch_row($vysledek))
  @dbase_add_record($dbf_soubor, $zaznam);
 
//Uzavřeme obě spojení
@mysql_close($spojeni);
@dbase_close($dbf_soubor);
 
/* Uživateli nabídneme soubor ke stažení – zašleme sadu příslušných hlaviček a následně obsah celého souboru */
header("Content-Type: application/dbf");
header("Content-Disposition: attachment; filename=vysledek.dbf");
header("Content-Description: PHP Generated Data");
@readfile($nazev_souboru);
 
//Soubor nakonec smažeme
@unlink($nazev_souboru);
 
} while (false);
?>

Pokud by přicházelo na server velké množství požadavků a nevadily by nám větší nároky na diskovou kapacitu, mohli bychom zrychlit celý proces tím, že bychom DBF soubory nemazali a cesty k těmto souborům ukládali společně s příslušnými SQL dotazy do nějaké databáze. PHP skript by vytvořil nový DBF soubor pouze v případě, že by databáze neobsahovala zadaný dotaz. Pak by samozřejmě bylo nutné zajistit, aby se při každé změně dat na SQL serveru změnily i obsahy DBF souborů.

Pro úplnost dodejme, že podobným způsobem bychom mohli pomocí PHP skriptů vytvářet soubory ve formátu CSV, což jsou textové soubory, jejichž řádky odpovídají jednotlivým záznamům, přičemž jednotlivé položky jsou od sebe odděleny středníkem. Soubor bychom vytvořili např. pomocí funkce fopen. Prvky polí, která získáváme při čtení jednotlivých záznamů z výsledku SQL dotazu, bychom sloučili do jednoho řetězce příkazem implode($zaznam, „;“) a výsledné řetězce zapsali do souboru pomocí funkce fwrite. Posledním rozdílem proti našemu skriptu, který generuje soubory ve formátu DBF, by byly zasílané hlavičky.

Stejně jako minule si můžete stáhnout zdrojový soubor.

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

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

2 Příspěvků v diskuzi

  1. Díky moc za návod, pomohl mi vyřešit zdánlivě neřešitelný problém. :)

    Jen by se hodil i návod na to, jak nainstalovat knihovnu php_dbase.dll, s tím jsem laboroval asi týden, protože mi wamp server stále hlásil nekompatibilitu. Vyřešila to instalace nižší verze php, která knihovnu obsahovala už v sobě.

  2. Článek mi také moc pomohl, děkuji, ale narazil jsem na problém s kódováním. Dbase mi vytváří soubor s ASCII a OEM doplňkem. Potřeboval bych ale ASCII s ANSI. řešil to už někdo? Děkuji za odpověď

Odpovědět