Předávání polí z formuláře

Školení, která pořádám

V HTML formulářích lze pomocí atributu <select multiple> vytvořit menu, ve kterém je možné vybrat více položek. Pokud však uživatel skutečně vybere víc položek, naplní PHP proměnnou odpovídající názvu menu pouze poslední vybranou hodnotu. Tento problém se dá řešit pomocí předávání polí z HTML formulářů. Je to velice jednoduché – za hodnotu názvu pole stačí doplnit [] (tedy např. <select name="volby[]">) a PHP z takovýchto formulářových prvků vytvoří pole.

Tento obrat se samozřejmě dá použít u libovolných formulářových prvků, výborně se hodí např. u přepínačů. S využitím vlastnosti, že hranaté závorky nemusí být prázdné, lze šikovně vytvořit i hromadnou editaci více položek v jednom formuláři:

<?php
if (is_array($_POST["nazev"])) {
    foreach ($_POST["nazev"] as $key => $val) {
        mysql_query("UPDATE tabulka SET nazev = '$val' WHERE id = '$key'");
    }
}

$result = mysql_query("SELECT id, nazev FROM tabulka");
while ($row = mysql_fetch_assoc($result)) {
    echo "<input name='nazev[$row[id]]' value=\"" . htmlspecialchars($row["nazev"]) . "\" /><br />\n";
}
mysql_free_result($result);
?>
Jakub Vrána, Výuka, 24.6.2005, diskuse: 30 (nové: 0)

Diskuse

ikona Milan Kryl:

Jen v RSS by to chtělo převádět < na &lt; atd., misto select multiple se mi ve FeedDemonu objevil inputbox ;)

ikona Jakub Vrána OpenID:

Já bych spíš řekl, že to je chyba čtečky. < na &lt; samozřejmě převedené je, ale čtečka se snaží vnitřek <description> interpretovat jako HTML, což by podle mého názoru neměla: "<description> - a plain text description of an item" (http://my.netscape.com/publish/formats/rss-…#description)

T3RMiX:

Škoda, že tenhle článek nevyšel před týdnem. Odhaloval jsem v kódu chybu a jediný co mě tam nedávalo smysl proč mam v name u selectu []. Čímž jsem si zavařil na další půlhodinu hledání, když jsem to elegantně odstranil :) Stejnak dík, mrzí mě že takových blogů není víc :(

Leo:

Problem je jinde - nejsem si jisty, jestli podle specifikace (X)HTML muze byt v hodnote name hranata zavorka, ale skoro urcite ne. Pak musite zpracovavat hruby vstup do PHP, co je u POSTu mirne slozitejsi nez u GETu, ale jde to. Vic manual PHP (promenne z formularu). Leos Ondra

ikona dgx:

doplním, že jde o parsování file_get_contents('php://input'), což je vychytávka od verze PHP 4.3.0 - http://www.php.net/wrappers.php

ikona dgx:

...a nebude fungovat při enctype="multipart/form-data"

ikona spaze:

zajimavy je, ze ale validator(.w3.org) nijak neprotestuje na name="foo[]" jak v HTML 4.01 trans, tak v XHTML 1.0 strict.

Leo:

Vychazel jsem z tohohle:

http://www.w3.org/TR/html4/types.html#type-cdata

ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").

Leo

Leo:

Mozna je to tak, ze validator to kontroluje jen proti DTD a pokud jsem to pochopil, tak DTD povolene znaky v name a id neresi. Leo

Leo:

Konkretne

http://www.php.net/manual/cs/language.variables.external.php

a zvlast komentare dole, Leo

ikona spaze:

ano, takze podle vseho [] je v poradku ;)
protoze name je CDATA, viz ty odkazy, ktere uvadis.

Gimli2:

Input se zjevil i v RSS ctecce v Opere 8.0. A chybel tam pote link primo na clanek. (bylo nutne zobrazit primo kod hlavicky prispevku v RSS)

ikona Jakub Vrána OpenID:

V tom případě to prosím nareportujte autorům Opery. To bych pravděpodobně musel vypisovat &amp;lt;, což nechci, protože ve slušných čtečkách by se to zobrazilo jako &lt;.

Andrew:

Abilon dělá to samé, tedy zobrazí prvek, ale nemá už problémy s dalšími věcmi (jako linky atd.)

Michal Molhanec:

ono u toho rss 0.9x neni uplne jednoznacny, jak je to s HTML v description, proto je IMHO mnohem lepsi pouzivat 2.0, kde je to jasne dany

ikona llook:

Validní to sice není (znaky [] v NMTOKEN), ale koho to zajímá, když to funguje.
Přesto si myslím, že multiple select by se neměl používat. Zkuste se optat několika běžných uživatelů, jak označí několik položek. Radši spoustu checkboxů ve scrollovacím boxíku.

Mimochodem ty entity si na značky převádí snad většina čteček, včetně těch webových. Jednou jsem do titulku napsal <table> a několika agregátorům jsem dočasně rozhodil layout :-)

ikona dgx:

používám to v admin. rozhraních, které obsluhují "poučení" uživatelé. Tam je to výhoda.

Leo:

"Validní to sice není (znaky [] v NMTOKEN), ale koho to zajímá, když to funguje."

Ja jenom nerad pro jednu technologii prznim jinou :-) Leo

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL: Reakce na: Leo

Tomáš:

Já nevím, ale podle mě je u všech formulářových prvků atrbibut name typu CDATA a ten přece může pbsahovat [], ne?

Tomáš:

Jo a při každém odeslání přízpěvku mi zůstane Opera vyset a stránka se nenačte, i když přízpěvek se odešle, musím se ale ručně vrátit na článek. Nevíte, někdo v čem je problém?

ikona Jakub Vrána OpenID:

Problém se mi podařilo reprodukovat, ale nezjistil jsem příčinu. V Opeře je volba "Enable automatic redirection", ale ta je defaultně zapnutá a měl jsem ji zapnutou i já.

Možná to bude souviset s opravou chyby http://secunia.com/advisories/15423/?

ikona spaze:

me to dela taky. A delalo to i v 8.0, ve statusbaru zustane "Completed request to php.vrana.cz" a to je vse.

ikona dgx:

Už jsem na to asi přišel - odstraň z redirectu hash (tedy #a-text-za-nim)

ikona Jakub Vrána OpenID:

Díky za radu, v Opeře jsem to vypnul, ale smysl tohoto omezení mi moc jasný není.

ikona spaze:

pokud je to redirect pres Location: pak je smysl uveden v RFC, #anchor do teto hlavicky nepatri. Nicmene staci jej uvest do "puvodni" hlavicky, priklad:

form action="uloz.ext#sem"
uloz.ext: Location: stav.ext a klient by mel skocit na stav.ext#sem

ikona Jakub Vrána OpenID:

Díky za objasnění, zase jsem se něco nového dozvěděl.

Problém je v tom, že kotvu se dozvím, až když zprávu uložím, takže bych to musel vyřešit trochu jinak:

článek: <form action="diskuse.php#new">
diskuse.php: <?php header("Location: $url?new=$id"); ?>
článek: <?php if ($id == $_GET["new"]) echo "<a name='new'></a>"; ?>

Zdeněk Bouška:

Toto rešení však v Opeře nefunguje, pokud je URL v hlavičce Location stejné jako URL článku.

ikona spaze:

A nějakej nápad, jak to fixnout/obejít?

Guardian:

Dobrý den,
s PHP jsem začal nedávno a tak Vám můj dotaz asi bude připadat hloupý, ale zkusím to.

Snažím se vytvořit něco jako osobní minidatabázi filmů co mám doma. Součástí by měla být funkce, která:
1. z html multiple select formuláře (nebo povícero checkboxů, to je asi jedno) vezme hodnoty např. pro žánr filmů
2. poskládá dohromady sql dotaz, který se tabulky 'movies' se sloupci movie_name, style_id (a plno dalšími) kde style_id je provázaný s další tabulkou styles (style_id, style_name) zeptá na filmy (movie_name), které mají odpovídající styl vybraný ve formuláři (style_name).

Nedokážu to už pár dní rozchodit, asi jsem hlupec -/

ikona Jakub Vrána OpenID:

Pokud má mít jeden film (z tabulky movies) více žánrů (z tabulky styles), tak by měla existovat tabulka movies_styles, kde bude (movie_id, style_id).

Ve zpracování formuláře se pak bude pracovat pouze se style_id, style_name se pouze zobrazí:

<label><input type="checkbox" name="styles[]" value="{$style_id}"> {$style_name}</label>
avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.