szakma

A register_shutdown_function esete az ImageCreateFromPNG-vel

Sajnos úgy tűnik, hogy az php GD comagban lévő imagecreatefrompng függvénynek lehet olyan bemenetet adni, amitől úgy hasal el és rántja magával a php-t, hogy utóbbinak már arra sincs ereje, hogy meghívja a register_shutdown_function-el regisztrált kilépő függvényünket.

Aki képeket akar feldolgozni cron-ban php szkript-el, annak jó ezt észben tartani.

form_set_warning()

Vigyázat, ez az aktuális világmegváltó agyszüleményem! A Drupal Forms API előtt használtam néhány másis űrlap generáló rendszert is, de volt egy funkció, amivel soha nem találkoztam, pedig szerintem sok különböző weboldal hasznát venné.

Miután egy felhasználó kitöltöti, és a szervernek visszaküldi az űrlapot, ne csak azt lehessen eldönteni, hogy a kitöltés helye-e vagy sem, hanem legyen egy figyelmezetető, megerősítő funkció is. Úgy tudom elképzelni ezt a legjobban, hogy ha hiba helyett csak figyelmeztetést adunk ki egy mezőre, akkor az űrlap ugyanúgy megjelenik mint hiba esetén, kiemelve a problémás elemeket, de alul a submit mellett, lenne egy Igen, biztos ezt akarom checkbox. Ezt bepipálva már lefutna az űrlap _submit függvénye.

Miért van erre szükség? Azért, mert a hibás- nem hibás eldöntése túl nagy felelősség. Néha vannak veszélyes (vagy szinte bíztosan rossz) űrlap kitöltések, amelyeket nem szabad rögtön feldolgozni, de teljesen elvenni sem lehet egy ilyen kitöltésnek a lehetőségét.

Tengernyi konkrét példát tudnék mondani amikor erre szükség van:

  • Használtautó kereskedő oldal, az árat ezer forintban kell megadni. Erre a felhasználó beírja, hogy 150000. Persze lehet, hogy ez egy 150 milliót érő használt autó, de azért elég valószínűtlen. Jó lenne erre figyelmeztetni.
  • Klasszikus példa, és drupal-ban is számtalan helyen van, a törlés megerősítés (delete_confirm fg.) Ha lenne form_set_warning(), nem kellene plussz egy űrlapot definiálni minden egyes törlés funkcióhoz.
  • Linkeket akarunk tárolni. A http://www.example.com már bent van a rendszerben, mikor valaki hozzá akarja adni a http://example.com–ot, vagy a http://www.example.com/index.php-t.

Persze, most is el lehet érni ezt a funkcionalitást Drupal-ban (lásd delete_confirm), de csak hegesztéssel, egy form_set_warning-al sokkal elegánsabban meg lehetne oldani ezeket a helyzeteket. Ráadásul, amennyire ismerem a Forms API lelkivilágát, ezt nem is lenne túl nehéz beleimplementálni jól.

Kiváncsi vagyok a véleményetekre, nálatok is felmerültek már ilyen igények?

parse_url() alternatíva

HTML-ből kiszedett url-eket dolgoztam volna fel, de a PHP beépített parse_url() függvénye egy warning kíséretében elszáll, ha relatív url-eket adunk meg.

Szintén nem tetszenek neki az olyan URI-k, mint pl. a mailto: vagy ftp://

Írtam egy függvényt, ami úgy dolgozza fel az URL-eket és URI-kat, hogy

  • soha nem száll el warning-al
  • jól kezeli a relatív URL-eket
  • teljes értékű helyettesítője a php parse_url()-nek

Itt a kód, illetve a post végén egy linken le is tölthető. Bárki bármilyen hibát talál, jelezze a hozzászólásoknál, hogy javíthassam.

<?php
function parse_url_relative($url, $component = NULL){
 
$full_rx = '!^
    (?P<scheme>[a-z][a-z0-9\+\-\.]*):/*         # scheme
    (?:(?P<user>[^:@]*)(?::(?P<pass>[^@]*))?@)? # user and password
    (?P<host>[^/\?\#:]*)                        # host
    (?::(?P<port>[0-9]+))?                      # port
    (?P<path>[^\?\#]*)                          # path
    (?:\?(?P<query>[^\#]*))?                    # query
    (?:\#(?P<fragment>.*))?                     # fragment
  $!ix'
;

 
$path_rx = '!^
    (?P<path>[^\?\#]*)                          # path
    (?:\?(?P<query>[^\#]*))?                    # query
    (?:\#(?P<fragment>.*))?                     # fragment
  $!ix'
;

  if (!
preg_match($full_rx, $url, $m)) {
   
preg_match($path_rx, $url, $m);
  }

 
$return = array(
   
'scheme'    => isset($m['scheme'])    ? $m['scheme']    : NULL,
   
'user'      => isset($m['user'])      ? $m['user']      : NULL,
   
'pass'      => isset($m['pass'])      ? $m['pass']      : NULL,
   
'host'      => isset($m['host'])      ? $m['host']      : NULL,
   
'port'      => isset($m['port'])      ? $m['port']      : NULL,
   
'path'      => isset($m['path'])      ? $m['path']      : '',
   
'query'     => isset($m['query'])     ? $m['query']     : '',
   
'fragment'  => isset($m['fragment'])  ? $m['fragment']  : '',
  );

  switch (
$component) {
    case
NULL:
      return
$return;
    case
PHP_URL_SCHEME:
      return
$return['scheme'];
    case
PHP_URL_HOST:
      return
$return['host'];
    case
PHP_URL_PORT:
      return
$return['port'];
    case
PHP_URL_USER:
      return
$return['user'];
    case
PHP_URL_PASS:
      return
$return['pass'];
    case
PHP_URL_PATH:
      return
$return['path'];
    case
PHP_URL_QUERY:
      return
$return['query'];
    case
PHP_URL_FRAGMENT:
      return
$return['fragment'];
  }
}
?>

Az Xdebug lassú és nem hagyja békén a var_dump()-ot

Tamás postján fellelkesülve, én is beállítottam itthon a php debug környezetet (PHPEclipse+xdebug). Eddig megvoltam nélküle, de bizony ha egyszer kipróbáljuk, nehéz lesz megválni tőle. Nélkülözhetetlen segítség a mindennapi PHP/Drupal hekkelés közben.

Az Eclipse-et én nem szerettem, és most sem a szívem csücske, de a PHPEclipse-el együtt egy használható eszköznek mondható. A debug melett kifejezetten hasznos funkció a kód kiegészítés és a gépelés közbeni szintaxis elemzés.

Viszont az Xdebug-os környezettel volt két komoly bajom: egyrészt érthetetlenül lassú egy oldal megjelenítése. Érthetetlen, mert sem az sql szerver, sem az apache (+php+xdebug) sem a böngésző kliens nem pörgette a CPU-t, mégis több másodpercig tartott egy oldal megjelenítése. A másik gond, hogy képtelen voltam rávenni az Xdebug-ot, hogy ne definiálja felül a var_dump() függvényt.

A var_dump()-ot sokat használom, főleg a Drupal devel moduljának dvm() függvényén keresztül. De ha belenyúl az Xdebug, a dvm() használhatatlan lesz. A neten (és az xdebug.org/docs-on!) jópár pletyka terjed, hogy miként lehet ezt hatástalanítani. Találtam én mindent, pl ilyeneket:

xdebug.overload_var_display = 0
// vagy
xdebug.overload_var_dump = 0

Érdekes módon nem működnek. Hosszas kutatás után viszont rátaláltam a megoldára: a nevével ellentétben az xdebug.default_enable nem a teljes xdebug-ot kapcsolja ki/be, hanem csak a megjelenítéssel kapcsolatos funkciókat. Tehát ha kikapcsoljuk, attól még a debug működik. Emellett érdemes még kikapcsolni a html_errors standard php.ini kapcsolót is, a teljesen korrekt működéshez.

A másik gond, ami felmerült, a lassú oldal letöltés. Egy E8500-as procin szerintem nem kéne 2-3 másodpercig tartania egyetlen oldal generálásának. Ezt az xdebug.remote_autostart = On beállítás okozta, ami miatt minden egyes oldaletöltés debug session-ként futott le. Ez felesleges, ki kell kapcsolni a fenti funkciót és ha debugolni szeretnénk, elég a GET paraméterek közé felvenni az XDEBUG_SESSION_START=debug_id változót.

Összegezve a fent leírtakat nekem xdebug-ra a következő recept vált be:

; var_dump felülírás hatástalanítása
xdebug.default_enable = Off
html_errors = Off

; debug funkciók bekapcsolása, de
xdebug.remote_enable = On

; debug session automatikusan ne induljon.
xdebug.remote_autostart = Off

A fenti beállításokkal és Tamás leírásával és linkjeivel, teljesen jól használható debug környezetet lehet kialakítani.

Mindenkinek jó rovarírtást.

Oldalak

Feliratkozás RSS - szakma csatornájára