Upload souboru/souborů – jak na to?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Croc
Člen | 270
+
0
-

Zdravím,
potřebuji udělat upload souboru (zatím pouze jednoho) spolu s formulářem. Později budu řešit i upload více souborů najednou. Bude se jedna z 90% o obrázky.

Procházel jsem fórum, ale nevím kde se chytit (většina vláken je starší 2 a více let).

Prosím tedy o výkop správným směrem. Mám Nette 2.3.7.

Co mi připadalo zajímavé:

MultipleFileUpload
Upload Manager

Je z toho něco použitelné? Popřípadě jaký postup by jste doporučili vy. Určitě bych preferoval Ajax.

Díky moc

Editoval Croc (10. 11. 2015 21:14)

Oli
Člen | 1215
+
0
-

https://forum.nette.org/…tridu-pouzit#…

Záleží co od toho chceš. Jestli chceš aby to za tebe řešilo všechno (i ukládání do db), jen soubory (verze velikostí obrázků) nebo jen upload…

Croc
Člen | 270
+
0
-

Díky za tipy. Asi nejdřív zkusím WebChemistry-Images.

Mám zde ale problém s instalací přes composer – composer require webchemistry\images:1.4.3:


./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - The requested package webchemistry\images could not be found, it looks like its name is invalid, "\" is not allowed in package names.

Potential causes:
 - A typo in the package name
 - The package is not available in a stable-enough version according to your minimum-stability setting
   see <https://groups.google.com/d/topic/composer-dev/_g3ASeIFlrc/discussion> for more details.

Read <https://getcomposer.org/doc/articles/troubleshooting.md> for further common problems.

Installation failed, reverting ./composer.json to its original content.

Koukal jsem i na packagist.org ale nenašel bych tam že bych měl špatně příkaz… Nevíte čím to může být způsobeno?

Editoval Croc (11. 11. 2015 8:09)

Oli
Člen | 1215
+
0
-

Obraceny lomitko? :)

Croc
Člen | 270
+
0
-

Díky :)

BTW umí DropzoneUploader, MultiFileUpload nebo WebChemistry toto (či trochu podobné)? → Demo

Ani jeden nemá live demo, tak nevím co od toho čekat :-)

Editoval Croc (11. 11. 2015 8:41)

mrtnzlml
Člen | 140
+
0
-

Pokud hledáš přímo hotový uploader, tak mohu jedině doporučit Fine Uploader jelikož toho umí ranec a jeho integrace je snadná. Akorát pozor na to, že pokud jej chceš pro komerční využití, tak bys měl koupit licenci… :)

Croc
Člen | 270
+
0
-

Díky za tip. Koukal jsem na licenci a toto budu určitě prvních pár let splňovat:

When do I need to purchase a license?
You must purchase a license if you are going to use Fine Uploader for a commercial product or in a commercial setting. If you are developing an open-source or free product and will not derive any money from the product using Fine Uploader, you may use Fine Uploader free of charge under the Widen Commercial License.

Stránky budou pro veřejnost a ze začátku určitě nebudu (jestli někdy vůbec:-) ) na nich vydělávat. Potom bych licenci asi musel dokoupit.

Dnes na něj kouknu a uvidím :-)

Oli
Člen | 1215
+
0
-

Dropzone umí tohle: http://www.dropzonejs.com/. Je to jen jednoduchá integrace do nette. Nastavíš si v podstatě jen složku kam to chceš nahrát a můžeš omezit jestli chceš fotky, soubory (jaký), jaký velikosti, … No a až se to uloží do složky, tak se zavolá událost a v ní si to zpracuješ a uložíš do db (nebo kamkoli chceš).

Webchemistry jsem nikdy nepoužil, tak nevím jestli používá nějakou knihovnu pro nahrávání nebo jen obaluje html5 multiupload.

@mrtnzlml tak proto jsem se na to ani nekoukal. $480 není zrovna málo a málokdy potřebuju (bylo by hezký to mít, ale není to must have) něco jinýho než multiuploader…

Croc
Člen | 270
+
0
-

Tak ten Dropzone se mi líbí úplně nejvíce. Je také možné ho dát do bootstrap3 vzhledu.

@Oli Jestli můžu, vyzkoušel bych tedy tvůj DropzoneUploader. Máš ho v composer repository? Jak je možné ho nainstalovat a nakonfigurovat?

F.Vesely
Člen | 369
+
0
-

Ja pouzivam Dropzone na nahravani a na ukladani Webchemistry/Images.

Oli
Člen | 1215
+
0
-

Já svůj dropzone používám spolu s https://github.com/…te-webimages.

@Croc Snad se dneska dostanu k tomu napsat nějaký readme.

Croc
Člen | 270
+
0
-

To vypadá zajímavě. Taky kouknu.

To by bylo úplně super :) Díky moc

Oli
Člen | 1215
+
0
-

Tak jsem aspon v rychlosti updatoval readme

iguana007
Člen | 970
+
0
-

@Oli kde si updatoval readme?

Oli
Člen | 1215
+
0
-

@iguana007 heh, sorry. ono se to tu řešilo tak napůl: https://github.com/…zoneUploader

iguana007
Člen | 970
+
0
-

@Oli tipuji, že tam máš překlep ;)

composer require olicek/google-map-api:dev-master
Croc
Člen | 270
+
0
-

@Oli Super díky moc :) Pustil jsem se pomalu do práce, ale mám několik dotazů:

  1. `extensions:

    map: Oli\Form\DropzoneUploaderExtension` → asi tam máš překlep :) „map“

  2. Pokud mám presenter takto:
use Nette,
    Oli\Form\DropzoneUploaderFactory,
    Oli\Form\DropzoneUploader;

class Presenter extends BasePresenter
{
    /** @var DropzoneUploaderFactory
     * @inject
     */
    public $factory;

    public function __construct(Nette\Database\Context $database)
    {
        $this->database = $database;

    }


    public function createComponentUploader($name, DropzoneUploaderFactory $factory) //chyba ukazuje na tento řádek
    {
        $dropzone = $factory->create();
        $path = $dropzone->getPath();
        $dropzone->onSuccess[] = function (DropzoneUploader $dropzoneUploader, $targetPath, $name, $suffix) {
            $photo = new Photo;
            $photo->filename = $name . '.' . $suffix;
            $photo->suffix = $suffix;

            $this->photosRepository->save($photo);
        };
        return $dropzone->setPath($path . '/' . $this->galleryEntity->folder . '/1600x1200');
    }

Tak mi to zahlásí tuto hlášku:

Recoverable Error

Argument 2 passed to App\Presenters\Presenter::createComponentUploader() must implement interface Oli\Form\DropzoneUploaderFactory, none given,
 called in G:\workspace\master\vendor\nette\component-model\src\ComponentModel\Container.php on line 181 and defined

Dělám něco špatně?

Editoval Croc (12. 11. 2015 8:09)

Oli
Člen | 1215
+
0
-

To DropzoneUploaderFactory si musíš předat do konstruktoru (stejně jako si předáváš database). Já používám https://github.com/Kdyby/Autowired, proto to můžu zapsat takhle, pro začátek je určitě lepší dělat to správnou a čistou cestou :-)

Jsem to jen copy pastnul ze svyho projektu a tohle tam zustalo, pak to změním ať je to jasnější

Ad 1) sakta ještě map. No ono to je jeno, jmenovat se totak může, ale nedává to smysl, to je pravda. Taky to změním. Díky.

EDIT: používám doctrine. Proto tam je to new Photo. Jestli používáš nette database, tak použíj místo toho něco jako

$toDb = [
	'filename' => $name . '.' . $suffix,
	'suffix' => $suffix,
	'gallery_id' => $galleryId,
	// Cokoli dalšího potřebuješ, je to jen na tobě
]

$this->database->save($toDb);

Editoval Oli (12. 11. 2015 8:12)

Croc
Člen | 270
+
0
-

Já sem debžon. Sice jsem si injectnul komponentu, ale pak ji nezavolal správně:

$dropzone = $factory->create(); // špatně

$dropzone = $this->factory->create(); //správně

To že používáš doctrine jsem kupodivu poznal :). Ale díky za příklad, šikne se :)

Večer dám vědět jak se to povedlo.

Zatím díky moc

Editoval Croc (12. 11. 2015 10:05)

Oli
Člen | 1215
+
0
-

https://github.com/…xtension.php#L22

Root je vzdy wwwDir a v path si muzes nastavit tu defaultni cestu.

Croc
Člen | 270
+
0
-

Pátral jsem, ale nenašel jsem že default je wwwDir. Takže díky :)

Aktuální kód mám takto:

 public function createComponentUploader($name)
    {
        $dropzone = $this->factory->create();
        $path = $dropzone->getPath('\upload');
        $dropzone->onSuccess[] = function (DropzoneUploader $dropzoneUploader, $targetPath, $name, $suffix) {
         /*   $photo = new Photo;
            $photo->filename = $name . '.' . $suffix;
            $photo->suffix = $suffix;

            $this->photosRepository->save($photo);*/
        };
        return $dropzone->setPath($path);
    }

Při samotném uploadu dostanu tuto chybu:

Fatal error: Call to undefined function Nette\Http\finfo_file() in G:\workspace\master\vendor\nette\http\src\Http\FileUpload.php on line 87 exception
 'ErrorException' with message 'Call to undefined function Nette\Http\finfo_file()'
in G:\workspace\master\vendor\nette\http\src\Http\FileUpload.php:87 Stack trace: #0 [internal function]:
Tracy\Debugger::shutdownHandler() #1 {main} (stored in G:\workspace\master\app\..\log\exception--
2015-11-12--08-53--6e173df2fe.html)

Nevíš kde by mohl být problém?

Editoval Croc (12. 11. 2015 10:50)

David Matějka
Moderator | 6445
+
0
-

nemas aktivni extension fileinfo

Oli
Člen | 1215
+
0
-

getPath a setPath nemusíš používat, pokud ti stačí defaultní path z configu. Já to tam mám, protože jsem potřeboval nějakou jinou. Takže jsem si pomocí $path = $dropzone->getPath(); vytáhnul to, co dostal Dropzone z configu jako path a pomocí setPath($path . '/' . $this->galleryEntity->folder . '/1600x1200'); jsem mu nastavil další zanoření. Takže výsledek je ten, že se to uloží podle téhle logiky:

// bez setPath
server/project/www/gallery // gallery je defaultní z configu. Pokud si to tam přepíšeš, bude to jiná složka/strom.

// s setPath
server/project/www/gallery/gallery-folder/1600x1200 //z příkladu

Takže pokud to chceš uložit jen do složky gallery a neukládat do db, tak by ti mělo stačit dokonce jen tohle

public function createComponentUploader($name)
   {
       $dropzone = $this->factory->create();
//       $dropzone->onSuccess[] = function (DropzoneUploader $dropzoneUploader, $targetPath, $name, $suffix) {
//       };
       return $dropzone;
   }
Croc
Člen | 270
+
0
-

@DavidMatějka Díky, opraveno :)

@Oli Určitě se mi ta cesta taky bude hodit, takže je dobře že to tam máš. Jen jsem nemohl najít jaká je výchozí a jak se nastavuje. Takže taky díky :)

Upload už probíhá OK. Vyberu/dropnu obrázky a ty se uploadujou, ale zobrazí se mi toto: Obrázek

S již uploadovaným obrázkem nelze dělat nic (nejde smazat). Zkoušel jsem i nastavit různé parametry pro dropzone ale žádnou změnu jsem nezaznamenal…

Asi to nebude souviset s Nette nebo s tvým extension, bude to asi problém mojí implementace dropzone.js. Bohužel nevím kde je problém a co s tím dělat. Nenapadá vás něco prosím?

EDIT: Zkoušel jsem odlinkovat všechny CSS i JS soubory z @layout.latte (pro ověření že se mi něco nepere), ale po uploadu se zobrazuje pořád stejně.

EDIT: Pokud uploaduji něco jiného než obrázek:

20151105101246_00.pdf
exception 'Nette\InvalidArgumentException' with message 'Soubor musí být obrázek' in G:\workspace\master\vendor\olicek\dropzone-uploader\src\DropzoneUploader.php:132 Stack trace:
 #0 [internal function]: Oli\Form\DropzoneUploader->process(Object(Nette\Application\UI\Form), Object(Nette\Utils\ArrayHash))
#1 G:\workspace\master\vendor\nette\utils\src\Utils\Callback.php(65): call_user_func_array(Object(Closure), Array)
#2 G:\workspace\master\vendor\nette\forms\src\Forms\Form.php(411): Nette\Utils\Callback::invoke(Object(Closure), Object(Nette\Application\UI\Form), Object(Nette\Utils\ArrayHash))
#3 G:\workspace\master\vendor\nette\application\src\Application\UI\Form.php(133): Nette\Forms\Form->fireEvents()
#4 G:\workspace\master\vendor\nette\application\src\Application\UI\Presenter.php(324): Nette\Application\UI\Form->signalReceived('submit')
#5 G:\workspace\master\vendor\nette\application\src\Application\UI\Presenter.php(201): Nette\Application\UI\Presenter->processSignal()
#6 G:\workspace\master\vendor\nette\application\src\Application\Application.php(141): Nette\Application\UI\Presenter->run(Object(Nette\Application\Request))
#7 G:\workspace\master\vendor\nette\application\src\Application\Application.php(81): Nette\Application\Application->processRequest(Object(Nette\Application\Request))
#8 G:\workspace\master\www\www\index.php(8): Nette\Application\Application->run()
#9 {main} (stored in G:\workspace\master\app\..\log\exception--2015-11-12--11-45--f71553c68d.html)

Editoval Croc (12. 11. 2015 12:41)

Oli
Člen | 1215
+
0
-

Vypada to, ze nemas styly z dropzonu. Jinak ten muj doplnek zatim umi jen uploadovat. Mazat po nahrani to neumi… zobrazeni nahranych, editaci, mazani, … to si musis dodelat sam. Tohle zatim umi opravdu jen upload

Edit: ta chyba je kvuli tomuto: https://github.com/…xtension.php#L34

Editoval Oli (12. 11. 2015 12:45)

Croc
Člen | 270
+
0
-

Super, díky moc, to bylo ono :)

Základní funkčnost mám a to zatím stačí :) Mazání, atd. dořeším později až se v tom trochu víc zorientuju.

Ještě jednou díky za reakce a trpělivost.

Croc
Člen | 270
+
0
-

Zatím koukám jak by se dal implementovat výmaz již uplodovaného souboru. Nějakou představu už mám, ale mám jednu otázku. Dle dokumentace dropzonejs stačí do configu přidat addRemoveLinks: true a díky tomu by se měl ke každému thumb přidat <a class="dz-remove">Remove file</a>, viz zde.

U tebe se tomu tak neděje, protože s tímto parametrem nepracuješ. Tím pádem to tam nikde nevykresluješ, je to tak?

Editoval Croc (12. 11. 2015 15:36)

Oli
Člen | 1215
+
0
-

Přesně tak, v rychlosti jsem to zkoušel, ale nějak mě to nešlo, tak jsem to dal uplně pryč. Ono to je stejně jen proto, že kdyžto nahraješ a teď na to koukneš a zjistíž, že nějakej obrázek tam je navíc, tak ho hned smažeš. Jinak po refreshi ti ty soubory z dropzone zmizí.

Ono celej ten dorpzone ma hromadu dalších funkcí, který nemám implementovaný. Ale neznamená to, že nejdou. Když si upravíš ten js soubor, tak si tam můžeš udělat cokoli co je v dokumentaci. Když něco doplníš, tak klidně pošli PR. Rozhodně se nebráním mít tam další funkce, jen je zatím nepotřebuju…

K tomu mazání. Pokud nepoužíváš nějaký datagrid, tak bych to udělal uplně normálně. Něco jako:

{forach $photos as $photo}
	<img src="{$somePath}/{$photo}"> <a n:href="delete! $photo->id">smazat</a>
{/foreach}
Croc
Člen | 270
+
0
-

Kdyžtak to zkusím nějak pořešit a pokud by se mi to kloudně podařilo tak pošlu PR. Aktuálně mám ještě dost jiných věci na práci, takže mě to zatím úplně netlačí (ale koncem roku bude).

To mazání jsem myslel hlavně pro uživatele, kteří si nahrajou obrázek a budou ho chtít hned smazat (nahráli špatný, atd.). Dropzone nabízí funkci kdy najedeš na uploadovaný obrázek a rovnou ho můžeš smazat.

Croc
Člen | 270
+
0
-

Tak jseště budu mít jeden dotaz :-) Pokud bych chtěl použít omezení na počet souborů na jednom místě a na jiném bych potřeboval použít dropzone zase bez omezení, je to nějakým způsobem možné?

Zkoušel jsem si hrát s nastavením extension, jak v dropzoneUploader.js

var myDropzone = new Dropzone('#' + self.attr('id'),
			{
				url: $(this).attr('action'),
				maxFilesize: settings.fileSizeLimit,
                maxFiles: 1 //přidáno
            });

tak i v DropzoneUploaderExtension.php:

public $defaults = [
		'wwwDir' => '%wwwDir%',
		'path' => 'gallery',
		'settings' => [
			'maxFilesize' => 5,
			'fileSizeLimit' => 100,
            'maxFiles' => 1 // přídáno
		],
		//...

jediné co pomůže je změnit defaultní nastavení přímo v dropzone.js, což se zase projeví všude… Připadá mi jako když ty parametry nastavení z extension jsou ignorovány.

Editoval Croc (12. 11. 2015 20:25)

Oli
Člen | 1215
+
0
-

Samozřejmě máš pravdu :-) Až budu mít čas, tak to opravím. Nebo jestli to potřebuješ co nejdříve, tak pošli PR. Mám tam i typo maxFilesize má být maxFiles. Mělo by to staačit jen přepsat v DI a přidat do js souboru. Do js souboru to přidáš jako settings.maxFiles

Ono tam těch bugů bude víc, vím asi o 3 drobnejch chybičkách, ale zatím jsem se k tomu nedostal :-(

Editoval Oli (12. 11. 2015 21:32)

Croc
Člen | 270
+
0
-

Zítra na to kouknu a zkusím poslat PR. Dnes už toho mám dost :P

Croc
Člen | 270
+
+1
-

Tak jsem se trochu víc rýpal ve tvé extension :) a mám následující poznatky:

  1. Obsah JS souboru dropzoneUploader.js vůbec není potřeba. Když jsem ho smazal, funkčnost byla stejná.
  2. Nastavení v extension není bráno v potaz (ani po těch úpravách co jsi psal výše) – DropzoneUploaderExtension.php – (maxFiles, atd.).
  3. Upravil jsem trochu šablonu:
{* Latte template *}
{block content}
<form n:name="uploadForm" class="dropzone alert alert-info" id="myDropzone">
	<div class="fallback">
		<input type="file" n:name="file"/>
	</div>
	<div class="fileUpload-settings" data-fileUpload-settings="{$uploadSettings}"></div>

</form>
{/block}
  1. Rozchodil jsem nastavení v místě použití:
<script>
Dropzone.options.myDropzone = {
    maxFiles: 1,
    maxFilesize: 1, // MB
    addRemoveLinks: true, // přidá remove link pod thumb (ale neodstraní soubor ze serveru)
    removedfile: function(file) { // zde volám akci pro smazání souboru ze serveru a z DB - akce se opravdu zavolá
    var name = file.name;
    $.ajax({
        type: 'POST',
        url: '../delete?file='+name,
        dataType: 'html'
    });
    var _ref;
    return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
    }
};
</script>
  1. Zde se pokouším vytvořit akci pro mazání souboru a výmaz z DB (zatím se snažím rochodit samotný výmaz souboru), ale neúspěšně.
    /**
     * @param $file
     */
    public function actionDelete($file)
    {
		// zde budou kontroly zda uživatel opravdu může smazat soubor, atd.
        unlink($file); // výmaz souboru
		// zde bude výmaz souboru z DB
    }

unlink($path_to_file); potřebuje název souboru i s cestou, ale nevím jak přesně. Zkoušel jsem např.: $path_to_file = "G:workspace/master/www/www/gallery/".$file, ale napsalo to že složka/soubor neexistuje (cesta k souboru i jeho název byl správný).

Myslíte si že je to dobrý přístup? Nebo by bylo nějaké lepší řešení?

Oli
Člen | 1215
+
0
-

Super, děkuju za feedback. Jestli se ti to nastaveni neprojevuje, tak se to nějak nepropojilo správně. Mám pocit, že mě to fungovalo. Dneska na to zkusím kouknout.

Croc
Člen | 270
+
0
-

Ono se to nastavení z extension přenese do HTML kódu stránky, ale dropzonejs ho nebere v potaz.

Croc
Člen | 270
+
0
-

Tak se zdá, že se podařilo ± vše implementovat až na jednu věc (pro mazání, generování thumbs a pro zobrazování obrázků v šabloně jsem použil WebChemistry-Images). Tou je pojmenování souborů. Je zde háček s mazáním souboru ihned po uploadu, kdy se na serveru již vyskytuje obrázek se stejným názvem.

Soubor se uploaduje (např. foto.jpg), pokud tam je stejný název tak se uloží na server a do DB jako fotka1.jpg. Problém ja ale ve volání akce pro výmaz souboru při uploadu, protože tam zůstane původní název a tím by se mohl smazat úplně jiný soubor (při mazání kontroluji uživatele), či se ho naopak smazat nepodaří.

Je realozovatelné poslat nový název souboru po uploadu zpět na clienta? Nejradši bych totiž přejmenovával všechny uploadované soubory :)

// script v místě použití dropzone
Dropzone.options.myDropzone = {
    maxFiles: 1,
    maxFilesize: 3,
    addRemoveLinks: true,
    removedfile: function(file) {
    var name = file.name; // tento název potřebuji aktualizovat po fyzickém uploadu souboru na server
    $.ajax({
        type: 'POST',
        url: '../delete?file='+name,
        dataType: 'html'
    });
    var _ref;
    return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
    }
};

Editoval Croc (14. 11. 2015 11:01)

F.Vesely
Člen | 369
+
0
-

Ja po uploadu pres Dropzone z nej ty obrazky smazu a zobrazim je pod nim. Pak je muzu jednoduse mazat, prepisovat alt, radit, vybirat defaultni atd. Pokud na to pouzijes ajax se snippetem, tak to chodi dobre.

Croc
Člen | 270
+
0
-

To zní dobře :) Díky za tip, zkusím něco vytvořit.

Croc
Člen | 270
+
0
-

Seznamuji se s Ajaxem a snippety. Přibližně vím jak z dropzonejs zavolat „něco“ po dokončení uploadu a přibližně vím jak se pracuje se snippety. Bohužel moc netuším co a jak zavolat, aby se snippet aktualizoval a ukázal ty soubory.

Definice Dropzone pro volání po dokončení uploadu.

Dropzone.options.myDropzone = {
    init: function () {
        this.on("complete", function (file) {
            if (this.getUploadingFiles().length === 0 && this.getQueuedFiles().length === 0) {
                // toto se zavolá po dokončení uploadu
            }
        });
    }
};

Nemáš prosím nějakou ukázku? Nebo aspoň nějaký tip co by mě popostrčil? Díky moc

F.Vesely
Člen | 369
+
0
-

Control:

public function handleRefresh(){
	$this->redrawControl('imagesSnippet');
}

Template:

<div n:snippet="imagesSnippet">
	<div n:foreach="$images as $image">
		...
	</div>
</div>

JavaScript:

<script>
var myDropzone = new Dropzone(...);

myDropzone.on("queuecomplete", function() {
	$.nette.ajax({
		type: 'get',
		url: {link refresh} //pokud mas JS primo v template, nebo si ten link predej do data-dropzone-settings
	});
	myDropzone.removeAllFiles(); //smaze obrazky z Dropzone
});
</script>

Predpoklada se, ze pouzivas nette.ajax.js :)

Editoval F.Vesely (15. 11. 2015 21:48)

Croc
Člen | 270
+
0
-

Super, tohle jsem potřeboval, díky :)

Teď vymýšlím, jak postupovat při zpracování příloh. Moje představa je zatím tato:

  1. Uživatel vybere soubory (obrázky) a uploaduje na server → ty se uloží do cílové složky originálním názvem a v zápětí je přejmenuju.
  2. Názvy příloh uložím do TEMP tabulky pro přílohy s nějakým společným ID, abych poznal že se jedná o jeden balík (proto abych věděl jaké přílohy zobrazit pod uploadem). Jde to rozlišit i jinak?
  3. Bylo by zde tlačítko, kterým by uživatel potvrdil uploadované přílohy → tím by řekl, OK to je vše (tím by se uložily na požadované místo do DB a smazaly by se z TEMP tabulky).

Co si o tomto myslíte? Není to moc komplikované?

Pavel Kravčík
Člen | 1205
+
0
-

Nedávno jsem to řešil. Cca takto:

Ukládám na disk do složky /uploads/. Cca tímto stylem:

/uploads/5000/34/ahoj.jpg → 5000 je id do 5000 (aby v budoucnu nebylo 20000 složek – to by filesystem nezvládl. Pak je samotné ID balíčku a název souboru.

Při stažení jen vezmu složku 34 projedu jí finderem, soubory zazipuju a pošlu response.

Croc
Člen | 270
+
0
-

Super díky za tip. Nechal jsem si to trochu projít hlavou a strukturu budu mít trochu jinak, ale pomohlo mi to.

@Oli Trochu si upravuju extension pro osobní použití, konkrétně tyto 2 věci:

1) Dynamické určení namespace pro uložení souboru, takže $targetPath vypadá takto: $targetPath = $this->wwwDir . DIRECTORY_SEPARATOR . $this->path . DIRECTORY_SEPARATOR . $this->namespace;

$namespace si definuji v presenteru:

public function createComponentUploader($name)
    {
        $namespace = $this->user->identity->user_guid;

        $dropzone = $this->factory->create($namespace); // přidán vstupní parametr $namespace
        $path = $dropzone->getPath();
        $dropzone->onSuccess[] = function (DropzoneUploader $dropzoneUploader, $targetPath, $name, $suffix) {
            $values = [
                'image_name' => $name . '.' . $suffix,
				'namespace' => $namespace
            ];

            //uložení $values do DB.
        };
        return $dropzone->setPath($path);
    }

– Práci s namespace mám implementovanou a na první pohled vypadá že funguje, ale ještě musím více otestovat.

2) Při uploadu generuju náhodný GUID, kterým pak přejmenuji uploadovaný soubor. Toto jsem udělal zatím takto:

$nameNoSuffix = Strings::random(32, '0-9a-zA-Z');
$name = $nameNoSuffix. '.' . $suffix;

Bohužel Strings::random je deprecated, ale zatím ho používám, páč jsem nenašel náhradu, ale na první pohled také funguje.

Pokud by si chtěl, tak až to doladím, můžu poslat PR (V tom případě bych u bodu 2 dodělal možnost nechat i původní název dle vstupního parametru $isNameRandom = TRUE/FALSE).

Editoval Croc (17. 11. 2015 21:06)

F.Vesely
Člen | 369
+
0
-

Croc napsal(a):
Bohužel Strings::random je deprecated, ale zatím ho používám, páč jsem nenašel náhradu, ale na první pohled také funguje.

Nette\Utils\Random

Oli
Člen | 1215
+
0
-

@Croc ten namespace nemusis takhle predavat. Jestli to chapu dobre, tak muzes udelat setPath($path . '/' . $namespace). Predavat namespace me prijde zbytecny.

To nahodny jmeno souboru e mi libi, jesli to posles jako pr, tak budu rad :)

Croc
Člen | 270
+
0
-

@F.Vesely Díky :)

@Oli Jo, máš pravdu. Já sem předtím zkoušel setPath, ale nějak mi nedošlo, že to mohu využít i na toto.
Přes víkend zkusím doladit ty náhodná jména, pak pošlu PR.

Zatím díky všem

EDIT: Jak chceš aby bylo možné předat parameter generování náhodného jména (TRUE/FALSE)?

Přes konstruktor?

 public function __construct($isRandomFileName)
    {
        parent::__construct();

        $this->isRandomFileName = $isRandomFileName;
    }

//nastavení ve vytváření komponenty:

$dropzone = $this->factory->create(TRUE);

Přes public metodu?

	public function isRandomFileName($isRandomFileName = FALSE)
	{
		$this->isRandomFileName = $isRandomFileName;
		return $this;
	}

//nastavení ve vytváření komponenty:
$dropzone = $this->factory->create();
$dropzone->isRandomFileName(TRUE);

Další otázkou je, jestli nechat náhodné generování jména defaultně FALSE či TRUE.

Editoval Croc (19. 11. 2015 13:52)

Oli
Člen | 1215
+
0
-

Určitě přes setter jako všechno ostatní: https://github.com/…xtension.php#…. Ono to totiž všechno můžeš nastavit globálně v configu a jen pokud chceš pro jeden konkrétní případ změnu, tak to provedeš přes ten setter.

Nechal bych náhodné generování na FALSE. To je totiž vycházející stav. Ideálně totiž aby starej kod fungoval bez zásahu stejně jako po PR.

Díky

Oli
Člen | 1215
+
0
-

@Croc opravil jsem ten počet souborů, které můžeš připojit. Byla chyba v tom. Takže nyní by ti mělo opravdu fungovat nalinkování toho souboru. Jako další jsem tam přidal přesměrování. Zatím jen this nebo na předpřipravenej signál refresh!. Ten invaliduje snippet photos.

PS. jak jsi posílal ten PR. tak tam to id="dropzoneId" je navíc. Možná proto ti to nešlo propojit řádně.

Croc
Člen | 270
+
0
-

Super, díky, kouknu na to.

To id jsem tam přidával až potom co jsem zjistil, že to nastavení z extension nejde. Přidal jsem ho tam, abych pak mohl v dané šabloně zavolat definici nastavení pro dropzone: Dropzone.options.myDropzone = {}

Croc
Člen | 270
+
0
-

@Oli Mohu se zeptat či vším by mohla být teoreticky způsobena chyba:

Nette\FileNotFoundException

Soubor byl poškozen:6

134:            if(!$file->isOk())
135:            {
136:                throw new \Nette\FileNotFoundException('Soubor byl poškozen:' . $file->error);
137:            }

Na localhostu mi to někdy udělá 1. soubor z vícero a na hostingu mi to dělá pořád (i když uploaduju 1 soubor). Nenapadá tě něco prosím?

EDIT: Už vím kde je chyba. Měl jsem smazaný tmp adresář na hostingu…

UPLOAD_ERR_NO_TMP_DIR
Value: 6; Missing a temporary folder. Introduced in PHP 5.0.3.

Editoval Croc (22. 11. 2015 20:59)