[addon multiplefileupload] MultipleFileUpload – form control

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 MultipleFileUpload – form control


Ahoj, už mám skorou hotový tento MultipleFileUpload s jQuery. Ale řeším takový menší problémek:

Nahraji soubory na server pomocí uploadify. Uložím je do tempů. Uživatel stránku opustí. → soubory zůstanou v tempech dokud je něco ručně neodstraní. Napadá Vás nějaké elegantní řešení jak tohle vyřešit? Napadlo mě to řešit tak, že si vytvořím v cache nějaké pole se všemi soubory a ty co budou straší než něco, tak by se odmazaly. (asi by to bylo navěšeno na event onShutdown)

Honza Marek
Člen | 1664
+
0
-

Já bych je dal do cache s časovým omezením. Tam je ale zas problém, kdyby někdo chtěl ručně smazat keš, může někomu zrušit právě uploadnuté soubory.

Honza Kuchař
Člen | 1662
+
0
-

To ano, ale ukládat do cache přímo binární data které můžou mít třeba 1 GB? To asi nepůjde. :(

Honza Marek
Člen | 1664
+
0
-

Jako dohromady 1 GB myslíš? Nevim přesně jak cache funguje a jestli by to teda vadilo…

Každopádně taky místo onShutDown můžeš promazání tempu zavolat před nahráním nového souboru. Vždycky tam pak zůstanou soubory maximálně od jednoho uživatele.

paranoiq
Člen | 392
+
0
-

@honzakuchar: co myslíš tím „Uživatel stránku opustí“?
není řešením tohle?:

ignore_user_abort() http://cz2.php.net/…er-abort.php

connection_aborted() http://cz2.php.net/…-aborted.php

Editoval paranoiq (19. 8. 2009 19:04)

Honza Kuchař
Člen | 1662
+
0
-

paranoiq: Není, o tom vím. Když odesíláš přes uploadify musíš použít takovou okliku. Každý soubor se odešle vlastním vláknem a potom se nakonec odešle formulář.

Honza M.: Pokud vím, tak do cache můžu uložit cokoliv co jsem serializovat (tzn. string, objekt a tak). Ale já dostanu od klienta soubory. Mám jich 20 a každý z nich má 500MB. Kdybych je chtěl uložit do cache, tak bych je musel celé načíst do paměti a předat cache ne?


Jak se tak dívám, tak to co potřebuji ani není tak úloha pro cache, ale spíš pro nějaké dočasné uložiště. Ještě zkusím něco vymyslet.


Komu nebo čemu vděčím za ten titul? :)

jasir
Člen | 746
+
0
-

honzakuchar napsal(a):

Komu nebo čemu vděčím za ten titul? :)

Jseš prostě dobrej… ;-) 200 příspěvků…

Honza Marek
Člen | 1664
+
0
-

My normální smrtelníci umíme přes formulář nahrávat soubor do 2 MB :) Uploadify to snad umí obelstít?

A že by někdo nahrával přes formulář 20 × 500 MB, to bych se divil i kdyby to šlo.

kravčo
Člen | 721
+
0
-

Honza M. napsal(a):

My normální smrtelníci umíme přes formulář nahrávat soubor do 2 MB :) Uploadify to snad umí obelstít?

A že by někdo nahrával přes formulář 20 × 500 MB, to bych se divil i kdyby to šlo.

Všetko záleží na nastavení PHP :)

Honza Kuchař
Člen | 1662
+
0
-

Všetko záleží na nastavení PHP :)

Přesně tak u našich ve firmě (mají grafické studio) se běžně posílají soubory kole ~200MB. A limit je 1024MB :)

Ale k tomu obejití omezení. Umí to velice elegatně Google Gears. (nezkoušel jsem to, ale mělo by to z principu fungovat) Prostě soubor rozseká na kousky a předá ty kousky JavaScriptu a ten je jeden po druhém odešle. V php se to potom zase slepí dohromady.

Honza Kuchař
Člen | 1662
+
0
-

Tak už je krátičká dokumentace a je ke stažení taková jakási první release.

Toto rozšíření je zatím dost experimentální!

JavaScriptová validace: už mám nápad jak na to – bude.
Thread-safe: už mám taky nápad jak na to – bude.
Vytvoření ověřovacího tokenu už při vytváření políčka. Tento token potom oveřovat u každého odeslaného souboru. Zatím (provizorně) se vygeneruje náhodné číslo, které se potom pošle přes uplodify a to podle něho vytvoří / přidá na seznam uploadovaný soubor.

Doufám, že jsem v tom ZIPu na nic nezapomněl.

Honza Kuchař
Člen | 1662
+
0
-

Ještě taková ukázka. Exendovaná verze (MultipleFileUploadEditable). Veřejný repozitář založím hned potom co udělám todo.

Editovatelný se myslí, že do toho políčka naházíte soubory, které už máte na server a přidáte sinály na mazání případně na cokoliv dalšího co vás napadne. Výhoda: je to všechno pohoromadě na jednom místě. (i na stránce)

cuga
Člen | 210
+
0
-

cauko, jak to vypada s nejakym tim demem??? mam trosku problem v tom, ze nevim co vsechno zahrnout a ktery ten css styl pridat :)

Honza Kuchař
Člen | 1662
+
0
-

demo udělám snad ještě dnes. ;)

cuga
Člen | 210
+
0
-

tisicere diky ;)))

Honza Kuchař
Člen | 1662
+
0
-

Ale opravdu zatím moc nedoporučuji nasazení do ostrého provozu! Předpokládám, že se bude vyskytovat asi dost bugů.

cuga
Člen | 210
+
0
-

to az tak nevadi, o ostry provoz zatim nejde :)

Honza Kuchař
Člen | 1662
+
0
-

Máš to tam.

Ondřej Mirtes
Člen | 1536
+
0
-

Jak můžu oddebugovat, když mi ta komponenta na konci uploadování souboru (těsně před odesláním – reloadnutím stránky) zahlásí HTTP error? Ve firebugu se nic neukáže.

A po odeslání formu mi PHP háže warning, že soubor k přesunutí (někde v tempu) už neexistuje. Takže se prostě neuploaduje úspěšně.

Editoval LastHunter (14. 9. 2009 19:45)

Honza Kuchař
Člen | 1662
+
0
-

Mno na debugování na straně serveru xdebug. Na debugování na straně klienta (používá to flash) nic nemám.

Příklad přímo na webu ti funguje?

A po odeslání formu mi PHP háže warning, že soubor k přesunutí (někde v tempu) už neexistuje. Takže se prostě neuploaduje úspěšně.

Používáš poslední revizi Nette? (je vyžadováno Nette d52a529ab0e68a684ce7d0434a97b4165f2ba98b nebo vyšší)

Ondřej Mirtes
Člen | 1536
+
0
-

Příklad na webu funguje, revizi Nette jsem dnes kvůli tomu updatoval.

Tak to asi může být leda ve špatném pořadí skriptů/něčemu chybějícímu v hlavičce. Mám tam tohle:

<script type="text/javascript" src="{$baseUri}js/jquery.js"></script>
<script type="text/javascript" src="{$baseUri}js/jq-ui.js"></script>
<script type="text/javascript" src="{$baseUri}js/my.js"></script> <!-- obsahuje nette.ajax -->
<script type="text/JavaScript" src="{$baseUri}js/nette-ajax-form.js"></script>
<script type="text/JavaScript" src="{$baseUri}js/jquery.livequery.js"></script>
<script type="text/JavaScript" src="{$baseUri}js/swfobject.js"></script>
<script type="text/JavaScript" src="{$baseUri}js/jquery.uploadify.js"></script>
<script type="text/JavaScript" src="{$baseUri}js/MultipleFileUpload.js"></script>

A dle Firebugu se všechny tyhle soubory i načtou.

Problém možná bude v nějaké odpovědi od serveru, když je to HTTP error.

Továrnička a obsluhující událost:

	protected function createComponentMassImportForm() {
		$form = new BaseForm;
		$form->getElementPrototype()->class[] = "ajax";
		$form->addSelect('gallery', 'Gallery', $this['galleryModel']->getGalleries()->orderBy('time', 'DESC')->fetchPairs('id', 'name'))
			->addRule(Form::FILLED, 'Select the gallery!')
			->skipFirst('Select the gallery');

		$form->addMultipleFileUpload("images","Image upload",20)
			->addRule("MultipleFileUpload::validateFilled","Musíte odeslat alespoň jeden soubor!");

		$form->onSubmit[] = array($this, 'massImportFormSubmitted');

		$form->addSubmit('okSubmit', 'Send');

		return $form;
	}

	public function massImportFormSubmitted(BaseForm $form) {
		try {
			$values = $form->getValues();
			$this['galleryModel']->massImport($values['gallery'], $values['images']);
			$this->flashMessage('Photos successfully imported!');
			//$this->redirect('Gallery:');
		} catch(IOException $e) {
			$form->addError($e->getMessage());
		}
	}

Metoda modelu:

	public function massImport($gallery, $images) {
		foreach($images as $image) {
			if (!$image->getError() == UPLOAD_ERR_NO_FILE && !$image->isOk())
				throw new IOException('Error occured while uploading the file.');

			if ($image->getContentType() != 'image/jpeg' && $image->getContentType() != 'image/pjpeg' || $image->getContentType() != 'image/jpg') {
				throw new IOException('Unsupported image type.');
			}

			if ($image->isOk()) {
				$galleryName = $this->db->fetchSingle('SELECT name FROM [::'. self::GALLERIES_TABLE . '] WHERE id=%i', $gallery);

				$this->db->query('INSERT INTO [::'. self::PHOTOS_TABLE . ']', array(
					'gallery_id' => $gallery,
					'title' => $galleryName,
					'description' => NULL,
				));

				$image->move($this->getImagePath($this->db->insertId()));
			}
		}
	}

Editoval LastHunter (15. 9. 2009 0:13)

Ondřej Mirtes
Člen | 1536
+
0
-

Když vypnu v prohlížeči javascript, tak se mi nahoře na stránce objeví tento warning:

Warning: rename(C:\Windows\Temp\php76B0.tmp,D:\Webs\html\Baywatch\www\admin/../../app/temp/MultipleFileUpload-uploads/300174aaec0140eb33-4aaec020db918) [function.rename]: No error in D:\Webs\html\Baywatch\libs\Nette\Web\HttpUploadedFile.php on line 181

A ve formuláři error ‚Unsupported image type‘ – zjevně selhává $image->getContentType().

Editoval LastHunter (15. 9. 2009 0:15)

Honza Kuchař
Člen | 1662
+
0
-

Tip 1

Máš tam upravenou verzi nette-ajax-form.js? S tou původní se to chovalo tak všelijak. Je to plně zpětně kompatibilní

Tip 2

(warning) Aaah, už to vidím. Windows neumí přesouvat soubory mezi disky. (používá se rename) Tempy máš na C: a data na D:
Ale stále mi není jasný, proč je na přesunutí nepoužilo move_uploaded_file – které evidentně funguje i mezi disky. Protože u mě to jede suprově. Ale i přes to všechno zkus v HttpUploadedFile změnit metodu move:

	/**
	 * Move uploaded file to new location.
	 * @param  string
	 * @return bool
	 */
	public function move($dest)
	{
		if (move_uploaded_file($this->tmpName, $dest)) {
			$this->tmpName = $dest;
			return TRUE;

		} else {
if(rename($this->tmpName, $dest)) {
        $this->tmpName = $dest;
        return TRUE;

} else {
        if(copy($this->tmpName, $dest)){
            unlink($this->tmpName);
            $this->tmpName = $dest;
            return TRUE;
        }
        return FALSE;
}
		}
	}

Dotaz

Když si z SVN stáhneš ten příklad, tak ti to funguje jak má? Soubory se přesouvají do APP_DIR/uploadData/.

Editoval honzakuchar (15. 9. 2009 11:19)

Honza Kuchař
Člen | 1662
+
0
-

Tak s tím content-type. Nette se tak chová i se standardním file inputem. Mime-typ co mu pošle klient zahazuje a potom se ho snaží zjistit samo. Nejdříve se pokusí k souboru chovat jako k obrázku. Pokud selže, pokusí se použít fileinfo popřípadě mime_content_type, která pokud vím, tak na Win není dostupná. Nicméně mě tedy u obrázků mime-typ určil správně.

Tip: Nemusíš kontrolovat, zda byl soubor v pořádku odeslán – o to se stará už MultipleFileUpload

Zaktualizoval jsem příklad, takže ukazuje co Nette vykouzlilo za Mime-typ

Ondřej Mirtes
Člen | 1536
+
0
-

Tak jo, přepsal jsem metodu move (nestálo by to za přidání do Nette?), takže při klasickém uploadu (s vypnutým Javascriptem) to už proběhne v pohodě. Ale při zapnutém JS a použitém Flashi to vyhazuje stále HTTP Error. Jdu to zkusit na ostrém serveru.

Mimochodem, jak dostanu do windows open dialogu ty checkboxy, které jsou vyobrazené na screenshotech? Nebo to s touto komponentou nesouvisí a je to nějaké tvé rozšíření winshellu?


Ty jo, tak to začalo fungovat, foto se přidá, i když mi ten flash zahlásí HTTP Error… fakt divné.


Na serveru to bez JS funguje, s JS to neprojde přes podmínku:

->addRule("MultipleFileUpload::validateFilled","You have to upload at least one file!");

Editoval LastHunter (15. 9. 2009 12:54)

Honza Kuchař
Člen | 1662
+
0
-

Zkus si prosím stáhnout poslední revizi se SVN. všiml jsem si tam jedné takové nepříjmené krpy. Byla vytvářena AbortException, ale tahle část byla volána mimo Application. → 500 Přepsáno na die a už je vše ok. Alespoň u mě.

Honza Kuchař
Člen | 1662
+
0
-

Tak jo, přepsal jsem metodu move (nestálo by to za přidání do Nette?)

No stálo, původně ta metoda šla přesouvat pouze jednou. Viz https://forum.nette.org/…2x-presunout . Jak se tak dívám, tak úplně tu stejnou chybu dostal phx.

Honza Kuchař
Člen | 1662
+
0
-

jak dostanu do windows open dialogu ty checkboxy, které jsou vyobrazené na screenshotech

já ti sám nevím, objevilo se mi to tam po tom, co jsem nainstaloval tablet. (asi si to myslí, že je to tablet PC)

Ondřej Mirtes
Člen | 1536
+
0
-

Updatnul jsem – na localhostu to už jede, ale na serveru stále před reloadem stránky na konci uploadování blikne HTTP Error a pak to zahlásí, že musím nahrát aspoň jeden soubor :(

Honza Kuchař
Člen | 1662
+
0
-

Tak to bude asi nějaký Windows / Linux wtf.

A na čem jsi to testoval?

K tomu HttpErroru. Zkusil bych dočasně oddělat nette-ajax-form (form se neodešlě ajaxově) a ještě v MultipleFileUpload.js odělat ten řádek, kde se znova odesílá formulář. Potom bych se pokusil navěsit na uploadify eventy onError a onComplete a z complete si někam vypsat respose a onError ten errorObj.info. Uvidíš co ti to řekne. Potom bych ještě prozkoumal co se ti objevilo v App_dir/log.

Honza Kuchař
Člen | 1662
+
0
-

Ještě bych potom zkusil na řádku 108,109 zakometovat

// V PHP 5.3 zhodí Apache!
if(self::isRequestFromFlash())
    Debug::enable(Debug::PRODUCTION);

Editoval honzakuchar (15. 9. 2009 14:22)

Honza Kuchař
Člen | 1662
+
0
-

Jinak k tomu mime-typu: https://github.com/…7d127cc26895

Honza Kuchař
Člen | 1662
+
0
-

Jenom ještě k tomu Linuxu: testování na jiných platformách než Win je na vás. Mám všechny servery na Windows. Pokud tedy někdo bude mít zájem vyřešit problém na Linuxu, tak ať mě kontaktuje na ICQ (je v profilu tady na fóru). Řešit to tady přímo přes fórum mi přijde dost pomalé.

lactarius
Člen | 47
+
0
-

Zdar vespolek,

jinak perfektně vypadající Uploadify u mě svým chováním přesně vystihuje zde popisovaný problém (HTTP Error). Metodu Move jsem přepsal, verzi Nette i MultiFileUpload jsem stáhnul poslední.
Bez JS to funguje.
Neodhalil už někdo z vás příčinu ?

Honza Kuchař
Člen | 1662
+
0
-

Bohužel, bude to chtít krokovat. U mě se všechno chová korektně. (WinXP a Win2k server + PHP 5.2.9) Ale myslím si, že bude někde špatně velikost písmen.


Jenom znova upozorňuji, tato komponenta zatím není vhodná pro produkční nasazení. Chce to to ještě dost věcí doladit. (hlavně ověřovací tokeny a validaci už při uploadu)

stromc3k
Člen | 7
+
0
-

taky bych uvital pokud by nekdo zjistil proc to nefunguje na linuxu. :(

cuga
Člen | 210
+
0
-

a jak to vypada s dotazenim do verze vhodne pro produkcni nasazeni???

Honza Kuchař
Člen | 1662
+
0
-

Vidim to o dalších prázdninách.


Proč to ale nejde na Linuxu stále nevím…

Editoval honzakuchar (2. 11. 2009 10:21)

marek-m
Člen | 66
+
0
-

moj predpoklad
script: {}, – aj ked tam doplnis nieco ako backLink, je to prazdne

neexistuje script pre spracovanie – daj si tam hocijaky subor, ktory len stiahne data, samozrejme bez validacie potom to ide

Panda
Člen | 569
+
0
-

Tak jsem se v tom trošku vrtal, ale zatím jsem to nijak výrazně nezkoušel. Opravil bych toto:

115: mkdir($dir, 0777);
// práva musí být v osmičkové soustavě, jinak se tam nastavuje 1411 (+t,u+r,g+x,o+x)
447: $template->backLink = (string) $this->form->action;
// explicitní přetypování na string

Po těchto úpravách mi HTTP error na linuxovém serveru zmizel.

Vyki
Člen | 388
+
0
-

Tak bohužel, mě tato úprava nepomohla. Možná je to stupidní dotaz, ale myslel jsem, ze při zapnutém safe mode nefunguje v php funkce mkdir??

Editoval Vyki (15. 11. 2009 12:07)

Panda
Člen | 569
+
0
-

Vyki napsal(a):

Tak bohužel, mě tato úprava nepomohla. Možná je to stupidní dotaz, ale myslel jsem, ze při zapnutém safe mode nefunguje v php funkce mkdir??

mkdir funguje, ale často je nepoužitelný – nově vytvořená složka má většinou jiného vlastníka, než je vlastník skriptu a tak safe_mode nepovolí přístup. Zkus se podívat, co Ti aplikace píše do error logu ve složce app/log. Pokud není v produkčním prostředí, tak bude možná potřeba logování zapnout pomocí Environment::setMode(Environment::PRODUCTION); v bootstrap.php (log se vytváří jen v produkčním prostředí).

Vyki
Člen | 388
+
0
-

Vyřešeno! Problém je s právy u souboru temp/MultipleFileUpload-uploads. Přes ftp klienta stačí tento adresář, který má špatně nastavená práva smazat a vytvořit jej znova s právy 0777. Potom už vše běží. Když jsem adresář nejdříve nesmazal a snažil se u něj nastavit jiná práva tak to nešlo. Musí se opravdu smazat a znovu vytvořit. + úpravy, které zde napsal Panda

Editoval Vyki (16. 11. 2009 15:35)

Honza Kuchař
Člen | 1662
+
0
-

Díky, za vyřešení problému. Je to na SVN.

Ad: $this->form->action; to je snad string vždy ne?

Panda
Člen | 569
+
0
-

honzakuchar napsal(a):

Ad: $this->form->action; to je snad string vždy ne?

Ne, AppForm si tam dává objekt Link: https://api.nette.org/…orm.php.html#75.

Vyki napsal(a):

Musí se opravdu smazat a znovu vytvořit. + úpravy, které zde napsal Panda.

Mělo by stačit jen smazat, vytvořit se správnými právy by se měl už sám. Na FTP Ti to upravit nešlo právě kvůli tomu, že se prvotně adresář vytvořil se špatnými právy (nešel modifikovat), ale jako objekt nadřazeného adresáře se správnými právy smazat šel.

Editoval Panda (16. 11. 2009 16:51)

Honza Kuchař
Člen | 1662
+
0
-

@Panda: Díky opraveno.

@Vyki: Opraveno: pokud nejde zapisovat do vytvořené složky, je použita přímo složka %tempDir%.

Problémy s IE:

  1. flash ve <form>u je problém. IE si to přeloží jako window.id.fce(..);. Ale muselo by to být window.form[x].id.fce(...). Řešení: pužívat patchlý swfobject.js (je v distribuci) Ten objekt flashe „zkopíruje“ do objektu window. (do toho co si vygenruje nejde zasahovat :( )
  2. flash s id, které obsahuje „-“ je taky problém. IE totiž potom používá někde interně id.nejakafce(...). Tzn. pak se to přeloží na něco typu frmform-test-text.fce(...). Tzn. odečítá od objektu frmform test a následně text. Ani jedno není definováno. → chyba → absolutně nepoužitelné. Řešení: používat patchnutý jquery.uploadify.v2.1.0.js, který „-“ nahrazuje.
  3. Je to hrozně pomalé, ale funguje to. Opravdu se vyplatí používat jen u velkých souborů. Mezi soubory čeká. Při výběru čeká. Řešení: používat jakýkoli jiný moderní prohlížeč.

TODO:

  1. Přestat používat cache jako storage dat.
    • Začít používat model, který bude thread-safe
  2. Modulární přeuspořádní. (že by nenbylo závislé jen na uploadify, ale podporovalo by třeba Google Gears)
  3. Průběžná validace dat. Aktuálně se všechny soubory přijmou (do tempů) a až poté se zkontrolují. Zatím nevím, jak by to mělo fungovat. Nebo je současné řešení vyhovující? (bezpečnostní mezera tím nevzniká, chová se to stejně jako PHPko, to taky soubory nejdříve všechny přijme, uloží do tempů a až potom je třeba smažem…)

Editoval honzakuchar (17. 11. 2009 14:13)

Matúš Matula
Člen | 257
+
0
-

Ahoj,

skusil som implementovat tento addon, na localhoste [Win] fachci. Akonahle ho dam na ostry server [Linux], tak to zrejme pada na tom, ze sa neodosle hlavicka Content-Type ..

MultipleFileUpload.php riadok 110

<?php
 if(!$req->getMethod() === "POST" OR !stristr($req->getHeader("Content-type"),"multipart/form-data"))
            return;
?>

ked dumpnem $req->getHeader("Content-type") po odoslani formulara, tak na locale vypise daco taketo multipart/form-data; boundary=---------------------------281123069513169, na ostrom serveri je to NULL.
Vie mi s tym, prosim, niekto poradit?

iguana007
Člen | 970
+
0
-

a prava mas dobre nastavene na vsech adresarich? tj. temp a uploadir?

Matúš Matula
Člen | 257
+
0
-

ano, prava su OK. pouzil som ukazku z https://componette.org/search/?… . na inom ostrom serveri mi to ide, na danom, na kt. momentalne hostuje projekt, to vsak nejde a pada to na vyssie spomenutej podmienke s hlavickou.