bitcomplex.se / 102 posts / categories / 157 comments / feed / comments feed

En liten kommentar tillägnad @Macfeast angående hans ”SQL-fetch-funktion underlättar vid foreach”

Från början tänkte jag lämna en kort kommentar på @Macfeast‘s blogg Undergr0und angående SQL-fetch-funktion underlättar vid foreach. Men se där var det stopp. Ingen kommentarsfunktion alls på den bloggen.

Istället får det bli ett en egen bloggpost, och för att fylla ut den så får vi sväva ut i lite mer allmänt svammel (som exempelvis de inledande orden jag just håller på att skriva – skulle ha kunnat ta vilket som helst av dem).

Jag tänker vara petig och lite pretentiös här, men är tämligen säker på att jag inte trampar på Mauritz tår, utan att han (och andra) snarare kan se det som en liten gratislektion i PHP och MySQL.

I grund och botten rör det sig om följande kodexempel från bloggposten i fråga (och denna post rör alltså kodexemplet och har inget med det faktum att det är just Macfeast som skrivit det – det finns tusentals liknande exempel som flyter runt där ute):

<?php
function sql_fetch($param_1, $param_2, $param_3){
	$q = mysql_query("SELECT ".$param_1." FROM ".
$param_2." ".$param_3);
	while($r = mysql_fetch_assoc($q)){
		$return_fetch[$r['id']] = $r;
	}
	return $return_fetch;
}

// Insaxad exempelkod från blogginlägget:
sql_fetch("*", "entries", "ORDER BY id DESC LIMIT 5");
?>

Mina synpunkter på koden ovan (vissa punkter viktigare än andra):

  1. Först och främst; Det är en sak att använda slarvig kod själv under kontrollerade former. En helt annan sak att tipsa andra om koden utan att poängtera uppenbara säkerhetshål.

    Om någon skulle kopiera den här funktionen och använda den på ett sätt som ger tredjepart direkt, eller indirekt, kontroll av parametrarna till funktion så kommer de att råka illa ut.

    Enbart med tillgång till $param_1 kan du ställa precis vilken fråga som helst till databasen. Exempelvis kan man testa med:

    <?php var_dump(sql_fetch("* FROM `users` -- ", "", ""));

    Det är extremt viktigt att vara övertydlig när det gäller databassäkerhet i – framför allt – nybörjarguider.

    Om vi tar ett nybörjarforum som phpportalen.net så svämmar det över av dåliga kodexempel. Med en kultur som innebär att man ”lär” sig genom att kopiera och klistra in andras kod är det inte konstigt att PHP fått oförtjänt dåligt rykte som ett osäkert programmeringsspråk.

    Nu vill jag inte klanka ner på vare sig de som försöker lära sig att koda på detta sätt eller på PHPportalen eller för den delen den enskilde som publicerar mindre genomtänkt kod. Jag har själv varit en aktiv användare av PHPportalen och det finns (fanns?) ett par riktiga guldkorn i medlemsdatabasen där. Och jag har säkert – mer än en gång – visat upp undermålig kod, både i testsyfte och i produktion(!).

  2. En annan sak viktig att poängtera; Försök hålla dig uppdaterad med utvecklingen av språket du kodar i. I fallet med PHP har vi en fantastisk online-resurs i php.net och där går det bland annat att läsa:

    If you are using MySQL versions 4.1.3 or later it is strongly recommended that you use the mysqli extension instead [of the mysql extension].

    Vi är upp i version 5.5 av MySQL just nu, och förhoppningsvis har de flesta webbhotell en senare version än 4.1.3. (En annan bra sida från php.net när vi ändå är inne på det)

  3. Så till en lista med lite mindre viktiga punkter – där en del är mina egna helt personliga åsiker:
    • En liten reflektion angånde funktionen ovan: Vad händer om databastabellen man (förhoppningsvis medvetet) hämtar ifrån, inte har en kolumn som heter `id`?
    • Det är nästan uteslutande bättre att speca exakt de kolumner man vill hämta från en databastabell än att använda SELECT *. Varför hämta ut mer än man behöver? Lathet?
    • Jag tillhör skolan som förespråkar att inte avsluta php-filer med ?>. Detta av tre enkla anledningar: Det är två tecken mindre att skriva. Det är helt okej att göra det (inga notices eller errors, utan PHP avslutar helt enkelt skriptet när filens slut nås). Och betydligt viktigare; Om du råkar ha ett white space-tecken efter ?> så kommer detta white space-tecken att skrivas ut vilket kan leda till fatal errors. Exempelvis klassikern ”Cannot modify header information. Headers already sent”.
    • Sist men också minst, en kommentar angående strängar. Det tjatas en del om huruvida man ska använda enkel- eller dubbelfnuttar. Fördelen med dubbelfnuttar är just att man kan expandera variabler direkt i strängen. Det finns prestandatester som visar att det är snabbare att konkatinera ihop enkelfnuttsträngar och det finns andra tester som visar att dubellfnuttsträngar är snabbare…
      Microoptimeringar säger jag! Var konsekvent istället. Själv använder jag nästan enbart dubbelfnuttar och hade således skrivit (betydligt mer lättläst imo):

      "SELECT {$param_1} FROM {$param_2} {$param_3}"

Och just det… Håller med om att funktioner liknande Macfeasts kan vara bra (poängen är alltså att kunna återanvända kod och inte upprepa sig själv hela tiden). Men är det inte lite att överdriva när det nästan hade varit lika enkelt (+ betydligt mer lättläst) att skicka in hela querien som en sträng? Jämför de båda raderna. Vilken är mest självförklarande?

sql_fetch("*", "entries", "ORDER BY id DESC LIMIT 5");
sql_fetch("SELECT * FROM entries ORDER BY id DESC LIMIT 5");

Andra inlägg som kanske kan vara intressanta