php

Diff3 – az „elfelejtett” csodafegyver konfigurációs fájlok frissítésére

Nem tudom Ti hogy vagytok vele, de nekem bizony majd minden napra jut valamilyen használt eszköznek a verzió frissítése. Ez legtöbbször Drupal-t jelent, de van amikor Awstats-ot, phpMyAdmin-t, valami webmail scriptet, stb …

Namármost ezeknek a programoknak közös jellemzőjük, hogy van hozzájuk egy configurációs minta fájl, amit még a telepítéskor át kell nevezni és tesre kell szabni.

Frissítéskor a testreszabott, beállított konfig fájlokat természetesen nem írjuk felül, ezek érintetlenül maradnak. Igen ám, de az eredeti alapértelmezett konfigurációs fájlok néha megváltoznak, általában egy-egy új opcióval bővülnek, vagy csak a kommenteket egészítik ki a fejlesztők.

Szóval engem mindig is zavart, hogy a régi telepítések config fájljai nem követik az új verziók frissítéseit. Annyira zavart, hogy el is kezdtem megoldást keresni. És ahogy ez lenni szokott az open source világában, hamar kiderült, hogy másokban már sokkal korábban felmerült ez a probléma, sőt már réges régen meg is oldották. A programot ami segíteni fog nekünk elhárítani ezt a problémát, úgy hívják hogy diff3. A használati útmutatója (man page) teljesen világos, én most csak a fenti esetre kihegyezve mutatom be a paraméterezését.

A diff3 használata konfig fájlok összehasonlítására

Először ellenőrizzük, hogy nincs-e ütközés a módosításokban:

diff3 -x REGI_TESTRESZABOTT REGI_DEFAULT UJ_DEFAULT

-x paraméter után három fájlnevet vár, a régi testreszabott konfig fájl, a régi eredeti konfig fájl és az új eredeti fájl. Ha üres a parancs kimenete, akkor kell örülni, akkor nincs ütközés.

A fenti három fájl segítségével hozzuk létre az új konfig fájlt, amely tartalmazza mind a mi módosításainkat, mind pedig fejlesztők módosításait.

diff3 -m REGI_TESTRESZABOTT REGI_DEFAULT UJ_DEFAULT > UJ_TESTRESZABOTT

Ha az első lépésben volt ütközés, akkor az -m kapcsoló elvégzi a migrálást.

Ezek után én még egy sima diff-el ellenőrizni szoktam, hogy minden rendben ment-e, mondjuk így:

diff -y --suppress-common-lines UJ_DEFAULT UJ_TESTRESZABOTT

A kimenetből jól látszik, hogy az új konfigurációs fájlba átvezette a diff3 a régi változtatásokat.

The Drupal way

Az imént leírtak a default.settings.php és a settings.php-re vonatkoztak. De ugyanezt a módszert szoktam használni a .htaccess fájl és a robots.txt frissen tartására is.

Persze csak kis verzió ugrásnál, pl. 7.0-ról 7.1-re, főverzió ugrásnál, pl. 6.0-ról 7.0-ra, ennél azért több munkára lesz szükség :)

Másra is használható

Természetesen másra is használható a diff3: ha egy fájlt két külön irányba módosítanak, mert mondjuk ketten dolgoznak ugyanazon a forráskódon, akkor a diff3 egyszerűen összefésüli a módosításokat. Már amennyiben nincs közvetlen ütközés a módosítások között.

.HU domain ellenőrzés host névből

Szükségem volt arra, hogy egy adott string-ről eldöntsem, érvényes magyar (.hu) domain név-e avagy sem. Utánajártam a témának, és kiderítettem, hogy melyek a pontos szabályok .hu domain regisztrációja esetében:

  • A domain név csak angol kisbetűket (a-z), számokat (0-9), kötőjelet (-) és magyar ékezetes kisebetűket (áéíóöőúüű) tartalmazhat.
  • Az ékezetes domain neveknek létezik, egy un. IDN formával alakja, amely kódolt formában tartalmaz az ékezetes karaktereket. Ezek a domain nevek xn-- karakterekkel kezdődnek.
  • Nem lehet rövidebb 2 karakternél, és nem lehet hosszabb 40 karakternél. (Nincs infó, hogy az ékezetes karakterekkel kell-e számolni, vagy az eltérő hosszúságú IDN.)
  • Másodszintű közdomaineket (pl. info.hu) nem lehet regisztrálni, de eléjük egy harmadszintű nevet lehet regisztrálni (pl. edgarpe.info.hu érvényes lenne.)
  • Vannak védett nevek (pl. www) amelyeket nem lehet regisztrálni sem másod, sem harmad szinten. A net és az internet, bár védett neveke, a net.hu és az internet.hu domainek mégis lézetnek.
  • Vannak zárolt domain nevek (pl. turizmus.hu), amelyeket nem lehet regisztrálni.
  • Jelenleg (2012. március 12.) 31 darab másodszintű közdomain van, 28 darab védett név, és 28 darab zárolt név.

Több időt töltöttem el a szabályok kinyomozásával és a php nyelvű teszt függvény megírásával, mint amennyit szerettem volna.

Megosztom itt is, ha valakinek spórolok vele pár órát, már megérte.

Végül kicsit többet oldottam meg, mint egy ellenőrző: a függvény bemenete egy hostnév, visszatérési értéke a hostból kinyert domain név, vagy FALSE, ha nem érvényes a név. Utóbbi esetben a referencia szerínt átadott második $error paraméterben meg is mondja, mi volt a gond. Tehát pl. a valami.edgarpe.hu bemenetre, a válasz edgarpe.hu lesz, a valami.info.edgarpe.hu bemenetre pedig edgarpe.info.hu lesz a válasz.

Kizárólag .HU TLD domain nevekre működik.

Végül egy tipp: ha nem host név áll rendelkezésre, hanem teljes URL akkor érdemes lehet használni a parse_url php-s függvény átírását is, ritkábban hasal el rossz bemenetekre.

Itt a kód, de letölthető formmában is megvan az oldal alján:

<?php
/**
 * .HU domain név ellenörző. Ellenörzi, hogy egy adott host érvényes magyar .hu
 * domain-hez tartozik-e.
 *
 * Figyelembe vett szabályok:
 * - a domain név hossza (min 2, max 40 karakter)
 * - érvényes karakterek (a-z, 0-9, -, áéíóöőúüű)
 * - kötőjel szabályok a név elején, közepén és végén
 * - másodszintű közdomainek
 * - védett nevek
 * - zárolt nevek
 *
 * @param $host
 *   Host név, amely feltételezhetően egy érvényes .hu domain névhez tartozik.
 * @param $error
 *   Referencia szerint átadva. Hibaüzenet, ha a host nem .hu domain része.
 * @return
 *   A domain név (string) amihez a $host tartozik, vagy FALSE ha téves.
 */
function domain_from_host($host, &$error = NULL) {
 
$level2 = array(
   
'co', 'info', 'org', 'priv', 'sport', 'tm', '2000', 'agrar',
   
'bolt', 'casino', 'city', 'erotica', 'erotika', 'film', 'forum', 'games',
   
'hotel', 'ingatlan', 'jogasz', 'konyvelo', 'lakas', 'media', 'news',
   
'reklam', 'sex', 'shop', 'suli', 'szex', 'tozsde', 'utazas', 'video',
  );
 
 
$protected = array(
   
'ac', 'arpa', 'biz', 'co', 'com', 'dns', 'email', 'e-mail', 'firm', 'ftp',
   
'gov', 'ind', 'info', 'internet', 'iskola', 'mail', 'mx', 'net', 'nom',
   
'ns', 'nui', 'org', 'pp', 'priv', 'sport', 'tm', 'web', 'www',
  );

 
$closed = array(
   
'accomodation.hu', 'aruhaz.hu', 'aukcio.hu', 'auto.hu', 'befektetes.hu',
   
'bor.hu', 'broker.hu', 'business.hu', 'butor.hu', 'cash.hu', 'credit.hu',
   
'house.hu', 'jacht.hu', 'kamat.hu', 'konyv.hu', 'magazin.hu', 'oras.hu',
   
'orszag.hu', 'pc.hu', 'search.hu', 'szabadido.hu', 'telek.hu', 'trade.hu',
   
'translation.hu', 'travel.hu', 'turizmus.hu', 'voip.hu', 'vpn.hu',
  );
 
 
$error = NULL;

  if (
preg_match('/^[a-z0-9\\á\é\í\ó\ö\ő\ú\ü\ű\-\.]+$/', $host) !== 1) {
   
$error = 'Invalid characters';
    return
FALSE;
  }
 
 
$parts = array_reverse(explode('.', $host));
 
  if (
count($parts) < 2) {
   
$error = 'Invalid format.';
    return
FALSE;
  }
 
  if (
$parts[0] !== 'hu') {
   
$error = 'Not .hu domain.';
    return
FALSE;
  }
 
  if (
in_array($parts[1] .'.'. $parts[0], $closed)) {
   
$error = 'Closed domain.';
    return
FALSE;
  }
 
  if (
in_array($parts[1], $level2)) {
    if (isset(
$parts[2])) {
     
$name = $parts[2];
     
$suffix = '.'. $parts[1] .'.hu';
    }
    else {
     
$error = 'Second level domain.';
      return
FALSE;
    }
  }
  else {
   
$name = $parts[1];
   
$suffix = '.hu';
  }
 
  if (
in_array($name, $protected) && !in_array($name . $suffix, array('internet.hu', 'net.hu'))) {
   
$error = 'Protected name.';
    return
FALSE;
  }
 
  if (
mb_strlen($name) < 2) {
   
$error = 'Domain too short.';
    return
FALSE;
  }

  if (
mb_strlen($name) > 40) {
   
$error = 'Domain too long.';
    return
FALSE;
  }
 
  if (
$name[0] == '-') {
   
$error = 'Name stats with \'-\' character.';
    return
FALSE;
  }
 
  if (
$name[strlen($name) - 1] == '-') {
   
$error = 'Name ends with \'-\' character.';
    return
FALSE;
  }
 
 
$before_needle = strstr($name, '--', TRUE);
  if (
$before_needle === 'xn') {
   
$before_needle = strstr(substr($name, 4), '--');
  }
  if (
$before_needle !== FALSE) {
   
$error = 'Double minus (\'--\') character found.';
    return
FALSE;
  }
 
  return
$name . $suffix;
}
?>

Ha hibákért és a használatból eredő károkért nem vállalok felelősséget. Viszont ha megírjátok a hibát kommentben, akkor javítani, ha tudom.

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.

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'];
  }
}
?>

Mi a közös bennük: Firefox 2, MySQL 3, PHP4, Drupal 5?

Több mint két hete már, hogy megjelent a Firefox 3, kiváncsi lettem, hogy mennyien tértek át. Az F1világ látogatottsági statisztikája alapján az összes Firefox felhasználóból 17% tért át a 3-as verzióra. Ami kevés, szerintem.

Akkor mégis mi is a közös a Firefox 2, MySQL 3, PHP4 és Drupal 5-ben?

Nem, nem csak az hogy internettel kapcsolatos szoftverek, hanem az, hogy túl jól sikerültek, és kevesen tértek át az újabb verziókra.

A MySQL 3 hírhedt arról, hogy mennyi helyen használják, PHP4 szintén, és úgy néz ki a Drupal 5-el is ez a helyzet. Bár ez a hír valószínüleg lendít majd a Drupal 6 elterjedésében. Legalábbis remélem. Az FF3 penetráción meg egy Firebug dobna sokat, szerintem.

Oldalak

Feliratkozás RSS - php csatornájára