Společný formulář pro editaci a vložení záznamu
Školení, která pořádám
Pokud ve webové aplikaci chceme upravovat záznamy uložené v databázi, je potřeba vytvořit formulář pro úpravu a vložení záznamu. Nejpozději po vytvoření prvních tří formulářů asi každému dojde, že jsou si natolik podobné, že by se daly sjednotit do jednoho. Jak to řeším já?
<?php
// výpis dat - soubor tabulka.php
if (isset($_GET["insert"])) {
echo "<p><b>Záznam byl v pořádku uložen.</b></p>\n";
}
echo "<p><a href='tabulka_1.php'><i>nový záznam</i></a></p>\n";
$result = mysql_query("SELECT * FROM tabulka");
while ($row = mysql_fetch_assoc($result)) {
echo "<p><a href='tabulka_1.php?select=$row[id]'>" . htmlspecialchars($row["nazev"]) . "</a></p>\n";
}
mysql_free_result($result);
?>
<?php
// úprava dat - soubor tabulka_1.php
if ($_POST) {
$set = array();
$set["nazev"] = "'" . mysql_real_escape_string($_POST["nazev"]) . "'";
$set["cena"] = intval($_POST["cena"]);
// další položky spolu s případným ošetřením dat
if (isset($_GET["select"])) {
array_walk($set, create_function('&$val, $key', '$val = "$key = $val";'));
$result = mysql_query("UPDATE tabulka SET " . implode(", ", $set) . " WHERE id = " . intval($_GET["select"]));
} else {
$result = mysql_query("INSERT INTO tabulka (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")");
}
if ($result) {
header("Location: tabulka.php?insert=1");
exit;
}
echo "<p><b>Při zpracování došlo k chybě.</b><!-- " . mysql_error() . " --></p>\n";
} elseif (isset($_GET["select"])) {
$row = mysql_fetch_assoc(mysql_query("SELECT * FROM tabulka WHERE id = " . intval($_GET["select"])));
} else {
$row = array(); // nastavení výchozích hodnot
}
?>
<form action="" method="post">
<p>Název: <input name="nazev" value="<?php echo htmlspecialchars($row["nazev"]); ?>" maxlength="50" /></p>
<p>Cena: <input name="cena" value="<?php echo htmlspecialchars($row["cena"]); ?>" maxlength="9" /></p>
<p><input type="submit" value="Uložit" /></p>
</form>
Souboru tabulka_1.php
(_1
znamená, že soubor slouží ke zobrazení jednoho záznamu) se předá v parametru select
hodnota primárního klíče editovaného záznamu. Pokud se jedná o vložení záznamu, tak tento parametr předán není. Skript podle toho nastaví proměnnou $row
, kterou používá ve formuláři. Po odeslání formuláře metodou POST se tato data uloží. Všimněte si, že atribut action je prázdný – to znamená, že se pro zpracování formuláře použije stejné URL včetně parametrů, takže hodnota parametru select
se automaticky předá dál. Při zpracování formuláře se naplní proměnná $set
, která se použije pro uložení dat. Poněkud kryptická funkce array_walk zajistí překlad pole do tvaru používaného příkazem UPDATE. Pokud nedojde k chybě, provede se přesměrování zpět na výpis hodnot (spolu s předáním parametru informujícím o výsledku), jinak se vypíše chybová hláška a naplní se pole $row
tím, co zadal uživatel. Všimněte si, že SQL chyba se vypisuje do HTML komentáře, což neruší uživatele, ale informovaný člověk se o ní dozví – ve veřejně dostupných formulářích by se nicméně chyba neměla z bezpečnostních důvodů vypisovat vůbec.
Mazání záznamu by bylo o poznání jednodušší – odkaz lze umístit jak na stránku výpisu, tak na stránku editace, zpracování je přímočaré.
Diskuse
Petr:
Jakube díky za užitečné informace, jen pro nás začátečníky by bylo hodně užitečné vytvořit jednoduchou, funkční ukázku příkladu.
Já myslel, že příklad je sám o sobě jednoduchou funkční ukázkou - stačí první výpis kódu (nadepsaný "soubor tabulka.php") uložit do souboru tabulka.php, další dva výpisy pod sebe do souboru tabulka_1.php a po doplnění připojení k databázi a výpisu HTML hlaviček by to mělo fungovat.
Skript používá tuto tabulku:
CREATE TABLE tabulka (
id int NOT NULL AUTO_INCREMENT,
nazev varchar(50) NOT NULL,
cena int NOT NULL,
PRIMARY KEY (id)
);
Biker:
Zdar.lidi, hele jsem začatečnik,mužete mi někdo prosim napsat odpověď - nejlepe kod jak na tohle - po doplnění připojení k databázi a výpisu HTML hlaviček by to mělo fungovat.(viz první příspěvek nahoře)
díky
<em>anonymní</em>:
Pěkně uděláno, ale při posílání hlaviček header("Location: ") je problém, že předtím nesmí být odeslána žádná jiná hlavička. Tím se komplikuje použití totho scriptu jako vloženého (include("tabulka_1.php");).
shion:
reseni:
ob_start();
zdenek:
doplnil bych jeste nejakou fci na zmenu nazvu submitu pro upload ci edit pro prehlednost
Techi:
Taková hustá vychytávka! Že mě to nenapadlo taky :D
Techi:
Dovolil sem si trochu pozměnit kód, aby byl ještě přítulnější, stačí takhle jedna univerzální funkce...
<?php
/**
* ModifyTable
*
* This function can easy modify table (insert or update line)
*
* @param $table target SQL table
* @param $set array with items to update/insert
* @param $condition SQL condition if UPDATE table
* @param $delete TRUE if delete line(s)
* @return id of last inserted line
*/
function ModifyTable($table, array $set, $condition = "", $delete = FALSE)
{
if($delete)
{
new CQuery("DELETE FROM $table WHERE $condition");
}
// insert string into slashes
array_walk($set, create_function('&$a', '$a = "\'".AddSlashes($a)."\'";'));
if(!Empty($condition))
{
array_walk($set, create_function('&$val, $key', '$val = "$key = $val";'));
new CQuery("UPDATE $table SET " . implode(", ", $set) . " WHERE $condition");
}
else
{
new CQuery("INSERT INTO $table (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")");
return mysql_insert_id();
}
}
?>
kuba:
Ten postup v článku jsem zprovoznil a je celkem pochopitelný, ale tenhle příklad - z toho jsem na větvi. Vůbec nevím jak bych ho zkloubil s ukázkou z článku. Chtěl bych ale mít i možnost mazání z tabulky. Poradil by někdo, jak to jednoduše začlenit, nebo jak využít předchozí příklad - trochu popsat. Dík
24k:
zajímavé a jak se to bude resit pokud updatujete tabulku a pouzivat napr funkce?
* lastupdate=NOW()
apod. ??
Jakub Vrána :
Zcela stejně: <?php $set["lastupdate"] = "NOW()"; ?>
24k:
jak je mozne ze se to provede kdyz ta funkce bude v uvozovkach? pokud bych to napsal takto primo do SQL
<?php
$sel=mysql_query("udpate bla bla set lastupdate='NOW()'");
?>
tak je zcela jasny parse error. Muzete mi to objasnit, stale tomu nejak nerozumim. A diky za rychlou odezvu :)
Jakub Vrána :
Výsledný dotaz bude <?php $result = mysql_query("UPDATE tabulka SET lastupdate = NOW()"); ?>. Žádné apostrofy tam nejsou.
24k:
Aha promin, spatne jsem si to precetl. Ted jeste premyslim
zkusil jsem toto:
<?php
$set = array();
$set["A"] = "'hodnota1'";
$set["B"] = "NOW()";
$result = ("UPDATE tabulka SET " . implode(", ", $set) . " WHERE id = '1'");
echo $result;
?>
a to mi vrati -> UPDATE tabulka SET 'hodnota1', NOW() WHERE id = '1'
Nemelo by to vracet i klice pole?
Jakub Vrána :
Člověče, dávej trochu pozor a čti pečlivěji. Ve větvi pro UPDATE je důležitý kód <?php array_walk($set, create_function('&$val, $key', '$val = "$key = $val";')); ?>, který hodnoty prvků pole převede z "val" na "key = val".
24k:
Du si lehnout, chripka a zbrklost mi nesvedci.Thx
Techi:
Mate pravdu, ze funkce NOW() se hodi do uvozovek, tj. bude se s ní pracovat
jako se stringem, ale nenapadlo mě, že při vkládání/editování používáte často sql funkce
Já jsem zvyklej na PHP ekvivalenty...
Používam tuhle funkci v hodně skriptech, docela dost mi to zpřehlední dotaz a nemusíte jak blbci se patlat s uvozovkama a addslashes()... :)
Jediný co jsem upravil je, aby to akceptovalo NULL
Jinak je funkce v pořádku, kdo mi nevěří, ať se podívá na výslednej dotaz :)
new CQuery() - je jenom moje pomocná MySQL třída, hází mi výjimky...
<?php
/**
* ModifyTable
*
* This function can easy modify table (insert or update line)
* all variables are added into slashes and dangerous characters are escaped
* NULL pointers are re-transformed to NULL in SQL language
*
* @param $table target SQL table
* @param $set array with items to update/insert
* @param $condition SQL condition if UPDATE table
* @param $delete TRUE if delete line(s)
*
* @return id of last inserted line in case of INSERT operation
*/
function ModifyTable($table, array $set, $condition = "", $delete = FALSE)
{
if($delete)
{
new CQuery("DELETE FROM $table WHERE $condition");
}
// insert string into slashes and re-transform NULL
array_walk($set, create_function('&$a', 'if(isset($a)): $a = "\'".AddSlashes($a)."\'"; else: $a = "NULL"; endif;'));
if(!Empty($condition))
{
array_walk($set, create_function('&$val, $key', '$val = "$key = $val";'));
new CQuery("UPDATE $table SET " . implode(", ", $set) . " WHERE $condition");
}
else
{
new CQuery("INSERT INTO $table (" . implode(", ", array_keys($set)) . ") VALUES (" . implode(", ", $set) . ")");
return mysql_insert_id();
}
}
// příklad
$set = array();
$set['hotel_name'] = "Corinthia Towers";
$set['stars_count'] = 5;
$set['fk_hgr'] = NULL;
ModifyTable("hotels", $set, "pk_hot = $_REQUEST[hotel]");
?>
Techi:
Teda proto jsem napsal tuhle funkci, abych nemusel všude psát apostrofy... Jakubova verze právě uvozovky automaticky nedělá...
Jakub Vrána :
Ještě bys měl dát pozor na $_REQUEST["hotel"] v podmínce. Trestuhodně se spoléhá na to, že to bude vždy číslo.
Matěj:
jestli to dobře chápu, tak ten formulář slouží pro vkládání i editaci. V tom případě by to chtělo ale ošetřit ty hodnoty value u prvků, protože při vkládání nebudou definovány.
Jakub Vrána :
Jak je uvedeno v patičce, skripty předpokládají nastavení error_reporting = E_ALL & ~E_NOTICE, takže nedefinovanost položek pole nevadí.
Pavel:
trochu pozdě k původnímu tématu ale ta patička je teda hodně daleko od těch skriptů musel jsem si dát hledání na stránce abych ji našel
Michal:
Chtel sem se zeptat jak je mozne ze mi nefunguje cast kodu s Update ale vzdy se mi vlozi uplne novy zaznam???nevite v cem by mohl byt problem??rad bych toto pouzil..Dekuji
Michal Krkavec:
Ahoj, abych ozivil starou diskuzi...
Trochu me mate, proc se v prikladu pouziva <?php $_REQUEST["select"] ?> a ne primo <?php $_GET["select"] ?>? Ma to nejaky vyznam? Mne to prijde (kdyz ne rovnou spatne) jen na zmateni nepritele. Diky. MK
Pavel:
Díky přesně tohle jsem potřeboval jako inspiraci :-).
Já používám ještě další stav - Copy který vytvoří nový záznam se stejnými hodnotami - uživatel si změní třeba jen jedno pole z mnoha.
Diskuse je zrušena z důvodu spamu.