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

Diskuse ke stránce File Downloader


Ahoj, tak jsem vytvořil stránku v extras. Takže prosím svoje názory, postřehy, nápady a připomínky prosím pište sem. ;)

P.S.: Mám ještě dalších pár nápadů, jak to vylepšit. :)

Honza Kuchař
Člen | 1662
+
0
-

Poznámka: Toto téma je pokračování https://forum.nette.org/…vani-souboru

Jan Tvrdík
Nette guru | 2595
+
0
-

Trochu jsme nepochopil, proč k tak poměrně jednoduché stránce tvoříš ilustrační video. Myslím, že všechno je jasné i bez něj.

Honza Kuchař
Člen | 1662
+
0
-

Ok, mažu

jasir
Člen | 746
+
0
-

honzakuchar napsal(a):

Ok, mažu

Mně se líbí… :)

Editoval jasir (26. 6. 2009 14:22)

o5
Člen | 416
+
0
-

honzakuchar napsal(a):

Ok, mažu

To ze tady nekdo neco vykrikne, neznamena, ze toho nazoru jsou vsichni. Myslim, ze to byl i dokonce jako podmet k diskuzi (ikdyz nevybirave napsanej). Takze bych to tam vratil zpatky :D (to by bylo, kdyby vsechny extras mely video ;)

jasir
Člen | 746
+
0
-

To ze tady nekdo neco vykrikne, neznamena, ze toho nazoru jsou vsichni. Myslim, ze to byl i dokonce jako podmet k diskuzi (ikdyz nevybirave napsanej). Takze bych to tam vratil zpatky :D (to by bylo, kdyby vsechny extras mely video ;)

Nóó, viď, to by bylo prima :)

Ondřej Brejla
Člen | 746
+
0
-

Zvlášť u takových Helperů by to mělo vysokou informační hodnotu :-D

michalh
Člen | 22
+
0
-

Já bych zavedl povinné demo u každé položky v extras a pokud to pomůže v přehlednosti tak i krátké video.

Edit Pro Davida: šla by udělat nějaká konvence, aby všechny dema v extras byly na nette.org?

Editoval michalh (26. 6. 2009 14:17)

PetrP
Člen | 587
+
0
-

michalh napsal(a):

Edit Pro Davida: šla by udělat nějaká konvence, aby všechny dema v extras byly na nette.org?

David už někde psal že by to bylo zbytečně složité (nebo tak ňák) a že bude jednoduší když si live dema budem dávat na svoje hostingy, které stejně všichni máme, ne?

Honza Kuchař
Člen | 1662
+
0
-

Takže k tomu videu: vrátil jsem ho zpět. Pravda informační hodnotu (zatím) nemá, ale připravím nové, kde už nějakou bude mít (jak se chová readfile a FileDownloader). (už mám skoro hotovou další verzi, která je kompletně překopaná – lépe logicky členěná a více jsem se snažil dodržovat coding-standard) nová verze bude členěná podobně jako třída Mail v nette. (tzn. zde budou Downloadery atd.)

Honza Kuchař
Člen | 1662
+
0
-

Takže ukázka z verze 1.0.0 beta. Dneska ji dám do repozitáře ke stažení.

Co se změnilo:

– Prakticky vše – kompletně přepsáno
 – Opraveny nesmysly v názvech proměnných a metod (intuitivnější)
 – Modulární systém (FileDownload,IDownloader a tzv. downloadery)
 – Callbacky (BeforeDownloaderStarts; BeforeOutputStarts; StatusChange; Complete; ConnectionError; Abort; TransferContinue)
 – Plně fluentní prostředí
 – Vylepšená autodetekce mime-typu (když se zavolá setMimeType poté se použije nastavený, jinak se provede autodetekce)
 – Podpora pro defaults (viz ukázka bod 2)

Ukázka

  1. (volitelně) Zaregistrujeme downloadery – tyhle dva jsou zaregistrovány už ve FileDownload.php
FileDownload::registerFileDownloader(new NativePHPDownloader);
FileDownload::registerFileDownloader(new AdvancedDownloader);

Můžete si zaregistrovat svoje další downloadery (nejvyšší prioritu má ten poslední) nebo registraci zrušit pomocí:

FileDownload::clearFileDownloaders();
  1. (volitelně) Nastavíme výchozí hodnoty
FileDownload::$defaults["speedLimit"] = 10*FDTools::KILOBYTE;
  1. Pošleme soubor klientovi
    1. Fluentně
$file = FileDownload::getInstance()
->setSourceFile(dirname(__FILE__)."/temp/test-64MB.tmp")
->setTransferFileName("test ščř ščř ščř ščř.php")
->setSpeedLimit(5*FDTools::MEGABYTE)
->addBeforeDownloaderStartsCallback("onBeforeDownloaderStarts")
/* ... */
->download();

b) klasicky

$file = new FileDownload;
$file->sourceFile = dirname(__FILE__)."/temp/test-64MB.tmp";
$file->transferFileName = "test ščř ščř ščř ščř.php";
$file->speedLimit = 5*FDTools::MEGABYTE;
$file->onBeforeOutputStarts[] = "onBeforeOutputStarts";
/* ... */
$file->download();
Honza Kuchař
Člen | 1662
+
0
-

Ukázka callbacků (log) – 256MB soubor:

1. spojení – pozastaveno

onBeforeDownloaderStarts
onBeforeOutputStarts
onNewTransferStart
onStatusChange: 5242880bytes transferred
onStatusChange: 10485760bytes transferred
...
onStatusChange: 99614720bytes transferred
onStatusChange: 104857600bytes transferred
onConnectionError
onAbort

2. spojení pokračování

onBeforeDownloaderStarts
onBeforeOutputStarts
onTransferContinue
onStatusChange: 23068672bytes transferred
...
onStatusChange: 145096704bytes transferred
onComplete

Editoval honzakuchar (29. 6. 2009 10:53)

Honza Kuchař
Člen | 1662
+
0
-

Tak verze 1.0.0 beta1 je v repozitáři. Tak testujte :)

Lopo
Člen | 277
+
0
-

Call-time pass-by-reference has been deprecated in /home/…/app/extras/FileDownloader.php on line 362

@version $Id: FileDownloader.php 13 2009–06–25 16:35:50Z
PHP 5.2.10, Nette 0.9/398 nonprefix

pre istotu idem odskusat poslednu SVN verziu …

takze posledna SVN stable verzia:
Warning: Call-time pass-by-reference has been deprecated in /home/…/app/extras/FileDownload.php on line 476

Editoval Lopo (2. 7. 2009 14:55)

Honza Kuchař
Člen | 1662
+
0
-

Mě si sice tahle chybka neprojevuje. Nicméně, zkus na tom řádku 362 změnit ty parametry fuknce bez toho &. tzn:

self::_parseRangeHeader($req, $res, $req->getHeader("Range"), $size, $start, $end, $length);

//EDIT: Když vezmeš verzi z /trunk tak by se ta chyba neměla projevovat vůbec. (rev. 22)

P.S.: Na Mozille 3.5 nefunguje zapauzování stahování. Na opravě se už pracuje.

Editoval honzakuchar (3. 7. 2009 23:49)

sodae
Nette Evangelist | 250
+
0
-

Zdarec

Na řádku 35 ve examples/example_library.php ze vyskytuje chybka s Division by zero, dělá to u download manažerů (flashget).

Jinak dobrá práce ;-)

Editoval sodae (7. 7. 2009 11:04)

Honza Kuchař
Člen | 1662
+
0
-

Vydána verze 1.0.0 RC1.

Opraveny výše zmíněné bugy. (Firefox 3.5 a dělení nulou)

Pozámka: příklad form velmi zatěžuje CPU serveru – ukládá do cache všechny volané callbacky a poté je zase vypisuje. Přidám tam v další rev. zaškrtávací políčko na vypnutí logování. (edit: už je to tam: rev. 27)

//EDIT: + nové příklady

Editoval honzakuchar (13. 7. 2009 13:30)

Honza Kuchař
Člen | 1662
+
0
-

Už je zaktualizovaná dokumentace File Downloaderu. Vytvořil jsem nové video.

kutilm
Člen | 21
+
0
-

Ahoj,
rád bych downloader použil pro posílání obrázků (ale nejen jich) do prohlížeče, tak aby se zobrazili přímo v okně prohlížeče. Momentálně to řeším vlastním downloaderem:

<?php
class MyDownloader extends AdvancedDownloader
{
  protected function sendStandardFileHeaders(FileDownload $file,BaseDownloader $downloader=null)
  {
    parent::sendStandardFileHeaders($file,$downloader);
    $res = Environment::getHttpResponse();
    $res->setHeader('Content-Disposition', 'inline; filename="'.FDTools::getContentDispositionHeaderData($file->transferFileName).'"');
  }
}
?>

Ale možná by se to dalo elegantněji řešit přímo na úrovni FileDownload? A kdyby ne, tak se třeba někomu hodí ten downloader:)

Jinak děkuji
Michal

Honza Kuchař
Člen | 1662
+
0
-

Jsem rád, že to někdo používá. :) Nicméně vlastní downloader není potřeba, stačí si tu potřebnou hlavičku přepsat v callbacku. Sice jsem to nezkoušel, ale neměl by být problém přepsat si hlavičky v callbacku onBeforeOutputStarts nebo onBeforeDownloaderStarts(zde se nastavené hlavičky znova přepsaly hlavičkami downloaderu).

$download = new FileDownload;
$download->onBeforeOutputStarts[] = "mojeHlavicky";
function mojeHlavicky(FileDownload $download,IDownloader $downloader){
    Environment::getHttpResponse()->setHeader('Content-Disposition', 'inline; filename="'.FDTools::getContentDispositionHeaderData($download->transferFileName).'"');
}

Editoval honzakuchar (18. 7. 2009 19:50)

kutilm
Člen | 21
+
0
-

Ahoj,
ty callbacky jsem zkoušel, ale nějak jsem s v nich zaplet:), tak jsem to řešil tím vlastním downloaderem. Nicméně jsem si s tím teď ještě trochu pohrál a opravdu to funguje, ale jen v onBeforeOutputStarts.

Ještě jednou dík
Michal

Honza Kuchař
Člen | 1662
+
0
-

Ano díval jsem se do kódu a opravdu je to tak. Omlouvám se za zmatek.

//EDIT: zkusím na tohle vytvořit nějakou zkratku ;)

Editoval honzakuchar (18. 7. 2009 19:51)

theo
Člen | 57
+
0
-

Hlásím chybu v souboru FileDownload.php na radku 426. Je tam

if(!IsSet($cache["mime-types"])) {

což z nějakého ne zcela jasného důvodu vrací FALSE i když $cache['mime-types'] není nastavena. Řešením je použít

if(empty($cache["mime-types"])) {

což vrací správný stav.

David Grudl
Nette Core | 8218
+
0
-

Možná by bylo zajímavé zkusit File Downloader upravit do podoby IPresenterResponse. Jde o úplnou novinku, jako ukázka velmi primitovního downloaderu by mohlo posloužit tohle.

Honza Kuchař
Člen | 1662
+
0
-

Podívám se na to. (asi ne uplně hned – škola) ;) Vypadá to výborně.

Honza Kuchař
Člen | 1662
+
0
-

Když se podíváte do SVN, tak FileDownloader už umí IPresenterResponse. Použití je téměř stejné. (z examples/MVP)

		$fileDownload = new AppFileDownload($this);
		$fileDownload->sourceFile = __FILE__;
		$fileDownload->speedLimit = 5*FDTools::BYTE;
		$fileDownload->download();

nebo

		AppFileDownload::getInstance($this)
		->setSourceFile(__FILE__)
		->setSpeedLimit(5*FDTools::BYTE)
		->download();

nebo

		$fileDownload = new AppFileDownload($this);
		$fileDownload->sourceFile = __FILE__;
		$fileDownload->speedLimit = 5*FDTools::BYTE;
		$this->terminate($fileDownload);

Metoda download() volá Presenter::terminate(), takže aplikace které používají FileDownloader budou nyní podstatně lépe testovatelné.

Dále: opraveno pár bugů, které souvisí s přechodem na PHP 5.3

musa
Člen | 28
+
0
-

Díky za pěknou komponentu. Při použití s aktuálním Nette 0.9.3 / PHP 5.2 je problém s voláním metody sendStandardFileHeaders kde se používá $downloader->getClass(). Pokud na to někdo narazí také tak stačí vyměnit za get_class($downloader).

Honza Kuchař
Člen | 1662
+
0
-

Díky za upozornění. S aktuální verzí Nette FileDownloader nemám nikde spuštěný.

Honza Kuchař
Člen | 1662
+
0
-

Oprava je na SVN.

Aurielle
Člen | 1281
+
0
-

Nevím zda už to není opraveno, ale ve stable verzi (ze zipu) dělá na PHP 5.3 bordel eregi (deprecated), pak jeden warning u mime_content_type (když neexistuje transferFileName). A jak už bylo zmíněno tak deprecated getClass();

Poznámka – ve Firefoxu 3.6 se mi poslední chyba (deprecated getClass()) nechtěla ukázat, Firefox tvrdil že soubor byl nenalezen a hlavičky požadavku vracely 500. V IE byla chyba v Laděnce vidět.

Honza Kuchař
Člen | 1662
+
0
-

Stable verze je verze 1.0 na SVN je verze 1.1-rc, která už má podporu pro PHP 5.3. Je to verze RC. Ale nazval bych ji už stabilní. (dlouhodobě není žádná hlášená chyba)

Editoval honzakuchar (11. 4. 2010 13:30)

hrtlik
Člen | 7
+
0
-

Tak hlásím chybu :)
Nastavení diakritiky u stahovaného souboru nefunguje na 100% ve všech prohlížečích, teda alespoň ne u té ukázky:

  • Opera 10.60 – znaky s diakritikou jsou vynechány
  • IE8 – bordel
  • Safari – OK
  • Chrome – OK
  • Firefox – OK

Editoval hrtlik (24. 8. 2010 17:36)

Honza Kuchař
Člen | 1662
+
0
-

nemáš chuť si s tím zkusit pohrát? :)

Honza Kuchař
Člen | 1662
+
0
-

Možná by i stačilo, kdyby se ti podařil sehnat nějaký příklad (jakýkoli soubor kdekoli na internetu), kde to funguje korektně, odchytili bychom hlavičky a viděli bychom co a jak.

hrtlik
Člen | 7
+
0
-

Tak vyřešeno s IE. Opravený kód v FDTools: http://pastebin.com/FLKKkGDs . Je tam přidáno urlencode.
Opera nakonec háčky a čárky uměla, ale v tom příkladu je ukázka se složenými závorkami a z nějakého důvodu to vynechá, nedokázal jsem to vygůglit.

Editoval hrtlik (1. 9. 2010 20:26)

Honza Kuchař
Člen | 1662
+
0
-

Zahrnu to do distribuce, hned jak budu mít chvilku to otestovat. ;) Je to tam. Děkuji moc za spolupráci, jménem celé Nette komunity!

Editoval Honza Kuchař (2. 9. 2010 8:33)

Ondřej Kubíček
Člen | 494
+
0
-

zdravím,
díky za file downloader, ale mam problem jej rozchodit. Stáhl jsem si z svn nejnovější verzi (1.1.0rc) a firefox stále píše soubor nemůže nálezt. V podstatě jak píše gmvasek. Jak to vyřešit? Používám PHP 5.3 a nette ve verzi 1.

Honza Kuchař
Člen | 1662
+
0
-

Zkuste si s tím prosím trošku pohrát, oprava je vítána.

Jendaaa
Člen | 21
+
0
-

Zdravím,
můžete mi prosím někdo vysvětlit, v čem dělám chybu? Kód je následující

<?php
...
	public function download() {
		\FileDownload::getInstance()
			->setSourceFile($file)
			->addCompleteCallback('complete')
			->download();

	}

	public function complete(\FileDownload $download,\IDownloader $downloader)
	{
		 Environment::getSession('key')->downloaded = true;

	}
?>

problém je v tom, že callback se vůbec nevolá, protože session downloaded se nezmění. Přitom soubor se v pořádku stáhne.
Díky

redhead
Člen | 1313
+
0
-

Protože musíš specifikovat, kde se to má volat. Tvůj příklad by volal globální funkci, nikoli metodu objektu.

Nevím jak je to tam přesně řešené, ale zkus:

->addCompleteCallback($this, 'complete')
//nebo
->addCompleteCallback(callback($this, 'complete'))

Spíš asi to druhý..

Editoval redhead (13. 12. 2010 21:22)

Jendaaa
Člen | 21
+
0
-

redhead napsal(a):

Protože musíš specifikovat, kde se to má volat. Tvůj příklad by volal globální funkci, nikoli metodu objektu.

Nevím jak je to tam přesně řešené, ale zkus:

->addCompleteCallback($this, 'complete')
//nebo
->addCompleteCallback(callback($this, 'complete'))

Spíš asi to druhý..

Zkusil jsem oboje, bez úspěchu.

Mikulas Dite
Člen | 756
+
0
-

https://componette.org/search/?…:

Tzn. callbacky registrujeme buť onCallback[] = callback;

Zkontroluj, jesli registruješ validní callback (pokuď používáš array()). Jestli tam píšeš callback(), tak se buď nezavolá, protože je v addonu chyba, nebo proto, že se zavolat nemá – zavolá se něco jiného, třeba onConnectionLost místo onAbort nebo něco podobného.

Zkus svůj callback jinde, třeba na BeforeDownloaderStarts – jestli se tvůj callback zpustí, je chyba v triggeru.

Editoval Mikulas Dite (13. 12. 2010 22:08)

Jendaaa
Člen | 21
+
0
-

Mikulas Dite napsal(a):

https://componette.org/search/?…:

Tzn. callbacky registrujeme buť onCallback[] = callback;

Zkontroluj, jesli registruješ validní callback (pokuď používáš array()). Jestli tam píšeš callback(), tak se buď nezavolá, protože je v addonu chyba, nebo proto, že se zavolat nemá – zavolá se něco jiného, třeba onConnectionLost místo onAbort nebo něco podobného.

Zkus svůj callback jinde, třeba na BeforeDownloaderStarts – jestli se tvůj callback zpustí, je chyba v triggeru.

EDIT: Vyřešeno, zapomněl jsem na ten array()

Tak jsem zkusil zaregistrovat BeforeDownloaderStarts, ten už se spustí, ale laděnka mi hlásí: Callback ‚complete‘ is not callable. Takže u onComplete byla asi stejná chyba, která akorát kvůli odeslaným hlavičkám nebyla zobrazená…Teď akorát proč to nejde volat?

Editoval Jendaaa (17. 12. 2010 10:23)

JohnyK
Člen | 2
+
0
-

Zdravím, zdá se že mám stejný problém jako Jendaaa.

Callback na BeforeDownloaderStarts funguje, ale na Complete nikoli.
Pokud se někomu podařilo zavolat callback na Complete, poraďte prosím jak.
Nevím si s tím rady. Potřebuji po stažení smazat dočasný soubor z disku.

Honza Kuchař
Člen | 1662
+
0
-

Callback complete, pokud se správně pamatuji, funguje pouze u driveru Advanced. Ale musím to ověřit. Píšu si to do diáře.

Ale pozor! Complete je jen pokud proběhne úspěšné stažení. Doporučuji se podívat na příklad v distribuci „form“. Kde se ukazjí volané callbacky.

Bude to vypadat přibližně takto, pokud se přeruší spojení – tedy žádný complete se nezavolá. Je to očekávané chování.

Con. #1294142943-5224 (Aborted)

5: onAbort: 50 B <->; position: 100 B; http-range: 0 B-8 MB; progress (con: 0% X file: 0%)
4: onConnectionLost: 50 B <->; position: 100 B; http-range: 0 B-8 MB; progress (con: 0% X file: 0%)
3: onStatusChange: 50 B <->; position: 50 B; http-range: 0 B-8 MB; progress (con: 0% X file: 0%)
2: onNewTransferStart: 0 B <->; position: 0 B; http-range: 0 B-8 MB; progress (con: 0% X file: 0%)
1: onBeforeOutputStarts: 0 B <->; position: 0 B; http-range: 0 B-8 MB; progress (con: 0% X file: 0%)
0: onBeforeDownloaderStarts: 0 B <->;
JohnyK
Člen | 2
+
0
-

Díky za rychlou odpověď.
Po nějaké době co jsem s tím bojoval, se mi to nakonec podařilo.
:) uff

Honza Kuchař
Člen | 1662
+
0
-

Docela by mě zajímalo, kde byla chyba. Ale s tím complete je to tedy dobrý návrh. Protože by se mně samotnému líbil návrh toho, jak je to s jQuery, tedy

**success**  = úspěšně dokončeno
**complete** = dokončeno jakkoli
**error**    = chyba

…ale byl by to docela dost nepříjemný BC break, jste pro ho provést? (až bude alespoň 10 lidí pro nebo proti vynesu nějaký rozsudek, jak se tato věc bude mít dál)

Honza Kuchař
Člen | 1662
+
0
-
  1. Neměl by to být problém
  2. nesouvisí to s FileDownloaderem, ale s routováním

Routa by měla vypadat nějak takto:

new Route("<presenter downloads>/file/<fileId [0-9]>",array(
	"action" => "download"
));

Ale je dost možné, že je to úplná blbost.

klimax
Člen | 7
+
0
-

jde nějakým způsobem uživatele informovat o tom, že se probehl nějaký callback, tedy že spadlo stahování, stahování se úspěšně provedlo, atd.?
nic, co je po

<?php
$filedownload->download();
?>

se již neprovede a v callbackach sice mam flashmessage, ale ty se neprovedou

<?php
public function onFileDownloadAbort(FileDownload $download, IDownloader $downloader) {
        $this->flashMessage('Bylo přerušeno stahování souboru', 'error');
    }
?>

provede se napriklad ulozeni informaci do DB, ale rad bych prave flashmessagi uzivatele informoval.