Més consells per a la programació defensiva en PHP

La definició general de programació defensiva (tal com es veu a la part 1, una visió general de la programació defensiva en PHP) que s’utilitza aquí és la següent:

La programació defensiva, en poques paraules, és programar amb la intenció d’anticipar possibles punts de fallada. L’objectiu és evitar aquests possibles problemes abans que es produeixin.

Aquesta definició és àmplia. Molta gent discuteix en contra programació defensiva, però això sovint es deu als tipus de mètodes que alguns han vist adoptats com a programació defensiva. La programació defensiva no s’ha de veure com una manera d’evitar el desenvolupament impulsat per proves o com una manera simplement de compensar els errors i seguir endavant.

“Fail Fast” no s’ha de veure com un contrari a la programació defensiva. Tot cau sota el mateix paraigua. Quins són aquests mètodes, si no maneres d’anticipar que el vostre programa pot fallar, i prevenir-los, o bé maneres de gestionar aquests errors de manera adequada?

Falla ràpid i fort

En poques paraules, fallar ràpidament i en veu alta significa que quan es produeix un error, ho farà tan aviat com sigui possible i avisa a qui ha d’avisar, en lloc de continuar en silenci en un estat d’error que pot causar més problemes. Aquí teniu un article excel·lent sobre el desenvolupament d’estil ràpid fallit. La premissa de la metodologia de fallada ràpida és fallar quan s’adquireix inputs que posteriorment poden comprometre el programa (o, de manera més general, entrar en un estat de fallada tan aviat com es pugui detectar qualsevol problema, en lloc de permetre que les dades incorrectes viatgin i un programa). executar dades sense verificar, o pitjor encara, dades dolentes per emmagatzemar-les en algun lloc). Això és molt útil quan es tracta de l’entrada de l’usuari, o quan es tracta d’una entrada que arriba des de fora de l’script, mòdul o fins i tot fora del vostre sistema mitjançant una API. Un exemple d’on es podria utilitzar això seria una comprovació de valors no vàlids o tipus de dades passats a funcions.

function thisTestFunction($testInt)
{
	if(!is_int($testInt)){
		// Do something here
	}
}

Un error que cometen alguns programadors amb la metodologia de fallada ràpida és simplement llançar excepcions i errors a l’usuari sense fer les disposicions adequades per a maneig ells. No voleu que els usuaris normals es preocupin o confonguin els vostres missatges d’error. I el que és més important, no voleu que els usuaris amb intenció maliciosa aprenguin coses de la informació que se’ls mostra. Mostra un missatge útil a l’usuari, registre els teus errors i realitza qualsevol altra tasca que hagi de ser el resultat d’aquesta excepció. No vols simplement fallar ràpidtambé vols ser fort (saber hi ha un problema, immediatament) i segur (no deixeu que el vostre mal maneig d’excepcions o la manca total d’aquestes causes encara més problemes de seguretat).

Validació d’entrada

Hi ha molts mètodes per validar l’entrada de l’usuari de manera segura.

Typecasting és una manera interessant de “validar” l’entrada de l’usuari. De vegades passa una mica així:

$member->property = (int) $_GET['property'];

En lloc d’utilitzar un altre mètode per evitar atacs de scripting entre llocs, el valor simplement s’està capturant, tipificant i assignant. Això només funciona quan teniu un tipus esperat i qualsevol valor d’aquest tipus és segur (en cas contrari, també haureu de comprovar si apropiat valors int). El problema amb aquest enfocament, que veig (en la majoria de situacions) és que realment no ho ets comprovació l’entrada, només ets forçant que esdevingui el que hauria de ser. Això podria tenir conseqüències inesperades. En lloc d’això, un millor enfocament podria ser comprovar els valors adequats filter_input(). Aquí teniu un gran article sobre aquest tema. Bàsicament, això surt així:

$member->property = filter_input(INPUT_GET, 'property', FILTER_VALIDATE_INT);

if (false === $member->property) {
  throw new Exception('Property was not an int');
}

Hi ha molts avantatges d’utilitzar el nadiu filter_input funcionen en PHP modern, i podeu llegir-ne més a l’article esmentat o a php.net.

Prevenció de l’assignació accidental en les comparacions

Aquest és un principi fàcil, i sovint assenyalat, de la programació defensiva. Un simple canvi en la manera de fer les comparacions pot tenir grans efectes. Tingueu en compte el següent:

if($member->property == 12345){
	// Do crazy cool stuff
} else {
	// Don't do any fun stuff
}

Aquesta és una comparació relativament normal, oi? Tanmateix, què passa si utilitzeu accidentalment “=” en comptes de “==” (o, en la majoria dels casos, encara millor “===”)? Un simple lliscament del dit al teclat? Distracció, potser? De sobte, la teva comparació ara és certa, tot el temps, en tots els casos. A menys que tingueu un bon IDE que us avisi sobre això, quant de temps trigareu a esbrinar-ho? En alguns casos, pot ser un error silenciós durant un temps. Tanmateix, hi ha una manera extremadament senzilla d’evitar-ho:

if(12345 == $member->property){
	// Do crazy cool stuff
} else {
	// Don't do any fun stuff
}

Ara, si utilitzeu accidentalment un signe igual, l’error no serà silenciós. Òbviament, això pot no passar sovint, es pot mitigar amb les vostres proves i no és útil en tots els casos, especialment quan feu comparacions de variables a variables. Però encara no és una mala idea si això sol passar-te.

Tractar amb Try/Catch i excepcions

try/catch Les declaracions són un altre tema candent entre els desenvolupadors de PHP. Primer fem una ullada ràpida del que estem parlant.

try {
	if($member->property <= 0){
		throw new Exception("Value must be 1 or greater");
	}
	// If no exception was thrown, this will be output.
	echo "The value is acceptable";
} catch(Exception $e) {
	echo 'Message: '.$e->getMessage();
}

Una eina coneguda de programació defensiva és el try/catch declaració i el Exception classe. Són excel·lents per detectar i registrar errors, quan s’utilitzen correctament. Un bon programador emprarà try/catch declaracions per anticipar possibles errors o altres situacions que puguin interrompre el flux normal. Quan es produeixin aquestes excepcions, s’han de tractar d’una manera adequada. L’usuari de l’aplicació, quan sigui necessari, hauria de rebre un missatge d’error raonable que sigui tan útil com pugui ser sense revelar informació sensible. Els administradors de l’aplicació haurien de rebre alertes i/o registres detallats. Les excepcions que es gestionen malament o s’ignoren, ignoren el consell “Falla en veu alta” i poden permetre que el programa continuï essencialment en un estat d’error silenciós durant un temps, cosa que no és bo per a ningú implicat.

Per obtenir una mica més sobre les excepcions en PHP, vegeu aquí i aquí.

Transaccions

Les transaccions són una característica de les bases de dades que permeten agrupar les consultes, de manera que si una consulta falla, fallen totes. Aquesta és una implementació d’ACID, sobre la qual podeu llegir més informació aquí. La idea és que agrupar diverses consultes en un sol procés de vegades pot ser una solució més segura i estable, sobretot quan les consultes depenen les unes de les altres. Els desenvolupadors de PHP sovint ignoren completament les transaccions o assumeixen que són innecessàries, però quan interactuen amb bases de dades, una mica de programació defensiva pot recórrer un llarg camí. Les transaccions es comenten amb més profunditat en aquesta publicació excel·lent, però en poques paraules, les transaccions us permeten executar les vostres actualitzacions de MySQL i, a continuació, comprovar els resultats abans de fer-ho. cometent els resultats. Si utilitzeu PDO (ho hauríeu de fer), podeu utilitzar mètodes PDO per iniciar una transacció, confirmar els resultats i retrocedir. A més de la visió general esmentada de les transaccions, aprofundeix-hi amb aquesta guia detallada.

Aquí teniu un exemple ràpid de com podria semblar l’ús de les transaccions a PDO:

try{
	// Start the transaction
	$db->beginTransaction();

	// Perform one update
	$statement1 = $db->prepare("QUERY LANGAUGE HERE");
	$statement1->execute(array($a,$b));

	// Perform another update
	$statement2 = $db->prepare("MORE QUERY LANGUAGE HERE");
	$statement2->execute(array($a,$b,$c));

	// Commit the transaction
	$db->commit();
} catch(PDOException $ex) {
	// If an exception occurs, first, roll back updates
	$db->rollBack();
	// Then, in this block, further handle the exception
}

Conclusió

De nou, aquests són només consells generals. Òbviament, cadascun d’ells té els seus usos i cadascun té situacions notables on ho faria no ser utilitzat. Tanmateix, si agafeu conceptes com aquests i els treballeu en els vostres règims de desenvolupament diaris, us pot fer més eficient en el que feu. I tot i que aquest és generalment un tema que és més aplicable als desenvolupadors que actualment estan aprenent PHP, és una bona actualització de pràctiques per a tothom.

Si només se’n treu una cosa, especialment els desenvolupadors més nous, és que hauríeu de programar a la defensiva: planificar la possibilitat d’errors i errors. Manejar-los adequadament. No permeteu que els errors silenciosos progressin. Falla ràpid. Prova el teu codi. En crear aplicacions sòlides que testin i resolguin problemes, i anticipen i gestionen els futurs, esteu fent que les vostres aplicacions siguin més fiables i, esperem, ajudeu a crear una millor experiència d’usuari des de darrere de les escenes.

Leave a Comment

Your email address will not be published. Required fields are marked *