phphacker

phphacker er en side med tips og tricks, vedligeholdt af Jonathan Holst

Indhold

  1. Snippets
    1. genPass
    2. sanitize
    3. calcAge
  2. Tips
    1. Undersøg om en streng findes i en anden streng
    2. mysql_error
    3. Brug indryk (tabs)
    4. Undgå short tags (<?)
    5. Kommenter din kode
    6. Ternary operator
    7. Undersøg om en streng indeholder noget
    8. Strtotime upålidelighed

Snippets

genPass

Genererer et (relativt) tilfældigt kodeord. Tager et valgfrit parameter som specificerer længden. Hvis ingen længde er defineret, vil kodeordet blive på otte tegn. Kodeordet genereres som standard ud fra store og små latinske bogstaver og tal, inden for ASCII-rammen. Variablen $chr kan ændres, hvis dette ikke er optimalt.

function genPass($len = 8) {
    $str = '';
    $chr = 'abcdefghijklmnopqrstuvwxyz'.
           'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
           '0123456789';

    for($i=0;$i<$len;$i++) {
        $str .= $chr[(rand(0, (strlen($chr)-1)))];
    }

    return $str;
}

sanitize

Jeg er meget stor tilhænger af læsbare URL‘er, og meget inspireret af hvordan Wordpress håndterer det, skrev jeg denne funktion. Den udfører nogle få simple kommandoer:

  1. Den konverterer hele strengen til små bogstaver.
  2. Den omformer nogle specialtegn til deres tilsvarende latinske stavemåde. Dette array kan udbygges, hvis man føler at der mangler nogle tegn.
  3. Den fjerner alt der ikke er latinske bogstaver, tal og mellemrum.
  4. Den omformer mellemrum til bindestreger.
function sanitize($str) {
  $str = strtolower($str);
  $str = strtr($str, array('æ' => 'ae', 'ä' => 'ae', 'å' => 'aa', 
                           'ø' => 'oe', 'ö' => 'oe', 'ü' => 'u'));
  $str = preg_replace('/[^a-z0-9 ]*/', '', $str);
  $str = str_replace(' ', '-', $str);

  return $str;
}

calcAge

En funktion til at udregne alderen på noget. Den tager tre parametre, som repræsenterer året, måneden og dagen.

function calcAge($year, $month, $day) {
    $dif = date('Y') - $year;
    if(($month > date('n')) || ($month == date('n') && $day > date('j'))) {
        $dif--;
    }
    
    return $dif;
}

Tips

Undersøg om en streng findes i en anden streng

En ofte udført handling er at finde ud af, hvorvidt en given streng findes i en anden.

I mange sprog ville man gøre brug af regulære udtryk til at finde ud af dette, men PHP har nogle streng-funktioner, som er en smule hurtigere (og som man generelt betragter som best practice). Mange bruger strstr() til formålet, men der er faktisk et hurtigere alternativ: strpos().

strpos() har dog en lille tvist, som man skal være opmærksom på når man bruger den: Hvis den streng man søger efter befinder sig i starten af den streng man søger i, vil PHP returnere 0, fordi det er derfra indekset starter. Da 0 bliver betragtet som den boolske værdi false, skal man lave et typetjek:

if(strpos($haystack, $needle) !== false) {
  // Udfør kode hvis nålen er i høstakken
}

Den dobbelte brug af = laver et sådant typetjek. Den kan i øvrigt også bruges til at tjekke normalt — her bruges i stedet ===.

mysql_error

Når man udvikler med databaser i PHP, hvor MySQL er det generelt foretrukne valg, vil man nogle gange løbe ind i en fejl ala denne:

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /var/www/index.php on line 2

Denne kryptiske fejl afslører ikke hvad der er galt, men det kan man godt finde ud af. Man vil oftest have en mysql_query på linjerne inden, og det er her fejlen ligger. Løsningen er at tilføje brugen af mysql_error, en funktion der afslører eventuelle fejl i SQL-forespørgslen, så man kommer frem til noget der ligner det følgende:

mysql_query($sql) or die(mysql_error());

Så får man en brugbar fejlbeskrivelse. Det er dog en god idé at fjerne disse så snart man har lokaliseret fejlen, ellers kan man potentielt afsløre sikkerhedskompromitterende informationer.

Brug indryk (tabs)

Når kode vokser over nogle få linjer vil man som regel møde en eller anden form for kontrolstruktur. Dette være sig en if, switch, function, for, while eller lignende.

For at opnå læsbar kode (ja, det er faktisk vigtigt), bør man derfor brug indryk. Jeg har en tommelfingerregel der hedder, at hver { efterfølges af et linjeskift og et indryk.

Sammenlign disse to stykker kode:

<?php                                         
$something = true;                            
$somethingElse = false;                       

if($something == true) {                      
print 'a';                                    
switch($somethingElse) {                      
case true:                                    
print 'b';                                    
break;                                        
case false:                                   
print 'c';                                    
break;                                        
}                                             
}
<?php                                         
$something = true;                            
$somethingElse = false;                       

if($something == true) {                      
  print 'a';                                  
  switch($somethingElse) {                    
    case true:                                
      print 'b';                              
    break;                                    
    case false:                               
      print 'c';                              
    break;                                    
  }                                           
}
?>

(Bemærk at jeg bruger case og break som en slags tuborgklammer. Dette er mit personlige valg, fordi jeg synes der er en logisk sammenhæng.)

Hvilken er mest overskuelig? Brug indryk.

Undgå short tags (<?)

PHP’s konfigurationsfil, php.ini, tillader at man lader PHP parse kode indenfor <? som tilføjelse til den normale <?php. Dette er dumt at benytte sig af, af to årsager:

  1. Som nævnt er dette et tilvalg i php.ini – man kan altså ikke stole på at denne indstilling er slået til over alt, og koden kan derfor blive defekt.
  2. Hvis man bruger XHTML eller generel XML, og ønsker at benytte sig af den korrekte <?xml-deklaration i toppen af sit dokument, får man en PHP-parse error, fordi parseren ikke kan håndtere XML-deklarationen.

Undgå short tags. De sparer dig for nogle tegn, men giver dig en masse besvær.

Kommenter din kode

PHP tilbyder tre forskellige muligheder for kommentering af kode:

Gør brug af dem. Ikke al kode er så krystalklar som den oprindelige udvikler måske anser det for. Lad være med at tage chancen.

En tommelfingerregel er i øvrigt at man skal skrive hvorfor fremfor hvad man gør.

Ternary operator

PHP har en ternary (trefoldig) operatør. Dette giver mulighed for at forsøge et udtryk, og agere hvis udtrykket er sandt og hvis det er falsk.

I praksis kan dette lette tilskrivelsen af en værdi, hvis man har to mulige værdier:

<?php
$a = true;

$b = ($a == true) ? 'sand' : 'falsk';
?>

Reelt kan man godt lave nestede ternaries, men for at lette læsbarheden bør noget som det følgende undgåes:

<?php
$a = true;
$b = false;                                   

$c = ($a == true) ? ($b == true) ? 1 : 2 : 3;
?>

($c ville indeholde 2 i ovenstående eksempel, men den er ikke helt nem at udlede.)

Undersøg om en streng indeholder noget

Der er flere forskellige metoder til at undersøge hvorvidt der er noget indhold i en streng i PHP. isset og empty er begge ofte brugte metoder til dette, men de har begge deres mangler:

En bedre metode, der virker både på variable og almindelige strenge, er følgende snippet:

strlen(trim($var)) > 0

Denne vil undersøge på længden, og hvis denne er over nul vil man antage at der er indhold. Kan eventuelt krydres med også at erstatte newlines mv. med ingenting, for at få den mest optimale definition af “ingenting”.

Strtotime upålidelighed

PHP’s strtotime() funktion er smart at bruge, især til relative datoer. Den tillader stor frihed, så man eksempelvis kan skrive ting som:

date('Y-m', strtotime('+1 month'));

Der er dog en hage ved dette: den er ikke videre intelligent vedrørende disse; således vil man, sidste dag i en måned med 31 dage, få den samme måned, fordi måneden før ikke har 31 dage. (Dette gælder naturligvis ikke august og juli.)

Hvis man, som i eksemplet, blot skal bruge året og måneden, kan man skrive udtrykket lidt om:

date("Y-m", strtotime("+1 month", mktime(0, 0, 0, date('n'), 28, date('Y'))));

28 er naturligvis valgt, fordi det er det laveste antal dage i en måned. Et hvilket som helst tal under det kan dog bruges med samme resultat.