Jak zachytit chyby/upozornění spjaté s post_max_size

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

Zdravím,
lámu si hlavu jak nějak elegantně vyřešit následující:

mám tlačítko pro multiupload a submit. Jde mi o to je validovat, tak aby upload prošel, případně ohlásil uživatli, že všechny jeho vybrané soubory překročili limity.
Pronásleduje mě tato hláška, u které příčinu znám =>
Possible problem: you are starting session while already having some data in output buffer. This may not work if the outputted data grows. Try starting the session earlier.

Stiskni CTRL+U, a nad začátkem html je následující =>
<b>Warning</b>: POST Content-Length of 11105501 bytes exceeds the limit of 8388608 bytes in <b>Unknown</b> on line <b>0</b><br />

prošel jsem několik vláken na tuto problematiku, většina se týkala přenastavení php.ini nebo tvorbou htaccess, příklad zde:
https://stackoverflow.com/…-memory-size

zde je nástřel kódu u kterého jsem si říkal, že by mohl fungovat ALE:

<?php

	protected function createComponentUploadForm(){
        $target = $this->getParameter('target');
        $form = new Form;

        $form->addMultiUpload('files', NULL)
            ->addRule(Form::MAX_FILE_SIZE, 'Maximální velikost souboru je 4 MB.', 4 * 1024 * 1024)
            ->addRule(Form::FILLED , "Zde vyberte soubory")
            ->addRule(array($this,'validateSize'), "Zde vyberte soubory");

        $form['files']->getControlPrototype()->setid('multiplejpginput');

        $form->addHidden('target');
        $form['target']->setValue($target);

        $form->addSubmit('confirm', 'Nahrát');
        $form->onSuccess[] = array($this, 'uploadFormSucceeded');

        return $form;
    }

	public function validateSize(\Nette\Application\UI\Form $form, $values)
    {
		// vrati minimu z post_max_size a max_file_size
        $maxSize = $this->getMaximumFileUploadSize();
        $fileSize = 0;
        foreach ($values['files'] as $file) {
            $fileSize += $file->getSize();
        }
        if ($fileSize > $maxSize)
            $form->addError('Tato kombinace není možná.');
    }

	public function uploadFormSucceeded(\Nette\Application\UI\Form $form, $values)
    {
		// nejake cachry machry nesouvisejici s otazkou...

		if ($file->isOk()) {
            $file->move($path.'/'.$fileName);
        }
		$this->redirect('Upload:', array('target' => $target));
	}
?>

Buď je tu jen nějaká logická chyba, která mi uniká, nebo dojde k zaslání chyby ještě před samotným vyvoláním a vyhodnocením $form->onSuccess[]. V takovém případě jsem otevřený jakýmkoliv dobrým nápadům :)

Unlink
Člen | 298
+
0
-

No toto priamo nieje chyba nette. V php je parameter post_max_size (nastavuje sa cez php.ini) ktorý hovorí o tom, aká je maximálna veľkosť požiadavku. Ono sa do toho rátajú všetky súbory dokopy. Čiže ty síce máš že Maximální velikost souboru je 4 MB. ale keď tam nahráš povezdme tri 3MB súbory, tak ti to prekročí ten defaultný limit (8M)

Fera
Člen | 22
+
0
-

Jasné, to mi hlaval bere, na to je tam ta funkce validateSize, ve které jsem chtěl sečíst velikosti všech souborů, a v případě, že to překročím, tak zastavit odesílání nebo ohlásit chybu. Jenže to vypadá, že se ta funkce nějak neprovede. Na druhou stranu, toto podle mě musí jít nějak ošetřit. I kdybych přenastavil v php.ini například na 2000mb, stejně bych se bál, že někdo z hecu zkusí odeslat soubor(y) větší…

enumag
Člen | 2118
+
0
-

Vlastně jde spíše u tuhle issue.

Zatím to řeším tak, že jsem vypnul direktivu display_startup_errors, ta chyba se dá odchytit později nějak takto:

		$files = $this->getPresenter()->getRequest()->getFiles();

		if (count($files) !== 1 || !isset($files['upload'])) {
			// If post_max_size is exceeded both $_POST and $_FILES are empty.
			if (empty($_POST) && empty($_FILES) && isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0) {
				// ... chyba detekována
			}

			// případ který by neměl nastat, zatím zde vyhazuji BadRequestException
		}

Editoval enumag (4. 5. 2016 11:20)

Fera
Člen | 22
+
0
-

To vypadá dobře, teď to zksouším a ještě bych se teda zeptal, jak vypínáš ten „display_startup_errors“, zkoušel jsem různě házet ini_set(‚display_errors‘,‚off‘) – presenter, basepresenter i index.php a nějak to nepomáhá…

a ten úsek kódu, ten taky nevím kam, momentálně jej mam v uploadFormSucceeded, měl bych jej mít jinde?

možná zkouším jen špatné kombinace :)

enumag
Člen | 2118
+
0
-

Tohle se musí nastavit v php.ini nebo v .htaccess. Ty chyby se dají do outputbufferu ještě než tvůj kód vůbec začne takže ini_set proběhne pozdě. A pozor že display_errors je něco jiného než display_startup_errors.

V uploadFormSucceeded je to ok. Jen ten kód je z mého případu kdy jsem řešil upload mimo formuláře. Ve formulářích typicky nepolezeš přes request.

Fera
Člen | 22
+
0
-

Jasný, super, děkuju moc i za rychlou reakci :) vyzkouším to, případně se ještě ozvu

Fera
Člen | 22
+
0
-

Ok, tak bych asi ještě potřeboval popošťouchnout

1. Co se vlastně děje u tebe zde?

<?php
// tady asi natahnes z pozadavku soubory
$files = $this->getPresenter()->getRequest()->getFiles();
// tady testujes, jestli neni jeden? why?... a $files['upload'] je u tebe neco jako submit?
if (count($files) !== 1 || !isset($files['upload']))
?>

Zkoušel jsem to obdobně, ale tady mi to právě běhá na ten badRequest

<?php
public function uploadFormSucceeded(\Nette\Application\UI\Form $form, $values)
{
    $files = $values['files'];

    if (count($files) !== 1 || !isset($files['upload'])) {
        // If post_max_size is exceeded both $_POST and $_FILES are empty.
        if (empty($_POST) && empty($_FILES) && isset($_SERVER['CONTENT_LENGTH']) &&
			$_SERVER['CONTENT_LENGTH'] > 0) {
                echo "chyba";
        }

        throw new \Nette\Application\BadRequestException("");
    }
	//...
 }
?>

2. formular se nemenil

<?php
protected function createComponentUploadForm(){

    $target = $this->getParameter('target');
    $form = new Form;

    if ($this->lang == 'cs'){
        $form->addMultiUpload('files', NULL)
        	->addRule(Form::MAX_FILE_SIZE, 'Maximální velikost souboru je 4 MB.', 4 * 1024 * 1024)
            ->addRule(Form::FILLED , "Zde vyberte soubory");
    } else {
        $form->addMultiUpload('files', NULL)
            ->addRule(Form::MAX_FILE_SIZE, 'Maximum file size is 4 MB.', 4 * 1024 * 1024 )
            ->addRule(Form::FILLED , "Select your files");
    }
    $form->addHidden('target');
    $form['target']->setValue($target);

    $form->addSubmit('confirm', 'Nahrát');
    $form->onSuccess[] = array($this, 'uploadFormSucceeded');

    return $form;
}
?>

3. co se týká toho .htaccess, dal jsem tam:
php_flag display_startup_errors off

mám projekt členěný

  • app

-----AdminModul
---------presenters
---------template
-----FrontModul
---------presenters
--------------presnterA
--------------presenterB
--------------uploadPresenter
--------------TADY MAM TEN .HTACCESS
---------templates

  • www

------slozky
------slozkaProUpload

Možná jsem si model namyslel, celý špatně, ale nevím kam ten .htaccess hodit, poněvadž mi to ty hlášky pořád nepotlačuje. Napadá mě, hodit ho přímo tam, kde je index.php, ale tím potlačím hlášky všude…trochu jsem si myslel, že by to mohlo jít jen pro ten určitý presenter, ale to hádám.

Editoval Fera (4. 5. 2016 21:25)

ondrusu
Člen | 118
+
0
-

Ahoj, chtěl bych se zeptat jak toto řešit nějak na straně nette.
Všiml jsem si že v Nette\Froms je metoda

	public function validateMaxPostSize()
	{
		if (!$this->submittedBy || strcasecmp($this->getMethod(), 'POST') || empty($_SERVER['CONTENT_LENGTH'])) {
			return;
		}
		$maxSize = ini_get('post_max_size');
		$units = array('k' => 10, 'm' => 20, 'g' => 30);
		if (isset($units[$ch = strtolower(substr($maxSize, -1))])) {
			$maxSize <<= $units[$ch];
		}
		if ($maxSize > 0 && $maxSize < $_SERVER['CONTENT_LENGTH']) {
			$this->addError(sprintf(Validator::$messages[self::MAX_FILE_SIZE], $maxSize));
		}
	}

a proměnná maxSize nastavuje přesně to co já potřebuji vědět.
Jelikož direktivu post_max_size můžou mít na každým serveru jinak nastavenou tak se tím nechci zabívat abych to nastavoval všude ručně do formuláře na přímo

$form->addUpload('file_1')
     ->addRule(Form::MAX_FILE_SIZE, 'Maximální velikost souboru je 64 kB.', 64 * 1024);

Můžu si napsat něco jako toto:

$max_post_kb = $this->getMaxPost('kb');
$max_post_b = $this->getMaxPost('b');
$form->addUpload('file_1')
     ->addRule(Form::MAX_FILE_SIZE, 'Maximální velikost souboru je ' . $max_post_kb, $max_post_b);

a metoda getMaxPost by se zeptala ini_get funkce a nějak by si to „přepočítala“ na MB / Kb apod. abych tam měl čísla co potřebuji.

Jen se ptám pokud je něco na straně nette ta abych něco nepsal zbytčně.
díky za odpověď