[addon file-downloader] File Downloader

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Honza Kuchař
Člen | 1662
+
+1
-

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
+
0
-

Hledej UTF-8 BOM.

Honza Kuchař
Člen | 1662
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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)

Nox
Člen | 378
+
0
-

Jestli jsou tam správně ty namespacy, Nette\Web\HttpResponse neimplementuje IHttpResponse ale Nette\Web\IHttpResponse (nebo tak nějak, chápeš)

Editoval Nox (4. 4. 2011 19:03)

Honza Kuchař
Člen | 1662
+
0
-

Chápu to přesně. Podívej se sem a sem. A bude ti to jasné. Musíš připsat, do FDTools, že má vyžadovat Nette\Web\IHttpResponse ne IHttpResponse.

Případně by asi šlo použít projekt na automatické přidání use – AutoUse.

Peetee
Člen | 75
+
0
-

Děkuji za rady, už mi to funguje. Kdyby byl zájem, tak mohu zveřejnit svou verzi s doplněnými use…

Honza Kuchař
Člen | 1662
+
0
-

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
+
0
-

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
+
0
-

Co myslíš tím druhým řádkem netuším. Ten první je opraven, vydán bugfix. (pro PHP 5.2)

drakul
Člen | 37
+
0
-

Nu ta druhá část je tam proto, že eregi už je deprecated nebo ne ?

Honza Kuchař
Člen | 1662
+
0
-

Jo to je pravda, zítra na to mrknu.

Honza Kuchař
Člen | 1662
+
0
-

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
+
0
-

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
+
0
-

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)

hrach
Člen | 1834
+
+1
-

huh, když to vidím, nedá mi to, přoč tam není: return preg_match('/^[a-z\\-]*\\/[a-z\\-]*$/i', $mime);? :-)

Honza Kuchař
Člen | 1662
+
0
-

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/

iguana007
Člen | 970
+
0
-

Díky :) Jdu to zkusit, zrovna se mi to hodí ;)

Peetee
Člen | 75
+
0
-

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
+
0
-

(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
+
0
-

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.

  1. 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.

  1. 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
+
0
-

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
+
0
-

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)

Honza Kuchař
Člen | 1662
+
0
-

V logu nic není? (pri ladence v produkcnim rezimu)

Peetee
Člen | 75
+
0
-

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).

Honza Kuchař
Člen | 1662
+
0
-

A podařilo se ti to nasimulovat na lokálním PC? Při jaké konfiguraci?

Matúš Matula
Člen | 256
+
0
-

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");
?>
Honza Kuchař
Člen | 1662
+
0
-

To take neni uplne spravne… Zkus to lepe. ;-)

Matúš Matula
Člen | 256
+
0
-

: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

Honza Kuchař
Člen | 1662
+
0
-

Takhle je to správně. :-)

Opraveno v SVN

Matúš Matula
Člen | 256
+
0
-

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 | 256
+
0
-

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
+
0
-

Opraveno. Děkuji moc za podnětné připomínky. Ať ti FileDownloader slouží! :-)

voda
Člen | 561
+
0
-

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“ :)

Matúš Matula
Člen | 256
+
0
-

Fuu, to je riadny mime type :D Dik obom, FileDownloader je super Honzo! ;)

Honza Kuchař
Člen | 1662
+
0
-

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
+
0
-

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)

net-vor
Člen | 35
+
0
-

Taky se přidávám k achtan + pro aktuální Nette nefunguje, hlásí „Argument 1 passed to FDTools::clearHeaders() must be an instance of Nette\Web\IHttpResponse,
instance of Nette\Http\Response given“

Honza Kuchař
Člen | 1662
+
0
-

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.

ViPEr*CZ*
Člen | 809
+
0
-

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???

MartinitCZ
Člen | 580
+
0
-

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
+
0
-

Ano je stále udržován, však pro Nette verzi 0.9.x

Honza Kuchař
Člen | 1662
+
0
-

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
+
0
-

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 setupNonCacheHeadersEnvironment na \Nette\Environment.

maslo
Člen | 6
+
0
-

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;
}
?>
Matúš Matula
Člen | 256
+
0
-

Ahoj,

uz si nepamatam, ake som robil upravy, ale pouzivam toto

peace.and
Člen | 1
+
0
-

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

OscarHanzely
Člen | 7
+
0
-

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.