PHP v praxi, 26. díl - Zipujeme za pochodu
Tématem dnešního dílu bude vytváření zazipovaného souboru na straně serveru.
Představme si situaci, kdy jste fotograf a výsledky své práce nabízíte ke stažení.
Fotografie v archivu neustále přibývají a aby návštěvníci vašich stránek nebyli
příliš otráveni neustálým klikáním, nabízíte všechny své fotografie zabalené
v jednom souboru. To ovšem na druhou stranu znamená značné časové ztráty pro
vás - po každém updatu fotografií je znovu všechny zabalit a uploadovat na server.
Proto je značně výhodné využít skript, který všechny soubory v dotyčném adresáři
zabalí za vás.
Co budeme potřebovat: využijeme třídu, dodávanou s phpMyAdmin, jež má v sobě
informace, jak takový zip soubor má vypadat. Stáhnout phpMyAdmin
(450 kB). Soubor se nachází v adresáři "libraries" a jmenuje se "zip.lib.php".
Budeme mít celkem tři soubory - výše zmíněný zip.lib.php, dále pack.php, obsahující
konkrétní funkce, a download.html, jenž bude nabízet příslušný "soubor"
ke stažení.
Začneme právě download.html:
<html> <body> <a href="pack.php">package.zip</a> </body> </html>
|
Odkaz, jak vidíte, nemíří tedy na žádný *.zip, nýbrž na soubor pack.php. Ten
si postupně rozebereme. Nejprve si ukážeme kostru bez obsahu funkcí:
<?
include("zip.lib.php");
$dir="pictures/";
$zip_name="pictures.zip";
$files=get_files($dir);
$names=$files;
$zip_content=pack_it($dir,$files,$names);
download_it($zip_content,$zip_name);
?>
|
Nejprve se načte příslušná knihovna zip.lib.php, pak nastavíme jméno adresáře,
ve kterém budou umístěné dotyčné soubory (třeba ty fotografie) a do proměnné
$zip_name umístíme informaci o názvu výsledného (staženého) souboru.
Pole $files bude obsahovat jména souborů (fotografiíí), které získáme z funkce
get_files(). Protože můžeme mít jiné názvy jmen ve výsledném archivu, než jsou
jména souborů, je zde ještě pole $names. V naší ukázce tuto vlastnost nevyužijeme,
proto jsme $names přiřadili hodnoty z $files. Rozumné by to bylo v případě,
že fotografie se jmenují 0001.jpg, 0002.jpg atp. a někde jinde máte uloženy
bližší popisné informace. Pak by si návštěvník stáhl soubor, ve kterém by již
byly kvetiny.jpg, hrad.jpg apod. Hned poté se použije funkce pack_it(), jež
zabalí soubory do archivu a vrátí obsah souboru. Ten tedy přiřadíme proměnné
$zip_content. Ukončíme zavoláním funkce download_it(), která již vyvolá nabídku
ke stažení souboru v prohlížeči.
Nyní se postupně seznámíme s jednotlivými funkcemi.
function get_files($dir)
{
$handle=opendir($dir);
$i=0;
while (false!==($file = readdir($handle)))
{
if ($file!="."&&$file!=".."&&!is_dir($file))
{
$files[$i]=$file;
$i++;
}
}
closedir($handle);
return $files;
}
|
Funkce get_files je již několikrát ukázaný a pozměněný cyklus na získání názvů
souborů. Výstupem funkce je pole $files[], obsahující tato jména.
function pack_it($dir,$files,$names)
{
$zip = new zipfile();
for($i=0;$i<count($files);$i++)
{
$fp=fopen($dir.$files[$i],"rb");
$part_content=fread($fp,filesize($dir.$files[$i]));
fclose($fp);
$zip->addFile($part_content,$names[$i]);
}
$content=$zip->file();
return $content;
}
|
Tato funkce, pack_it(), je jádrem celého skriptu. To ona pracuje se třídou
v zip.lib.php. Vytvoření instance třídy zipfile se vytvoří známým zaklínadlem
new název_třídy. $zip je tedy instance třídy zipfile a jako s takovou
s ní teď budeme pracovat. Následuje cyklus, jehož smyslem je načíst data ze
souborů a poslat je ke zpracování třídě zipfile. Načtení obsahu souboru již
bylo také několikrát okomentováno, proto jen upozorním (znovu) na atribut "rb".
Ten je pouze kvůli systémům, rozeznávajícím binární data (Windows), na linuxovém
serveru se s tímto problémem nesetkáte. Když však pod Windows použijete pouze
"r", načte se jen část souboru. Poté co otevřeme soubor a načteme
jeho obsah do proměnné $part_content, použijeme metodu addFile() třídy zipfile.
Ta zkomprimuje a začlení obsah souboru do budoucího zip archivu. Jeho atributy
jsou $part_content, tedy obsah toho jednoho souboru, a dále jeho jméno, jež
bude mít ve výsledném archivu. Toto se opakuje do doby, než se vyčerpají všechna
jména souborů. Když se tak stane, zavolá se metoda file(), která vrací kompletní
obsah zip archivu. To je také cílem této funkce pack_it(), takže právě tato
data vrátíme příkazem return.
function save_it($content,$zip_name)
{
$fp=fopen($zip_name,"wb");
fwrite($fp,$content);
fclose($fp);
}
function download_it($content,$zip_name)
{
header("Content-type: application/octet-stream name=$zip_name");
header("Content-disposition: attachment; filename=$zip_name");
echo $content;
}
|
Nakonec nabízíme zip archiv ke stažení ve funkci download_it(). Jako bonus
jsem přidal ještě funkci save_it(), jež má za úkol data čistě uložit. K té již
nelze moc říci, práci se soubory jsme si ukazovali již mnohokrát. Zato ve funkci
download_it() je použitá ještě nikdy nezmíněná funkce header(). Ta vytváří hlavičky
souborů, takže díky těmto informacím prohlížeč jednoduše pozná, že se nejedná
o stránku, ale o soubor. Obsah tohoto souboru mu pošleme standardním příkazem
echo. Bez hlavičky by jej ale zobrazil přímo na stránce jako změť znaků.
Nakonec opět kompletní skript, abyste jej nemuseli skládat jako puzzle.
<?
include("zip.lib.php");
$dir="pictures/";
$zip_name="pictures.zip";
function get_files($dir)
{
$handle=opendir($dir);
$i=0;
while (false!==($file = readdir($handle)))
{
if ($file!="."&&$file!=".."&&!is_dir($file))
{
$files[$i]=$file;
$i++;
}
}
closedir($handle);
return $files;
}
function pack_it($dir,$files,$names)
{
$zip = new zipfile();
if (count($files)!=count($names)) $names = $files;
for($i=0;$i<count($files);$i++)
{
$fp=fopen($dir.$files[$i],"rb");
$part_content=fread($fp,filesize($dir.$files[$i]));
fclose($fp);
$zip->addFile($part_content,$names[$i]);
}
$content=$zip->file();
return $content;
}
function save_it($content,$zip_name)
{
$fp=fopen($zip_name,"wb");
fwrite($fp,$content);
fclose($fp);
}
function download_it($content,$zip_name)
{
header("Content-type: application/octet-stream name=$zip_name");
header("Content-disposition: attachment; filename=$zip_name");
echo $content;
}
$files=get_files($dir);
$names=$files;
$zip_content=pack_it($dir,$files,$names);
download_it($zip_content,$zip_name);
?>
|
Veselý Jan
|