2010. május 1., szombat

Átállás (migráció) PHP 5.3-ra 5.2-ről

Számtalan weboldalt fejlesztettem/fejlesztettünk az elmúlt évek során. Azért, hogy a leghatékonyabban tudjunk dolgozni létrehoztam egy keretrendszert, ami mindenféle alap és sűrűn használt funkcionalitást tartalmaz és a keretet használó modulból pár sorban elérhető. Ilyenek a session kezelés, SQL futtatás, sablonok kezelése, callback rutinok és egyéb sablon-vezérlők alkalmazása. De ez a cikk most nem is erről szól. A fejlesztést még 4-es PHP-ban kezdtük, most jelenleg 5.2-es PHP alatt fut minden portálunk. Az elmúlt hónapokban debütált a PHP 5.3.2 és most az Windows-ra való átálláskor úgy döntöttem, hogy erre már ezt a verziót fogom felpakolni. Mondanom sem kell, hogy meglepő problémákba futottam. Az eddigi PHP verzióváltásokat a portáljaink alapvetően jól tűrték, egy-két beállítás után a php.ini-ben és minden makulátlanul működött. Nem úgy, mint most. A PHP 5.3-ra való átállás bizony migrációt (fejlesztést) jelent. Az 5.3-ból ugyanis számos eddig sokat használt (de azért már verziók óta elköszönőnek jelölt) eljárást bevontak a forgalomból, valamint egy-két ini beállítást is feketelistára helyeztek. Ezek a bevont (visszavont, deprecated) eljárások ettől még használhatók, de egy E_DEPRECATED hibát dobnak minden egyes alkalommal, amikor hozzájuk fordul a kód. Lássuk ezeket név szerint (hivatalos lista) és némi magyarázattal:

A visszavont ini paraméterek a következők:
  • define_syslog_variables - a leírás szerint performanciális okokból "javasolják" az elhagyását, ha valaki mégis ilyet szeretne használni, arra ott van a define_syslog_variables() eljárás (ami szintén visszavont)
  • register_globals - hát ezt csak támogatni tudom. Már évek óta "not recommended", hiszen a PHP legtöbb sebezhetősége ebből fakadt, ettől függetlenül mind a mai napig találkozom olyan kóddal, ami feltételezi, hogy be van kapcsolva. Igazából szinte csak időt spórolunk ezzel, hiszen milyen kényelmes, ha a HTTP hívás paraméterei egyből elérhetőek egy változóban, arra viszont sokan nem gondolnak, hogy ezzel a változó értékének tesztelését, inicializálását, stb. is kihagyják a kódból, így sérülékeny, esetleg törhető kódot gyártanak.
  • register_long_arrays - ez is a HTTP változók betöltésének globális változóba történő kezelése, helyette illik a superglobal-ok használata, $_GET, $_POST, stb.
  • safe_mode
  • magic_quotes_gpc
  • magic_quotes_runtime
  • magic_quotes_sybase
  • Comments starting with '#' are now deprecated in .INI files. - hogy miért, ki tudja? mostantól csak és kizárólag a pontosvessző használható erre a feladatra.
Lássuk az eljárásokat:
  • call_user_method() (use call_user_func() instead) - már PHP 4.1 óta visszavont eljárás, remélhetőleg senki sem használja már. A call_user_func szinte ugyanazt a funkcionalitást hozza, más paraméterezéssel. A callback eljárásoknál használjuk, de számos módon segíti a munkát, hiszen stringként adható meg egy-egy eljárás neve és a hozzá tartozó paraméterezés.
  • call_user_method_array() (use call_user_func_array() instead) - mint az előző
  • define_syslog_variables()
  • dl() - runtime tudott extension-öket betölteni, most már nem. Tessék az ini file extension eljárását használni.
  • ereg() (use preg_match() instead) - reguláris kifejezés alapján keres mintát egy stringben. A probléma az, hogy a Perl stílusú reguláris kifejezéseket egy kicsit másképpkell írni, mint hagyományos társaikat, ún. elválasztó jeleket kell alkalmazni. Jelesül a Perl stílusú reguláris kifejezés mindig a delimiterrel kezdődik, ami bármilyen karakter lehet, de jellemzően per / jel. Ez utóbbiban ráadásul ún. tag-eket is lehet használni az utolsó delimiter után, mint például az i betű, ami a mintaillesztést kis-nagybetű érzékennyé teszi, mint az alábbi példában: 
"/^[a-z0-9][a-z0-9_.-]*@[a-z0-9.-]+\.[a-z]{2,4}$/i"
E-mail cím validáció tehát ezentúl:
function validate_email_deprecated($email) {
    if (!eregi("^[[:alnum:]][a-z0-9_.-]*@[a-z0-9.-]+\.[a-z]{2,4}$", $email)) {
        echo 'bad email';
    } else {
        echo 'good email';
    }
}
function validate_email($email) {
    if (!preg_match("/^[[:alnum:]][a-z0-9_.-]*@[a-z0-9.-]+\.[a-z]{2,4}$/i", $email)) {
        echo 'bad email';
    } else {
        echo 'good email';
    }
}
  • ereg_replace() (use preg_replace() instead) - lásd. ereg
  • eregi() (use preg_match() with the 'i' modifier instead) lásd ereg
  • eregi_replace() (use preg_replace() with the 'i' modifier instead) - lásd ereg
  • set_magic_quotes_runtime() and its alias, magic_quotes_runtime() - nem nagyon értem ezt a magic_quotes mizériát, de ezt az eljárást kb. 5 perc alatt lehet megírni, és csak ott használni, ahol értelme van.
  • session_register() (use the $_SESSION superglobal instead) - ahogy javasolja, használjuk a superglobal-t, már 4.1 óta így javasolják
  • session_unregister() (use the $_SESSION superglobal instead) - ahogy javasolja, használjuk a superglobal-t, már 4.1 óta így javasolják
  • session_is_registered() (use the $_SESSION superglobal instead) - ahogy javasolja, használjuk a superglobal-t, már 4.1 óta így javasolják
  • set_socket_blocking() (use stream_set_blocking() instead)
  • split() (use preg_split() instead) - lásd ereg
  • spliti() (use preg_split() with the 'i' modifier instead) lásd ereg
  • sql_regcase() - ha erre valaha is szükséged lesz, használd a link alatt található hozzászólásokban található eljárást
  • mysql_db_query() (use mysql_select_db() and mysql_query() instead) - egy adott query lefuttatása egy adott adatbázisban. A probléma az volt vele, hogy nem ideiglenesen váltott adatbázist, hanem véglegesen, ezért rengeteg hibára adhatott okot. Sokkalta célszerűbb, és okosabb fejlesztői üzemmód, ha az ilyen query-ket a fenti két eljárásra alapozzuk, talán jobban belénk vásődik, hogy ha egyszer kiadjuk a mysql_select_db utasítást, akkor onnan illik is visszaváltani (persze, ha kell), vagy egyszerűen használjuk a select * from database.table szintaxist, ami csak a lekérdezés erejéig használja a másik adatbázis sémát.
  • mysql_escape_string() (use mysql_real_escape_string() instead) - ahogy írja, 4.1 óta célszerűbb az utóbbit használni.
  • Passing locale category names as strings is now deprecated. Use the LC_* family of constants instead. - ez van, sosem használtam ilyet.
  • The is_dst parameter to mktime(). Use the new timezone handling functions instead. - eddig ezzel lehetett állítgatni, hogy az eljrásr használja-e a nyári időszámítást vagy sem, amikor visszaadja a UNIX időt a megadott dátum alapján. Mostantól be KELL állítani a megfelelő timezone értéket a php.ini-ben, eféleképpen: date.timezone = Europe/Budapest a [date] szakaszban.
Én most állok neki PHP 5.3-sítani a keretrendszerünket. A fentiek közül kevés eljárást használok, de úgy érzem lesz vele meló, hiszen: tesztelni, tesztelni, tesztelni. A keretrendszert több mint 50 portál/weboldal használja jelenleg, és pl. a reguláris kifejezéseken alapuló eljárások cseréje, bár egyszerűnek látszik mégis a teljes keretrendszer funkcionalitását érinti.

A migrációt ezért valószínűleg úgy fogom kezdeni, hogy pl. minden ereg eljárást lecserélek egy ereg_migr-re, amit viszont már a fenti szabályok szerint fogok én megírni az új eljárásokkal és a régiekkel egyetemben. Így lehetőségem lesz egy darab konstanssal ki-be kapcsolni az "5.3-as üzemmódot", ha a tesztelés ideje alatt valamilyen oknál fogva mégis cserélnem kell azt az éles szerveren, ahol még az 5.2-es PHP fut.

Pl:

régi kód:

if (eregi("xy",...)) ...

új kód:

function phpMinV($v)
{
   
$phpV = PHP_VERSION;

    if (
$phpV[0] >= $v[0]) {
        if (empty(
$v[2]) || $v[2] == '*') {
            return
true;
        } elseif (
$phpV[2] >= $v[2]) {
            if (empty(
$v[4]) || $v[4] == '*' || $phpV[4] >= $v[4]) {
                return
true;
            }
        }
    }

    return
false;
}

$is53 = phpMinV('5.3');


function ereg_mig( string $pattern , string $string [, array &$regs ]) {
  if  ($is53) return preg_match("/".$pattern."/",...); else return ereg($pattern,...);
}


Azért előbb vagy utóbb érdemes kiírtani az ilyen kódrészeket...

Jó mulatást mindenkinek a migrációhoz!

Nincsenek megjegyzések:

Megjegyzés küldése