[addon file-downloader] File Downloader
- Honza Kuchař
- Člen | 1662
Mám pocit, že to fungovat nebude. Protože před spuštěním odesílání souborů se zavovalé sessions->commit(); či něco obdobného, což způsobí, že do session již nejde ukládat. Ale pomůže to v tom, že se nezablokuje načítání stránek vrámci session, tedy uživatel nezírám, půl hodiny, než se dostahuje soubor na prázdnou stránku.
- Honza Kuchař
- Člen | 1662
Po delší době nová featura! Po delší diskusi jsem přidal, podporu stahování souborů větších než 2GB (včetně segmentů). Ufff.
- Peetee
- Člen | 75
Ahoj,
doufám, že svou otázkou nebudu úplně mimo, ale pokouším se rozchodit FileDownloader na projektu na Nette 2.0dev, na PHP 5.3. Na stránce doplňku je napsáno, že je testován na Nette 0.9×. Pokoušel jsem se drobnýma úpravama rozchodit, ale zřejmě jsem to celé rozhodil, nemáš prosím k dispozici verzi pro 2.0dev?
- Honza Kuchař
- Člen | 1662
Myslím že s Nette 2.0 problém nebude. Ale bude to v namespaces, ale verzi s namespaces zatím nemám k dispozici…
- Peetee
- Člen | 75
Děkuju za rychlou odpověď. Pořád si s tím hraju, ale vypisuje mi to:
Argument 1 passed to FDTools::clearHeaders() must be an instance of IHTTPResponse, instance of Nette\Web\HttpResponse given, called in (…)
Čemuž moc nerozumím, protože Nette\Web\HttpRespons implementuje IHTTPResponse (API)
- Honza Kuchař
- Člen | 1662
No proč, ne třeba to někomu pomůže… ;) Jestli chceš, pošli mi to na mail v zipu. Dám to na server a dám odkaz do dokumentace. (posílám Ti mail, ať mi to můžeš poslat ;)
- drakul
- Člen | 37
Zdravím, po přechodu na nové namespace se mi objevila zajímavá chybka.
mime_content_type(): File or path not found ‚example.doc‘ .
Soubor je fyzicky přítomný na daném umístění (ověřeno i pomocí
$filedownload->sourceFile, který při změně názvu vyhodí chybu ‚File
not found at … atd.). Problém tedy hledám v oné fci která vyhazuje chybu
getMimeType() – konkrétně $mimeTmp =
mime_content_type($this->transferFileName) . Tady jsem se ale dostal do
slepé uličky. Pomohlo až přepsání na $mimeTmp =
mime_content_type($this->sourceFile) a ještě (řádku podtím)
eregi na if(Nette\Utils\Strings::match($mimeTmp,
'~[a-z\\-]\\/[a-z\\-]~‘));
Teď už vše funguje.
- Honza Kuchař
- Člen | 1662
Co myslíš tím druhým řádkem netuším. Ten první je opraven, vydán bugfix. (pro PHP 5.2)
- Honza Kuchař
- Člen | 1662
Já ti tedy nevím, odkud jsi to vykopíroval, ale string ereg se ve zdrojácích FileDownloaderu vůbe nevyskytuje. Zřejmě máš nějakou upravenout a starší verzi.
- drakul
- Člen | 37
Zdravím, tak jsem projel dostupné verze (/…jserver.net/ → stable verze i SVN verze) a v obou jsem to našel … FDTools.php → „if(eregi(‚^[a-z\\-]\\/[a-z\\-]$‘,$mime))“
- Honza Kuchař
- Člen | 1662
Já si nemohu pomoct, ale v SVN je tam metoda takto:
/**
* Checks if mime type is valid
* @param string $mime Mime-type
* @return bool
*/
static function isValidMimeType($mime) {
$mime = (string) $mime;
if (preg_match('/^[a-z\\-]*\\/[a-z\\-]*$/i', $mime))
return true;
else
return false;
}
A toto bylo opraveno už v revizi 32. (21.1.2010)
- Honza Kuchař
- Člen | 1662
Jak jsem to odeslal, také mě to praštilo do očí. :-) (opraveno)
Vydána stable verze 1.1.0.1: https://svn.mujserver.net:8443/…ags/1.1.0.1/
- Peetee
- Člen | 75
Ahoj, mám takový problém s FD, budu rád za každou radu.
Na jednom projektu jsem použil FD, na lokále se všechno zdálo v pořádku, ale po nahrání na ostrej server se mi při stahování většího souboru (152MB) začala zobrazovat výchozí zpráva prohlížeče, že adresu není možné najít. Zjistil jsem, že se ke stažení používá NativePHPDownloader a že mu došla paměť. Domnívám se, že řešením by bylo použít AdvanedDownloader, ale ten neprojde kontrolou kompatibility:
<?php
function isCompatible(FileDownload $file){
if(self::$checkEnvironmentSettings === true)
{
if(FDTools::setTimeLimit(0)!==true)
return false;
}
return true;
}
?>
Tuším, že to má něco dočinění s tím, že není možné nastavit dobu provádění skriptu. Proto bych se chtěl zeptat jak mám dále postupovat? Je možné použít FD i na této konfigurace servru? Je nějaká možnost, jak obejít limity dané hostingem? (používáme sdílený hosting)
(přiznám se, že nevím jakou používám verzi, ve všech souborech je
napsaný @version $Id$
, očekávám, že to bude verze větší
dostupná v 5.4.)
- Honza Kuchař
- Člen | 1662
(přiznám se, že nevím jakou používám verzi, ve všech souborech je napsaný @version $Id$, očekávám, že to bude verze větší dostupná v 5.4.)
:-) To je celkem jedno…
Upřímně řečeno, také nevím co s tím. Je to totiž souhra několika zvláštností. readfile měl v PHP 5.2 výjimku na omezení času i paměti. V PHP 5.3 se zdá, že ne.
Advanced downloader to samozřejmě řeší (umí i soubory nad 4GB). Pokud jsi tedy nucen použít NativePHPDownloader pokus se ho upravit. Například mě napadá použít místo readfile passthru. Řešení určitě nějaké bude, ale nejspíš bude třeba googlit.
Tedy shrnutí: to na co jsi narazil je omezení současné konfigurace. Pokud použiješ AdvancedDownloader, narazíš po chvíli na časový limit. Pokud použiješ NativePHPDownloader, narazíš na pamět. Ale třeba se pletu, zkus si přepsat ten test kompatibility a pořádně to otestuj. Třeba je to teď v PHPku jinak.
- Peetee
- Člen | 75
Děkuju za vyčerpávající odpověď. Zatím jsem to nevyřešil, popíšu aspoň na co jsem přišel (třeba se to bude někomu hodit). Rozdělil bych to do dvou částí – problém s pamětí a problém s časem.
- problém s pamětí:
Při použití NativePHPDownloader příkaz readfile vyvolá chybu s nedostatkem paměti. Příkaz se pokusí načíst CELÝ soubor do paměti(!) + nějaká paměť na režiji. Což nás dostane do nereálných požadavků na paměť. Informace o tom, že by tato nebo podobná fce v PHP 5.3 měla výjimku na paměť jsem nenašel.
- problém s časovým limitem:
Pokud jsem problém správně pochopil, tak při testu kompatibility se pokouší zrušit omezení na čas, což je samozřejmě na hostingu zakázáno. Pokud test kompatiblity vyřadím (bude vždy vracet TRUE), tak vše „funguje“ do okamžiku než to narazí na časový limit. Jinými slovy, třeba se soubor za těch 30s stáhne ;-) (v mém případě soubor asi 150M je úspěšnost asi 50%, což samozřejmě není řešení, jen poznámka pro zasmání)
Existuje samozřejmě více řešení – v diskuzích, kde se zmiňuje problém s nedostatkem paměti se často zmiňuje Apache modul X-SendFile.
Osobně jsem tento FileDownloader volil hlavně z důvodu autorizace stahování (soubor může stáhnout pouze oprávněná osoba) a širší statistiky nad stahováním (výborné je například záznam toho, že byl soubor stažen apod.) Ale tento problém by šlo (asi) provést i jinak – autorizaci klasicky přes PHP a soubor zabezpečený přihlášením přes .htaccess, tak aby PHP zaslalo přihlašovací údaje (zatím jsem nestudoval, nevím ani jak by to bylo s bezpečností apod).
Omlouvám se, nechci Ti spamovat vlákno tohoto super doplňku. Možná by stálo za to na stránce zmínit požadavky na hosting.
- Honza Kuchař
- Člen | 1662
Při použití NativePHPDownloader příkaz readfile vyvolá chybu s nedostatkem paměti. Příkaz se pokusí načíst CELÝ soubor do paměti(!) + nějaká paměť na režiji. Což nás dostane do nereálných požadavků na paměť. Informace o tom, že by tato nebo podobná fce v PHP 5.3 měla výjimku na paměť jsem nenašel.
To se právě v PHP 5.2 nedělo. Odeslalo se to postupně… (alespoň ma mém serveru) Ještě to teď může dělat output buffer, ale měl by být vypnutý… (viz NativePHPDownloader:61)
Existuje samozřejmě více řešení – v diskuzích, kde se zmiňuje problém s nedostatkem paměti se často zmiňuje Apache modul X-SendFile.
Toto je asi nejelegantnější řešení, ale vyžaduje to ten modul Apache.
Ale tento problém by šlo (asi) provést i jinak – autorizaci klasicky přes PHP a soubor zabezpečený přihlášením přes .htaccess, tak aby PHP zaslalo přihlašovací údaje (zatím jsem nestudoval, nevím ani jak by to bylo s bezpečností apod).
Musel bys ve své aplikaci používat pouze HTTP ověřování a jak to dát dohromady netuším.
Možná by stálo za to na stránce zmínit požadavky na hosting.
Dobrý nápad. ;-) Dokumentace je ještě z dob, kdy fungovalo to readfile.
- Peetee
- Člen | 75
Opět děkuji za vyčerpávající odpověď.
Při Tvé zmínce o NativePHPDownloader:61 jsem zjistil, že nepoužívám
aktuální verzi s ob_end_flush()
. Tak jsem začal experimentovat
s následujícím kódem z aktuální verze:
<?php
// Bugfix: when output buffer active, there is a problem with memory
// @see http://www.php.net/manual/en/function.readfile.php#81032
while (@ob_end_flush()); // @see example at http://php.net/manual/en/function.ob-end-flush.php
flush();
if(!readfile($file->sourceFile)) {
throw new InvalidStateException("PHP readfile() function failed!");
}
?>
V tomto případě to nevyvolá žádnou chybu a soubor se začne stahovat, bohužel se nedotáhne celý, stažený soubor má vždy jinou velikost. Proč se soubor nedotáhne celý si mi zjistit nepodařilo, do logu nepřibyla žádná chyba, konec staženého souboru neobsahuje nic srozumitelného.
Editoval Peetee (14. 5. 2011 15:31)
- Peetee
- Člen | 75
Ano, v logu není vůbec nic. (na ostrém servu, laděnka – zapnuté logování). Když budu hádat (hodně, hodně hádat), tak tuším, že readfile ten soubor načte a pošle na výstup, ale prohlížeč si ho nestihne stáhnout (proto se v PHP nestane žádná chyba, protože tam prostě všechno proběhne v pořádku), ale to je jen hádání.
BTW – zjistil jsem, že na hodně pomalém připojení se nestáhne ani
30MB (při aktuálním řešení). Přitom v původním řešení (bez
ob_end_flush
) to fungovalo na 100%. (do velikosti souboru, která
se vešla do paměti).
- Matúš Matula
- Člen | 257
ahoj, v subore BaseFileDownload.php
na riadku 469 mas
<?php
$cache["mime-types"] = parse_ini_file(dirname(__FILE__)."\\mime.ini");
?>
tie spatne lomitka frcia asi len na win?
zmenit na
<?php
$cache["mime-types"] = parse_ini_file(dirname(__FILE__)."/mime.ini");
?>
- Matúš Matula
- Člen | 257
:D OK, tak teda
<?php
$cache["mime-types"] = parse_ini_file(dirname(__FILE__). DIRECTORY_SEPARATOR . "mime.ini");
?>
ale dopredne lomitko je myslim akceptovane aj na win…
ci stale to je zle? :D
- Matúš Matula
- Člen | 257
Nasiel som chybku v overovani spravnosti mime type.
v metode FDTools::isValidMimeType
mas
<?php
preg_match('/^[a-z\\-]*\\/[a-z\\-]*$/i', $mime)
?>
ale mime type moze obsahovat aj +
, napr.
image/svg+xml
.
Inak je nutne zdvojovat lomitka? Upravil som to na
<?php
preg_match('/^[a-z\-]+\/[a-z\-\+]+$/i', $mime)
//resp. kratsie
preg_match('#^[-\w]+/[-\w\+]+$#i', $mime)
?>
- Matúš Matula
- Člen | 257
Tiez testujes v BaseFileDownload::getMimeType
regularom 2× to
iste
<?php
if(function_exists("mime_content_type")) {
$mimeTmp = mime_content_type($this->sourceFile);
if(preg_match('/^[a-z\\-]*\\/[a-z\\-]*$/i',$mimeTmp))
$mime = $mimeTmp;
if(FDTools::isValidMimeType($mime))
return $mime;
}
//staci
if(function_exists("mime_content_type")) {
$mimeTmp = mime_content_type($this->sourceFile);
if(FDTools::isValidMimeType($mimeTmp))
return $mimeTmp;
}
?>
- Honza Kuchař
- Člen | 1662
Opraveno. Děkuji moc za podnětné připomínky. Ať ti FileDownloader slouží! :-)
- voda
- Člen | 561
Ve skutečnosti toho mime type může obsahovat ještě o něco více (rfc4288). Viděl bych to asi takhle:
<?php
$regName = '[a-z0-9!#$&.+^_-]{1,127}';
preg_match("|^$regName/$regName$|i", $mime)
?>
Ty různé speciální znaky jsme asi v mime type ještě nepotkal, ale tečku už jsem viděl: „application/vnd.openxmlformats-officedocument.wordprocessingml.document“ :)
- Honza Kuchař
- Člen | 1662
Opět je to tam. :-) Když budeme takto pokračovat na FileDownloaderu, určitě to bude nejlepší utilitka svého druhu. :-) Díky moc!
- David Ďurika
- Člen | 328
pls nema to niekto prepisane na aktualeu nevrziu nette ? (zrusenie Environment, pridanie namespace atd…)
ja som to skusal ale nepodarilo sa mi to rozchodid… dik
Editoval achtan (5. 9. 2011 21:28)
- Honza Kuchař
- Člen | 1662
Potřeba se podívat, jak se liší ty dva interface. Pokud jsou stejné, tedy jen změna názvu, stačí změnit ten název i ve zdrojácích FileDownloaderu.
- MartinitCZ
- Člen | 580
Je tento addon ještě ve vývoji? Hází to chyby v podobě odeslaných hlaviček (Cannot set cookie after HTTP headers have been sent).
- Honza Kuchař
- Člen | 1662
ViPErCZ napsal(a):
achtan napsal(a):
pls nema to niekto prepisane na aktualeu nevrziu nette ? (zrusenie Environment, pridanie namespace atd…)
ja som to skusal ale nepodarilo sa mi to rozchodid… dik
Popřípadě jestli to je v plánu přepsat to podle DI a vyhodit statické Environment???
Ano je to v plánu, až přejdu sám se svými aplikacemi na Nette 2.0.
- romiix.org
- Člen | 343
Zdravím,
stiahol som si najnovšiu revíziu doplnku a je tam chyba.
V /FileDownloader/downloaders/BaseDownloader.php treba opraviť
namespaces v metódach setupCacheHeaders a
setupNonCacheHeaders z Environment na
\Nette\Environment.
- maslo
- Člen | 6
Zdravím, snažil jsem se dát dokupy FileDownloader pro nové Nette (hlavně doplněním namespaces), ale bohužel jsem neuspěl (v momentě kdy našel všechny třídy začal vyhazovat špatné hlavičky a tam mi došla trpělivost.. :D )
Nebyl náhodou někdo úspěšnější? Případně jak by se daly soubory stahovat bez použití FileDownloaderu? (Potřebuji jenom nastavit soubor a název, pod kterým se má odeslat klientovi..) Povedlo se mi vyřešit jenom poněkud volšácky:
<?php
public function actionDownload($s_id) {
//kontroly a výpisy z databáze
$r = $q->fetch()->toArray();
$file = UP_DIR.'/'.$r['file'];
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($r['original_name']).'"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header("Content-type: ".mime_content_type($file));
header('Content-Length: ' . filesize($file));
ob_clean();
flush();
readfile($file);
exit;
}
?>
- OscarHanzely
- Člen | 7
peace.and napsal(a):
ahoj,
tak jsem zkousel verzi z trunku (rev. 65) a zda se byt vse funkcni az na dve drobnosti :-) staci opravit chybne urceni namespace ve tride BaseDownloader na radku 83 a 94, kde misto Environment ma byt Nette\Environment
Tohle by mohlo byt fiznute cim drive, ono to totoiz nehlasi ani zadnou chybu, rovnou nedorazi u downloadu hlavicky prohlizeci a clovek netusi co se deje.