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]

Dakle, kada ocekujete neku odredjenu varijablu, recimo “username”, pre bilo kakvog procesiranja potrebno je proveriti da li postoji ta varijabla, odnosno da li je definisana. Obicno bi (početnici) radili ovakvu proveru


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 je

magic_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 :)

5 komentara na “Undefined variable - rešenje?”

  1. NIXA

    interesantan pristup … :D


  2. Jelena

    Interesantno, ali ne vidim potrebu za skraćenim if-ovima. Pogotovo ne kada se radi o funkciji.


  3. bluesman

    Na koje skraćene IF-ove mislite?


  4. Jelena

    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.


  5. bluesman

    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 x 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.


Napišite komentar

Molba i napomena: Ako imate želju da komentarišete molim vas da se predstavite. Anonimne komentar brišem ili u najboljem slučaju totalno ignorišem. Uvrede na bilo čiji račun ne tolerišem, ako se ne slažete sa tekstom ili nekim komentarom slobodno i iskreno to napišite ali se suzdržite od uvreda bilo koje vrste.

XHTML: Možete koristiti HTML tagove: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

Ako želite samo da SPAM-ujete, komentar će biti obrisan automatski, a ako vam je iz nekog razloga baš stalo da imate link ovde poslaću vam cenovnik za oglašavanje.