[sr] Undefined variable - rešenje?
Verovatno ste milion puta imali problem sa varijablama u PHP-u koje želite da koristite a ne znate da li su definisane ili šta je korisnik uneo. Uglavnom su rešenja jednostavna ali je kod postajao sve nepregledniji. Postoji jednostavno rešenje ovog “problema”.
[level: begginer, intermediate]
if (isset($_GET['username']))
$username = $_GET['username'];
else
$username = "";
Drugo, malo elegantnije resenje je
$username = isset($_GET['username']) ? $_GET['username'] : "";
Medjutim, ovo proverava samo da li je setovana varijabla, a ne i vrednost varijable. Ako ne dozvoljavate da varijabla bude prazna, koristili bi recimo
$username = empty($_GET['username']) ? false : $_GET['username'];
Problem moze da nastane ako varijabla mora da bude neka od predefinisanih. Recimo, ako proveravata broj telefona, pa operatora, u Srbiji mogu da budu samo 062, 063, 064, 065… (za sada). Kod bi morao da se nastavi:
$operator = empty($_GET['operator']) ? false : $_GET['operator'];
if ($operator != "062" || $operator != "063" || $operator != "064" || $operator != "065")
echo "Invalid operator";
malo elegantnije resenje bi izgledalo ovako:
$operator = empty($_GET['operator']) ? false : $_GET['operator'];
if (!in_array($operator, array("062", "063", "064", "065"))
echo "Invalid operator";
gde proveravamo da li je $operator iz array dozvoljenih.
Opet, postoji problem “quotes”. Znaci, ako je u inputu dozvoljeno uneti navodnike, treba ih pravilno “escape-ovati”, sto znaci da se navodnik ” menja sa ” da bi recimo moglo da se upiše u bazu. Zato je potrebna još jedna provera:
if (!get_magic_quotes_gpc())
$username : addslashes($username);
get_magic_quotes_gpc() proverava da li je ukljuceno automatsko escape-ovanje navodnika ili ne. Ako je isključeno morate ih “ručno” escapeovate funkcijom addslashes() jer ćete u protovnom dobijati myslq grešku ako pokušate da ga upišete u bazu. Pošto se uvek bolje razume na primeru, evo jednog primera:
Korisnik ima polje u koje unosi neki komentar. Tu može recimo da unese:
Omiljena pesma mi je “Let’s lynch the landlord” od Dead Kennedys
Kada bi pokušali da dodamo ovo u bazu, imali bi quoery koji izlgeda ovako:
$komentar = empty($_GET['komentar']) ? false : $_GET['komentar'];
$query = "INSERT INTO komentari VALUES ("".$komentar."")";
Što bi rezultiralo u ovakav query:
"INSERT INTO komentari VALUES ("Omiljena pesma mi je "Let's lynch the landlord" od Dead Kennedys")";
Što bi očigledno dovelo do greške zbog navodnika oko “Let’s lynch the landlord”. Rešenje je da se escape-uju navodnici:
$komentar = empty($_GET['komentar']) ? false : $_GET['komentar'];
$query = "INSERT INTO komentari VALUES ("".addslashes($komentar)."")";
Što bi rezultiralo u ovakav query:
"INSERT INTO komentari VALUES ("Omiljena pesma mi je "Let's lynch the landlord" od Dead Kennedys")";
međutim, ako je uključeno magic_quotes_gpc, automatsko escapovanje navodnika za GET, POST, COOKIE varijable kojim se menjaju svi navodnici (“), apostrofil (‘) i backslashovi () kao i NULL, dobićete dvostruko escape-ovane navodnike:
"INSERT INTO komentari VALUES ("Omiljena pesma mi je "Let's lynch the landlord" od Dead Kennedys")";
Što će u outputu prikazati ovako:
komentar: Omiljena pesma mi je “Let’s lynch the landlord” od Dead Kennedys
Što nismo hteli, pa se zato radi provera da li jemagic_quotes_gpc uključeno.
Valika nauka, a?
Postoji jednostavnije rešenje za ove probleme. Funkcija koja resava večinu ovih problema mogla bi da izgleda ovako
function get_value (&$variable, $default = "")
{
$var = isset($variable) ? trim ($variable) : $default;
return (get_magic_quotes_gpc()) ? $var : addslashes($var);
}
pa onda kada proveravate varijablu, umesto svog onog koda, jednostavno čitate:
$komentar = get_value ($_GET['komentar']);
funkcija uzima referencu varijable $_GET['komentar'], proverava da li je setovana i radio automatski trim() da bi sklonila sve whitespace (space, tab, ...) sa početka i kraja varijable, a zatim ako nije setovana varijabla, automatski joj dodeljuje neku DEFAULT vrednost. Na primer, ako proveravamo državu
$country = get_value ($_GET['country'], "US");
proveravamo da li je izabrana država, ako nije automatski dodeljujemo default vrednost “US”. A kako proveravamo da li je u dozvoljenom opsegu, recimo, kao u primeru za telefon, da li je jedan od dozvoljenih 062, 063, 064, 065? Malo modifikujemo funkciju:
function _get (&$variable, $default = "", $allowed = "")
{
$var = isset($variable) ? trim ($variable) : $default;
if (!empty($allowed) && is_array ($allowed)) {
if (!in_array ($var, $allowed))
$var = $allowed[0];
}
return (get_magic_quotes_gpc()) ? $var : addslashes($var);
}
pa u array $allowed upisujemo šta je dozvoljeno.
$operator = get_value ($_GET['operator'], "064", array("062", "063", "064", "065"));
i ako varijabla $_GET['operator'] nije setovana, dodeljuje joj se default “064”, a i pored toga, bez obzira da li je setovana ili nije, proverava se da li je dozvoljena pa se vraca samo ako je element niza $allowed.
Ono o čemu još morate da vodite računa je upoređivanje stringova u PHP-u, jer nije isto da li je “goran”, “GORAN”, “Goran”... pa bi poziv funkcije:
$ime = get_value ($_GET['ime'], "goran", array("Pera", "Goran"));
vratio $ime = "Pera"; jer se varijabli $_GET['ime'], u svakom slucaju ako nije tacno “Pera” ili “Goran” dodeljuje “Pera”, cak ne i default “goran” jer i “goran” nije u nizu $allowedgde se u stvari nalazi “Goran” što je različito od “goran”.
Znači ni jedno rešenje nije idealno ali vam omogućava bar malo čitljiviji i fleksibilnij kod. Na primer, ako čitate neki input iz formulara koji popunjava korisnik, pišete ovako:
$username = get_value ($_POST['username']);
$password = get_value ($_POST['password']);
$ime = ucfirst(get_value ($_POST['first_name']));
$prezime = ucfirst(get_value ($_POST['last_name']));
$country = get_value ($_POST['country'], "US", array("CS", "YU", "US"));
$subscribe = get_value ($_POST['subscribe'], true);
Naravno, morate i dalje da radite proveru da li je username prazno, ali bar ne morate da proveravate da li je setovano, da ih escapeujete, da proveravate da li je u dozvoljenom range… Bar vam neće izlaziti ona čuvena greška “undefined index username in array $_POST on line …”
Ako neko nađe ovo korisno – slobodno neka komentariše. Ja ovo koristim godinama bez problema, što i vama želim
May 16th, 2005 at 7:20 pm
interesantan pristup …
November 20th, 2005 at 8:10 pm
Interesantno, ali ne vidim potrebu za skraćenim if-ovima. Pogotovo ne kada se radi o funkciji.
November 20th, 2005 at 11:08 pm
Na koje skraćene IF-ove mislite?
November 21st, 2005 at 1:22 am
Recimo:
$var = isset($variable) ? trim ($variable) : $default;
umesto
if(isset($variable))
{
$var = trim($variable);
}
else
{
$var = $default;
}
Nekako uobičavam da “skraćene” uslove koristim samo na mestima gde imam preku potrebu za njima. Funkcija svakako nije to mesto.
November 21st, 2005 at 8:03 am
Skraćenje se ne stavlja kada postoji “preka potreba za tim” već da bi kod bio pregledniji i čitkiji. Vi ste sada upravo upotrebili 8 redova umesto jednog, a kada se pojavljuje slučaj gde varijabla može imate jedno od dve vrednosti zavisno od uslova, onda je ovo “skraćenje” pravi primer čitljivog koda.
Ne kažem da je to vaše nečitko, naprotiv, tako će početnici najbolje razumeti o čemu se radi, međutom kada imate script od 400-500 linija koda, i bar dvadesetak ovakvih uslova, skratili ste kod za 140 linija (20×8 – 20) što nije baš malo i značajno doprinosi čitljivosti scripta.
VARIABLE = (USLOV) ? TRUE : FALSE;
je standardan u skoro svim programskim jezicima i razumljiv je svakom programeru.