Invalid parameter name, číslo a ajax

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

Nette Framework 2.0.1 (revision 94abcaa released on 2012–02–29)
PHP Version 5.3.5–1ubuntu7.7

Narazil jsem na problém ve verzi 2.0.1 (v 2.0 bylo v pořádku)

Mám formulář jehož položky jsou pojmenovány čísly (int), pokud ho odešlu normálně, není žádný problém, ale pokud je odeslán přes ajax, ukončí se chybou „Nette\Application\BadRequestException: ‚Invalid parameter name ‘2'“

Přijde mi že za to může regulární výraz v /Nette/Application/UI/Presenter.php:1275 v kombinaci s přidáním postu mezi parametry v případě ajaxu.

Editoval leninzprahy (16. 4. 2012 12:44)

nanuqcz
Člen | 822
+
0
-

Ahoj, názvy proměnných v PHP nesmí začínat číslem, tedy ani názvy polí ve formuláři.

http://www.tvorba-webu.cz/php/vars.php:
Název proměnné nesmí začínat číslem (jinak může čísla obsahovat), toto je chybné $1promenna = „hodnota“.

leninzprahy
Člen | 150
+
0
-

To je mi jasné, že proměnné nesmí začínat číslem (případně být číslo), ale proč to nejde u formulářového pole. Tam jde o název parametru a ne proměnné, je to vlastně klíč asociativního pole a ten číselný být může.

Nebo mi něco uniká?

nanuqcz
Člen | 822
+
0
-

Pokud by bylo na serveru zapnuté register_globals, tak se automaticky všechny $_POST['1'] namapujou na $1 a to nejde. Takže proto tohle omezení platí i pro formulářové pole.

leninzprahy
Člen | 150
+
0
-

Díky za odpovědi, ale stále mluvíme každý o něčem jiném :)

register_globals na to dle mého názoru nemá vliv, navíc v php 5.3 je deprecated a v php 5.4 snad už nebude vůbec.

Položka formuláře je komponenta a ta žádné takové omezení na jméno nemá (musí jen projít '#^[a-zA-Z0-9_]+$#').

Navíc jak jsem psal už na začátku, pokud je formulář odeslán normálně, vše je v pořádku, problém nastává až při AJAXovém požadavku.

Domnívám se, že za to může initGlobalParameters() v /Nette/Application/UI/Presenter.php

ve verzi 2.0 vypadal takto

...
$params = $this->request->getParameters();
if ($this->isAjax()) {
	$params += $this->request->getPost();
}

foreach ($params as $key => $value) {
	$a = strlen($key) > 2 ? strrpos($key, self::NAME_SEPARATOR, -2) : FALSE;
	if (!$a) {
		$selfParams[$key] = $value;
	} else {
		$this->globalParams[substr($key, 0, $a)][substr($key, $a + 1)] = $value;
	}
}
...

zatímco ve verzi 2.0.1

...
$params = $this->request->getParameters();
if ($this->isAjax()) {
	$params += $this->request->getPost();
}

foreach ($params as $key => $value) {
	if (!preg_match('#^((?:[a-z0-9_]+-)*)((?!\d+$)[a-z0-9_]+)$#i', $key, $matches)) {
		$this->error("'Invalid parameter name '$key'");
	}
	if (!$matches[1]) {
		$selfParams[$key] = $value;
	} else {
		$this->globalParams[substr($matches[1], 0, -1)][$matches[2]] = $value;
	}
}
...
nanuqcz
Člen | 822
+
0
-

Já tě chápu, ale

$form->addText('1', '1:');

vygeneruje

<input type="text" name="1">  <!-- plus nějaké ID, DATA-NETTE apod. -->

Takže pokud by někdo takový formulář odeslal na serveru s PHP 5.2 a se zapnutým register_globals, byl by průšvih (neotestováno).

Takže podle mě je chyba, že Nette nevyhodí vyjímku už při vytváření formuláře… Už ale nechám prostor i dalším lidem, tady je to evidentně jen věc názoru.

leninzprahy
Člen | 150
+
0
-

Věc názoru určitě. Každopádně děkuju za odezvu.
Já s tím třeba problém nemám, ale zase chápu že pojmenování položek formuláře čísly není úplně normální :)

Vygeneruje to přesně:

<input id="frmForm-1" class="text" type="text" value="" name="1_">

Samozřejmě bych mohl položkám dát prefix a při zpracování ho zase zahodit, ale o to mi tu nejde.

Ten regulár dle mého názoru parsuje akci z GETu, ale při odeslání AJAXem se tam zamotá i POST a vzniká problém. V anotaci té funkce initGlobalParameters() se píše

@throws Nette\Application\BadRequestException if action name is not valid

ale mě jí to vyhodí i když se o jméno akce nejedná …

No, zatím zůstanu u verze 2.0 kde vše funguje tak jak má :)

David Grudl
Nette Core | 8228
+
0
-

Tohle s register globals nijak nesouvisí.

Je tu restrikce, aby poslední segment názvu parametru nezačínal číslem. Je to z toho důvodu, že funkce Presenter::createRequest() & argsToParams(), která se používá při canonicalizaci, převede číselné indexy na klíče dle názvů parametrů příslušné funkce. Nejspíš by bylo možné restrikci zrušit a při canonicalizaci tohle chování zakázat, ale to je jiné téma.

Při vytváření formuláře se každopádně číselné názvy doplňují podtržítkem (čísla by způsobila problémy s JavaScriptovou validací), takže <input type="text" name="1"> vzniknout nemůže, bude tam name="1_".

Z toho důvodu by nikdy k chybě dojít nemělo.

fak
Člen | 48
+
0
-

Tak to Davide prosím dokonči.

Když pro ten samý požadavek klasická verze projde a Ajaxová ne. Měl bys to zakázat i pro tu klasickou, když to není ve standardu.