Různé způsoby psaní kódu

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

V závislosti na nastavení různých konfiguračních direktiv a požadované bezpečnosti se kód v PHP dá psát velice rozmanitým způsobem. Třeba ve článku Společný formulář pro editaci a vložení záznamu se dají pro tutéž věc použít tyto dva různé zápisy kódu:

<?php
mysql_query("INSERT INTO tabulka VALUES ('$nazev', $cena)");
mysql_query("INSERT INTO tabulka (nazev, cena) VALUES ('" . mysql_real_escape_string($_POST["nazev"]) . "', " . intval($_POST["cena"]) . ")");
?>

První způsob předpokládá zapnutou direktivu register_globals, nepočítá s možností přidání dalších sloupců do tabulky a zcela nestoudným způsobem důvěřuje datům od uživatele – buď počítá se zapnutou direktivou magic_quotes_gpc nebo věří tomu, že uživatel do jména nezadá apostrof. Dále počítá s tím, že uživatel zadá číselnou cenu, takže je každopádně náchylný k SQL Injection. Druhý způsob je naopak při zapnuté direktivě magic_quotes_gpc pečlivý až moc, data budou ošetřena dvakrát – místo funkce addslashes by tedy bylo lepší volat funkci typu gpc_addslashes.

Podobně se dá více způsoby vypsat i editační políčko:

<input name="nazev" value="<?= $row[nazev] ?>">
<input name="nazev" value="<?php echo (isset($_GET["select"]) ? htmlspecialchars($row["nazev"]) : ""); ?>">

První způsob předpokládá zapnutou direktivu short_open_tag a vypnuté hlášení chyb úrovně E_NOTICE hned ze dvou důvodů – kvůli použití nedefinované konstanty nazev místo řetězce "nazev" a kvůli neexistujícímu klíči v poli v případě vložení záznamu, navíc kvůli neošetření speciálních znaků trpí rizikem XSS.

Další zdánlivě nevinný příklad je ve výukových textech často použit pro ukázku práce se soubory.

<?php
$pocitadlo = file_get_contents("pocitadlo.dat");
$fp = fopen("pocitadlo.dat", "wb");
fwrite($fp, $pocitadlo+1);
fclose($fp);
?>

Pokud však není doplněn o informaci o přístupových právech a především o riziku, které plyne z paralelního zpracování jednotlivých požadavků, takže u něj chybí alespoň zmínka o funkci flock, tak se mi jeví jako nebezpečný. Při nešťastném pořadí zpracování požadavků totiž může dojít v lepším případě k tomu, že se nějaké přístupy nezapočítají, v horším dokonce k tomu, že se počítadlo čas od času vynuluje. Lepší mi přijde raději zmínit, že soubory se na webu pro ukládání dat z uvedených důvodů nehodí a vhodnější je data ukládat do databáze.

Při výkladu základů PHP to přednášejícímu značně komplikuje život, ale oč jednoduší je popsat Jmenujete se <?= $jmeno ?> než Jmenujete se <?php echo htmlspecialchars($_GET["jmeno"]); ?>, o to složitější situaci budou mít posluchači v reálném světě.

Jakub Vrána, Výuka, 26.12.2005, diskuse: 14 (nové: 0)

Diskuse

houba:

Me vzdycky dojme, s jakym neuveritelnym zaujetim se prehrabujete v tom muzeu mrtveho PHP, musite byt zrejme opravdu velky fanda, kdyz se s takovou laskou venujete tematu, ktere mi pripomina asi neco jako kdyz na PC implantuje hry ze starych osmibitaku :)

ikona llook:

Podle mě by to pro přednášejícího nemělo být o nic obtížnější, ale trvalo by to dýl. Takže by se nestihlo probrat tolik témat a kurz by nevypadal tak lákavě.

Trochu mě mrzí rostoucí popularita vypínání krátkých značek. PHP je coby šablonovací jazyk už tak ve srovnání s jinými šablonovacími jazyky (JSP, ASP.NET) nic moc a s vypnutými short_open_tag je na tom ještě hůř.

tark:

Náhodou je dobrý upozorňovat na základní věci, před pár měsíci jsem opravdu psal stylem začátečníka, který by to tu občas měl číst. :-)

Každopádně zrovna na tyto věci doporučuju si napsat vlastní funkce (sám je mám a dost využívám). Třeba:

<?php
$data
= array('prijmeni' => $prijmeni, 'jmeno' => $jmeno);
$db->insert('lide',$data);
?>

Viz můj databázový layer: http://continuer.nfo.sk/24-php-databazove-layery.html

<?php
function ifKeyExistsReturnIt($key,$arr,$returnfalse=false,$objectvar=false) {
    if(array_key_exists($key,$arr) && !$objectvar)
        return $arr[$key];
    elseif(isset($arr->{$key}) && $objectvar)
        return $arr->{$val};
    else
        '';

    if($returnfalse)
        return false;
}

$data = array('jmeno' => $jmeno,'prijmeni' => $prijmeni);
echo
ifKeyExistsReturnIt('jmeno',$data);
?>

Speedy:

Notice: Undefined variable: prijmeni in c:\program files\easyphp1-8\www\pokus.php on line 2

Notice: Undefined variable: jmeno in c:\program files\easyphp1-8\www\pokus.php on line 2

Fatal error: Call to a member function on a non-object in c:\program files\easyphp1-8\www\pokus.php on line 3

tohle mi to napsalo kdyz jsme napsal to co je vyse uvedeno :-)

Leo:

"Trochu mě mrzí rostoucí popularita vypínání krátkých značek."

Me ne. V situaci, kdy mate kratke znacky, a na webhostingu zmeni nastaveni u short tags na Off tak nejenom, ze vam prestanou skripty behat, ale zdrojovy php kod se dostane neinterpretovany az do prohlizece. Opravdu tohle chcete doporucovat? Pokud chcete sablony, pouzivejte sablony (treba TemplatePower nebo neco na nem postavenyho). Leo

ikona llook:

Používám šablony, šablony v jazyce PHP. Nechci se vzdát možnosti v šabloně udělat něco krátce PHPkem. Podobně by asi Javisté nebyli nadšeni, kdyby z příští verze JSP zmizeli skriptlety.

Myslím, že málokterý webhoster si dovolí vypnout krátké značky pro celý server. Už proto, že spousta existujících aplikací by klekla. Přinejhorším je tu Apache direktiva php_flag a volbu short_open_tag lze nastavit adresář od adresáře různě.

Ale pokud jde o to, nabídnout uživateli upravit si layout, pak jsou lehkotonážní šablonovací systémy (jako Template Power) namístě.

anode:

Já myslím, že to je docela přirozený vývoj, napřed se dovědět, jak se to dá co nejjednodušeji udělat, a později zjistit, že to vlastně nebylo úplně dokonalé. Tohle je tak všude. Člověk se seznámí s tématem a pak ho dál studuje do hloubky.
Pokud jde o short tags, nic bych proti nim neměl, kdybych měl kontrolu nad nastavením serveru, na kterém běží moje skripty. Navíc <? se používá třeba i pro XML, takže nějaké rozlišení je na místě.

ikona dgx:

Měl bych k tomu trošku jiný přistup. Přednášející by měl vysvětlit, že z určitých historických důvodů existují direktivy, které kdysi měli programátorům zjednodušovat život a dnes jej komplikují. Minimálně tím, že jejich nastavení často nemohou ovlivnit. A také tím, že se na jejich nastavení nemohou spolehnout, protože ji může občas někdo změnit.

Poté by přednášející měl dodat, že se s těmito direktivami stejně do budoucna nepočítá a předvést fragment kódu, který tyto direktivy obejde už dnes. Všechny $_POST, $_GET, atd odslashuje, je-li třeba, a tak dále.

No a nakonec už může pokračovat s čistým stolem. Vysvětlit, proč je třeba data při vkládání do databáze slashovat, proč je třeba je při vypisování do HTML ošetřit funkcí htmlSpecialChars() atd.

Andrew:

Ano, jenže Jakub podobné věci řešil už dřív a podrobněji, takže stůl si již z velké části vyčistil.

ikona spaze:

K tomu prvnímu, ale přesto trochu mimo, doporučovaný způsob provádění dotazů do db se teď začínají stávat prepared statements, ať už nativní nebo emulované. Krom PDO se dají použít jiné knihovny, dibi, Creole atp. Nicméně závěr je takový, že již žádné addslashes(), mysql_real_escape_string(), PDO::quote(), pg_escape_*() apod.

J.:

Prilis nechapu ten druhy priklad

<input name="nazev" value="<?php echo (isset($_GET["select"]) ? htmlspecialchars($row["nazev"]) : ""); ?>">

$_GET["select"] ma byt co? K cemu to slouzi?

lukas:

Ja zase nechapu proc se tady porad pouziva addslashes(), to preci neni funkce pro slashovani dat do db, ne?

Proc ne mysql_escape_string(), kdyz jsou priklady pro mysql. A jak velke zlo je pouzivat addslashes() prave pro toto.

ikona Jakub Vrána OpenID:

Teoreticky to je správnější, ale u MySQL na tom nesejde, viz http://php.vrana.cz/obrana-proti-sql-injection.php#d-70.

JuJu:

nudný nijak mne to nezaujalo!!!! podle mne místamaVadný

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 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.