Verze ke stažení

Školení, která pořádám

Yuhů vyzývá, abychom svůj web dali k dispozici ke stažení, v diskusi kdosi dokonce zmiňuje přímo PHP triky.

Když si chci nějaký web stáhnout, tak osobně používám wget, ale zrovna u tohoto webu to není právě jednoduché (protože obsahuje spoustu balastních odkazů kvůli reakcím na diskusní příspěvky pro uživatele s vypnutým JavaScriptem), takže verzi pro stažení dávám pokusně k dispozici.

Generuje se on-line, takže je vždy aktuální. K vytvoření archivu využívám knihovnu Archive_Tar, ale nejsem s ní příliš spokojen, protože data zapisuje do souboru a já bych je potřeboval dávat přímo na výstup. Také jsem zatím nerozchodil kompresi archivu, takže se data díky zlib.output_compression komprimují jen při přenosu.

Pro archiv platí stejné omezení jako pro web, tedy: Publikované texty můžete přetiskovat pouze se svolením autora. Ať vám tato verze slouží, připomínky uvítám v diskusi.

<?php
include "./include/lib.inc.php";
include "./include/Tar.php";
header("Content-Type: application/x-tar");

register_shutdown_function(create_function('', 'unlink($GLOBALS["tempnam"]);'));
$tempnam = tempnam($_ENV["TEMP"], "tar");
$tar = new Archive_Tar($tempnam);
$tar->create(array("default.css", "favicon.ico", "logo.gif"));

// články
$archiv = "";
$result = mysql_query("SELECT *, UNIX_TIMESTAMP(publikovano) AS publikovano_ts FROM clanky WHERE publikovano <= CURDATE() ORDER BY publikovano DESC, id DESC");
while ($row = mysql_fetch_assoc($result)) {
    ob_start();
    page_header($row["nadpis"]);
    echo $row["zprava"];
    echo "<div class='podpis'>Jakub Vrána, " . date('j.n.Y', $row["publikovano_ts"]) . ", <a href='https://php.vrana.cz/$row[url].php'>on-line</a></div>\n";
    page_footer();
    $tar->addString("$row[url].html", ob_get_clean());
    $archiv .= "<tr><td align='right'>" . date('j.n.Y', $row["publikovano_ts"]) . "</td><td><a href='$row[url].html'><strong>" . htmlspecialchars($row["nadpis"]) . "</strong></a></td><td><a href='https://php.vrana.cz/$row[url].php'>on-line</a></td></tr>\n";
}
mysql_free_result($result);

// archiv
ob_start();
page_header("");
echo "<table cellspacing='0' cellpadding='3'>\n";
echo $archiv;
echo "</table>\n";
page_footer();
$tar->addString("index.html", ob_get_clean());

$tar->_Archive_Tar();
header("Content-Length: " . filesize($tempnam));
readfile($tempnam);
?>
Jakub Vrána, Ze zákulisí, 16.12.2005, diskuse: 18 (nové: 0)

Diskuse

Jan Rozehnal:

Dobré. Nemohl byste uveřejnit kód který ten archív generuje?

Tomik:

Také jsem čekal nějaký PHP trik, jak generovat z dynamických stránek, statický zabalený balíček... ;)

Určitě bych ho uvítal...

ikona Jakub Vrána OpenID:

Vystavil jsem to. Není to žádný univerzální postup, ale je to ušité na míru tomuto webu. Stránky pro off-line stažení je stejně vhodné trochu upravit (nezobrazovat formulář pro vložení příspěvku do diskuse, nenabízet vyhledávání, nezobrazovat nejnovější články, ...).

Tomik:

Mnohokrát děkuji, jdu studovat... ;)

Tibor:

PHP triky čítam už dlho a možnosť stiahnutia mi pomohla. Ďakujem.

ikona Jakub Vrána OpenID:

Zbavil jsem se závislosti na Archive_Tar a soubory nyní balím touto funkcí:

<?php
function tar_file($filename, $contents, $mtime)
{
    $s = pack("a100a8a8a8a12a12", $filename, 0, 0, 0, decoct(strlen($contents)), decoct($mtime));
    $checksum = 8*32; // space for checksum itself
    for ($i=0; $i < strlen($s); $i++) {
        $checksum += ord($s{$i});
    }
    $s .= sprintf("%06o", $checksum) . "\0 ";
    $s .= str_repeat("\0", 512 - strlen($s));
    $s .= $contents;
    if (strlen($contents) % 512) {
        $s .= str_repeat("\0", 512 - strlen($contents) % 512);
    }
    return $s;
}

// na konci vypsání patičky
echo pack("x512");
?>

Dodatečně mě napadlo, že místo vytváření dočasného souboru stačilo použít php://output, ale teď alespoň může být u souborů generovaných z databáze i správné datum vytvoření.

Pavel Z.:

Škoda, že tam také nejsou přibaleny komentáře. Vetšinou si v nich člověk celkem počte.

ikona Jakub Vrána OpenID:

OK, dal jsem to tam.

ikona Jakub Vrána OpenID:

Bohužel se mi nepodařilo rozchodit <?php fopen("compress.zlib://php://output", "wb"); ?> ani <?php gzopen("php://output", "wb"); ?>, takže jsem komprimaci nakonec vyřešil takto:

<?php
ini_set
("zlib.output_compression", false);
$print = gzencode($print);
header("Content-Type: application/x-gzip-compressed");
header("Content-Length: " . strlen($print));
echo
$print;
?>

Celý výstup se ukládá do proměnné a zkomprimuje se až na konci. Výhoda spočívá v tom, že je možné poslat velikost archivu, nevýhoda zase ve zbytečně veliké paměťové náročnosti.

Možná by bylo nejlepší data ukládat přeci jen do souboru, který by zároveň sloužil jako cache.

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL: Reakce na: Jakub Vrána

ikona jonik555:

nešlo by udělat nějaký script, kterým by se dal stáhnout celý web-pokud není řešený přes DB?? samozřejmě jen někt. typy souborů

ikona Jakub Vrána OpenID:

Třeba takhle:

<?php
$zip
= new ZipArchive;
$zip->open("web.zip", ZipArchive::OVERWRITE);
foreach (
glob("*") as $filename) {
    if (is_file($filename) && $filename != "web.zip") {
        $zip->addFile($filename, $filename);
    }
}
$zip->close();
header("Location: web.zip");
?>

Zamykání web.zip pro jednoduchost neřeším.

jonik:

a jak by to slo udelat na wz.cz? je tam akorat ZLIB a tohle tam bohuzel nefunguje...
Dekuju

Michael Fanta:

Ahoj mohl by mi někdo poradit jak udělat to aby se mi na stránce ukázaly náhledy na všechny obrázky co obsahuje archiv ?

ikona Jakub Vrána OpenID:


<?php
define
("SIRKA_NAHLEDU", 100);
define("VYSKA_NAHLEDU", 100);

$zip = new ZipArchive;
$zip->open($filename);
$sirka = ceil(sqrt($zip->numFiles));
$nahledy = imagecreatetruecolor(SIRKA_NAHLEDU * $sirka, VYSKA_NAHLEDU * ceil($zip->numFiles / $sirka));
for (
$i=0; $i < $zip->numFiles; $i++) {
    $stat = $zip->statIndex($i);
    $im = imagecreatefromjpeg("zip://" . dirname(__FILE__) . "/$filename#$stat[name]");
    imagecopyresampled($nahledy, $im, SIRKA_NAHLEDU * ($i % $sirka), VYSKA_NAHLEDU * floor($i / $sirka), 0, 0, SIRKA_NAHLEDU, VYSKA_NAHLEDU, imagesx($im), imagesy($im));
    imagedestroy($im);
}
?>

Předpokládá se, že všechny soubory v archivu jsou obrázky JPG. Vznikne jeden velký obrázek s náhledy, který lze zobrazit např. funkcí imagejpeg(). Tento obrázek je obvykle čtvercový, pokud bys preferoval pevnou šířku, stačí ji zadat do proměnné $sirka. Náhledy jsou zdeformované, to by se dalo vyřešit funkcí pro proporcionální zmenšení obrázků: http://php.vrana.cz/formaty-obrazku.php.

SodaE:

prosímtě Jakube kde seženu pesně tenhle class "ZipArchive" ?

ikona Jakub Vrána OpenID:

http://php.net/zip

Pavel:

Používám Vertrigo Server pod Windows a nevím, jak tam tu třídu ZipArchive zpřístupnit.

Zkoušel jsem stáhnout php_zip.dll, přidat jej do složky ext a v php.ini připsat extension=php_zip.dll. Jenže to nepomohlo.

Co přesně je potřeba udělat? Díky komukoliv za případnou pomoc.

SodaE:

a bez modulu by to asi nešlo že :(
avatar © 2005-2022 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.