par , 08/07/2017 à 17h32 (1435 Affichages)
Bonjour à tous,
La question est pourtant simple, mais j’ai pu constater qu’aucune réponse n’était disponible sur aucun forum à cette question à part dans un contexte de requête préparée.
Il est triste de constater de l’utilisation généralisée des requêtes préparées en programmation web, et ce, pour plusieurs raisons.
L’argument universel des Injections SQL
Ceci est un très mauvais argument, car comme je l’ai déjà expliqué ici sur développez.net Lorsque l’on effectue un contrôle systématique de type de contenu et de définition de chaque variable publique de son application, l’injection n’y est plus possible. (…) Donc à partir du moment où on vérifie soit même, pas besoin de PDO pour le faire quand surtout il n’est pas capable de contrôler la pertinence des données reçues vis-à-vis du modèle.
Il faut rappeler également que la mise en place d’une requête préparée est coûteuse en terme de ressources et le faire de plus au niveau d’un driver externe au SGBDR est moins pertinent que de le faire au sein du SGBDR lui-même (qui est le plus apte à en gérer les ressources associées) dans une procédure stockée par exemple.
De plus, à moins de devoir exécuter cette requête un grand nombre de fois avec des paramètres différents, il n’y a aucun intérêt technique à privilégier cette approche.
Un argument supplémentaire à cela: j'ai été surpris et déçu de constater sur les drivers PDO PHP 7 natifs pour SQL Server 2014 et 2016 qu'une requête appelant une procédure stockée sans utiliser de requête préparée au niveau PHP, avait recours à une requête préparée au niveau du driver. Ce constat à été fait au niveau du SQL Profiler dans SSMS.
Ceci étant dit, voyons comment récupérer notre variable de type OUTPUT de notre procédure stockée dans PDO d’une manière « normale » ou « classique » si vous préférez.
Voici la procédure stockée qui va nous servir d’exemple
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
USE MY_DATABASE;
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID('MON_SCHEMA.P_PROCEDURE_EXEMPLE') IS NOT NULL
DROP PROCEDURE MON_SCHEMA.P_PROCEDURE_EXEMPLE;
GO
CREATE PROCEDURE MON_SCHEMA.P_PROCEDURE_EXEMPLE
@user_id int = 0,
@last_infos [varchar](50)='' OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @last_infos=ma_colonne FROM MON_SCHEMA.MA_TABLE WHERE user_id=@user_id;
IF @last_infos IS NULL
RETURN 0;
RETURN 1;
END
GO |
Vous l’aurez compris ici, le but étant de récupérer la valeur de la variable @last_infos dans PDO. Pour rappel, on ne peut ici la placer au niveau du RETURN car seul un entier peut être retourné par une procédure stockée sous SQL SERVER.
Voici un exemple de comment procéder pour récupérer l’information qui nous intéresse.
1 2 3 4
|
function get_informations($user_id){
$PDOInstance=new PDO(DSN_infos, USER_login, PWD_user);
$PDOInstance->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); // facultatif selon vos préférences |
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
$user_id=intval($user_id);
$query="DECLARE @last_infos varchar(250)
EXEC MON_SCHEMA.P_PROCEDURE_EXEMPLE $user_id,@last_infos=@last_infos OUTPUT
SELECT @last_infos";
try{
$db_result = $PDOInstance->query($query)->fetchAll(PDO::FETCH_NUM);
} catch (Exception $e){
if (strpos($e->getMessage(),'SQLSTATE[IMSSP]')!==false){return $db_result;}
print ' @Err:[GET_informations] '.$e->getmessage();exit;
}
return $db_result;
}
|
Voilà. Vous voyez, il n’y a rien de difficile.
Bonne journée à vous.