Jak udelat on-the-fly zip stream, aby fungoval s action
- drasha
- Člen | 10
Cau,
potreboval bych, aby mi ma aplikace na kliknuti vracela zip vybranych souboru. Doposud jsem to delal tak, ze jsem si vytvoril zip soubor a vratil ho pres FileResponse:
<?php
public function actionDownloadFiles()
{
$zip = new \ZipArchive();
$zip->open($zipPath, \ZipArchive::CREATE);
$zip->addFile(...);
$zip->close();
this->sendResponse(new Nette\Application\Responses\FileResponse($zipPath, 'file.zip'));
?>
Problem je, ze skript ceka dokud nedobehne $zip->close a pripadne, podle nastaveni php to timeoutuje. Chtel jsem proto, aby se to balilo prubezne a vysledek se posilal na vystup, jako zde.
Narazil jsem ale na to, ze nevim, jak presvedcit Nette, aby s tim fungovalo, tj. pokud nevratim nejakou Response, tak se action nechova jak action, ale hlasi mi to page not found.
Jakekoliv napady uvitam.
Diky,
Drasha
- Felix
- Nette Core | 1247
her-ur napsal(a):
Nejdriv nastav spravne hlavicky, pak posilej data na vystup a zavolej na konci akce presenteru:
<?php $this->terminate(); ?>
Takhle to pouzivam zreba pri generovani velkeho CSV souboru.
Imho lepsi nette-way je.
Udelat si FlyFileReponse
, ktera implementuje IResponse,
podobne jako FileResponse.
A tam si nastavis prislusne hlavicky pres response objekt. A zaroven to ukoncis.
V presenteru/controlu bude cisto a nemusis pouzivat
Presenter::terminate()
.
Napriklad takto:
public function handleDownload() {
$response = new FlyFileResponse($mycallback);
$this->sendResponse($response);
}
Editoval Felix (13. 5. 2016 13:27)
- Felix
- Nette Core | 1247
Parkrat uz jsem neco takoveho potreboval take, tak jsem to zkusil udelat do vlastniho addonu.
Mrkni na to, jestli ti to treba nepomuze.
FlyResponse & FlyFileResponse
- drasha
- Člen | 10
Ahoj,
znova jeste oteviram toto tema, protoze mi to stale nefunguje podle mych predstav. Nakonec jsem nevyuzil ten addon, ale muj kod je v principu to same (aspon myslim, php neni uplne ma nejsilnejsi parketa).
public function actionDownloadAllFiles()
{
// ... Kus vynechaneho kodu
foreach ($files as $name => $file)
{
if (!$file->isDir())
{
$filePath = $file->getRealPath();
$zipCommand .= '"' . $filePath . '"' . " ";
}
}
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="' . $downloadName . '.zip"');
$zipCommand = "zip -r -j - ";
$fp = popen($zipCommand, 'r');
$buffSize = 8192;
$buff = '';
while (!feof($fp))
{
$buff = fread($fp, $buffSize);
echo $buff;
}
pclose($fp);
$this->terminate();
}
Takto se mi soubor vytvari a stahuje uplne krasne, ale zasekne mi to php. Tj. veskere zpracovani php ceka, az se mi ten soubor dotaha. Netreba rikat, ze kdyz se takhle ma stahnout x giga, tak se to dost vlece. V podstate bych potreboval vedet, jak to udelat, aby se ten soubor stahoval nezavisle na fungovani zbytku aplikace.
Uvazoval jsem o tom, ze bych mel cgi skript, ktery by se staral jen o vytvareni a posilani tech zip souboru a nechal apache, at si to vyresi, jak to resi, kdyz stahuje velke soubory, ale vlastne nevim, jak to rozchodit v kontextu Nette. No a pak jsem si rekl, ze radsi nebudu vymyslet hovadiny a zeptam se vas, co s tim mate vetsi zkusenosti…
- norbe
- Backer | 405
Jde o to, že sessions se při nastartování zamkne a ostatní požadavky od toho samého člověka čekají, dokud nedojde k jejímu uvolnění (je to z toho důvodu, aby si ty požadavky vzájemně nepřepisovali data).
První věc co budeš mít v té metodě actionDownloadAllFiles
bude:
$this->session->close();
V $this->session
musíš mít
Nette\Http\Session
, to tam dostaneš například takto – https://doc.nette.org/…n/presenters#….