DELPHPDate de publication : 24/09/06
Par
Sub0
Ce tutoriel est destiné à vous montrer comment j'utilise un composant
d'accès Http pour exécuter des scripts PHP avec Delphi et accéder à une
base de données MySQL. En exemple, la réalisation d'un espace membre PHP.
1. PRESENTATION 1-1. INTRODUCTION 1-2. «DELPHP» 1-3. CONVERSIONS DES DONNEES AVEC DELPHI 1-4. DELIMITATION DES DONNEES PHP 1-5. TIMEOUT & PROGRESSION AVEC DELPHI 1-6. SOURCES 2. ESPACE MEMBRE DELPHP 2-1. UTILISATION 2-2. INSTALLATION & CONFIGURATION 2-2-1. SOURCES 2-2-2. INSTALLATION PHP 2-2-3. CONFIGURATION PHP 2-2-4. SESSIONS PHP 2-2-5. DROITS D'ACCES 2-2-6. TABLE DE DONNEES 2-2-7. INSTALLATION DELPHI 2-2-8. CONFIGURATION DELPHI 3. ADMINISTRATION 3-1. LISTER LA BASE 3-2. STRUCTURE DE LA TABLE 3-3. DONNEES DE LA TABLE 3-4. ACCEDER A UN ENREGISTREMENT 3-5. SOURCES 3-6. REMERCIEMENTS 1. PRESENTATION1-1. INTRODUCTION
Apparemment, un grand nombre d'hébergeurs web ne permettent plus
l'accès direct aux bases de données avec des composants SGBD;
La solution que j'ai adopté est d'utiliser des scripts PHP,
hébergés sur le même serveur que la base de données et d'exécuter
ces scripts avec un programme Delphi.
Ce tutoriel est destiné à vous montrer comment j'utilise un
composant d'accès Http pour exécuter des scripts PHP avec Delphi
et pouvoir accéder aux bases de données MySQL. Ce tutoriel
contient également le code source d'un espace membre très complet
et une petite démo d'administration des données MySQL, ainsi que
toutes les informations nécessaires pour installer les scripts et
configurer ces programmes.
Cet article est aussi disponible... - Au format HTML : http://sub0.developpez.com/delphp/index.php - Au format PDF : http://sub0.developpez.com/tutoriel/delphp.pdf - Sur mon serveur FTP : ftp://ftp-developpez.com/sub0/tutoriel/delphp.pdf 1-2. «DELPHP»
J'ai baptisé ce projet DELPHP. Son principal avantage par rapport
aux composants SGBD est qu'il n'est pas nécessaire de fournir le
login d'accès de la base de données dans le programme Delphi. Il
n'est pas nécessaire non plus d'installer de nouveau composant
dans la palette de Delphi. Toutes les sources sont disponibles
gratuitement. Le principe est le même qu'un navigateur web.
Pour exécuter les scripts PHP, j'utilise le composant
THttpCli d'ICS. J'ai récupéré le code de ce composant
(3 unités) afin de pouvoir l'utiliser dynamiquement dans mes
projets. Ainsi, cela vous évitera l'installation de toute la
palette d'ICS juste pour compiler les démos.
Pour simplifier son utilisation, j'ai réalisé une Class nommée
THttpPost dans l'unité DelphpUnit.pas. Cette Class
permet de communiquer avec les scripts PHP. Le code suivant vous
montre comment je l'utilise pour simuler le Post d'un formulaire,
plus précisément, poster 3 champs de saisie texte vers le script
"connect.php" de mon serveur local :
1) Post du formulaire avec DELPHI : La méthode ResetPost sert à effacer la liste des champs de saisie. La méthode AddPost, à ajouter chaque champs de saisie. Note : Vraisemblablement, la taille d'une requête Http est limitée à 8Mo maximum.
2) Réception du formulaire avec PHP :
La réception des champs de saisie postés avec Delphi se fait de façon tout à fait normale avec le tableau $_POST. Sur le serveur, le script connect.php réceptionne les données comme ceci :
Il est tout de même conseillé de vérifier la syntaxe des données
avant de les utiliser pour contrer un éventuel piratage par
injections SQL. Pour cela, vous pouvez utiliser la fonction
Verifie_Syntax contenue dans le script func.php. Par
exemple, le code PHP suivant vérifie que le pseudo ne contient que
des chiffres ou des lettres en minuscule :
3) Réception des messages PHP avec DELPHI : Pour différencier les messages d'erreurs et les messages de données, un caractère spécial (149) suivi d'un espace (32) est placé au début des données. Ainsi, lorsque le programme Delphi réceptionne le résultat du script PHP, il teste les 2 premiers caractères pour déterminer si il s'agit d'un message d'erreur ou non : - Les messages d'erreur seront placés dans la chaîne StringError. - Les messages de données, dans la chaîne StringResult. 1-3. CONVERSIONS DES DONNEES AVEC DELPHI
Etant donné que les messages d'erreur de PHP sont au format HTML,
j'ai réalisé une petite fonction Delphi nommée StripHtmlTags
pour supprimer les balises HTML et pouvoir afficher proprement les
messages avec la fonction ShowMessage de Delphi. Cette fonction
remplace également les balises <BR> par des sauts de ligne
Windows (#13). Cela dit, dans le cas où vous souhaiteriez envoyer
du code HTML vers votre programme Delphi, utilisez le mode binaire
de la méthode StartPost pour conserver le format initial
des données.
Vous disposez également de la fonction Delphi StrExplode
pour découper une chaîne de caractère en liste de chaîne. Cette
fonction est prévue pour convertir le résultat PHP en tableau de
chaîne et ainsi récupérer des tableaux PHP dans le programme
Delphi.
La fonction Delphi AddSlashes permet d'échapper les
caractères spéciaux avant d'effectuer des requêtes SQL avec
Delphi. Cette fonction est nécessaire si vous souhaitez
enregistrer ou modifier du texte dans votre base de données.
Noter que cette fonction pourrait aussi être effectuée avec PHP
lors de la réception des données.
1-4. DELIMITATION DES DONNEES PHP
Durant les premiers tests du code, [Silk], un membre du forum, a
eu l'occasion de l'installer sur un hébergement gratuit où une
bannière de publicité est automatiquement ajoutée sur toutes les
pages de l'hébergement. A cause de cela, les données réceptionnées
avec Delphi étaient altérées car le programme réceptionnait aussi
le code HTML de la bannière sans pouvoir faire de distinction.
Pour résoudre ce problème, il a fallu encadrer les données émises
par les scripts PHP avec 2 chaînes de caractères spéciaux. La
fonction Mydie du script func.php s'occupe justement
d'ajouter ces délimiteurs au début et à la fin de tous les
messages PHP. De cette manière, lors de la réception des messages,
Delphi supprime les données situées à l'extérieur des délimiteurs.
1-5. TIMEOUT & PROGRESSION AVEC DELPHI
Le composant THttpPost possède un TimeOut qui est réinitialisé
chaque fois que le programme réceptionne des nouvelles données.
Cela est différent du temps total d'exécution. Il s'agit plutôt
d'un TimeOut d'inactivité.
La propriété MaxTimeOut définit la valeur de ce TimeOut en
millisecondes. Par défaut, sa valeur est fixée à 10000, soit 10
secondes. Selon le programme, il est probable qu'il faille
augmenter ce délai pour des requêtes très longues à répondre. Il
est conseillé d'utiliser la fonction flush de PHP pour
demander au script d'émettre les données lorsque cela est possible.
1-6. SOURCES
Télécharger le code de l'exemple ci-dessus : delphpunit.zip 1) Installer le script "connect.php" sur votre serveur 2) Définir l'url de ce script dans la propriété URL de l'objet HttpPost1
Vous pouvez choisir d'utiliser la dernière version du composant
d'ICS : HttpCli6.zip L'unité se nomme OverbyteIcsHttpProt au lieu de HttpProt... 2. ESPACE MEMBRE DELPHP
Ce programme est destiné à être utiliser dans un projet tel qu'un
tchat ou un jeu en ligne. Il s'intègre très facilement et s'utilise
comme une boîte de dialogue modale. Il intègre un formulaire
d'inscription, un formulaire d'identification et de réinscription
(perte de mot de passe). Cet espace membre est configurable pour
obtenir un niveau plus ou moins sécurisé. Le fonctionnement est le
même qu'un espace membre en PHP excepté que les formulaires sont
programmés et affichés avec Delphi au lieu d'être affichés par un
navigateur web au format HTML.
2-1. UTILISATION
2-2. INSTALLATION & CONFIGURATION2-2-1. SOURCES
L'archive contient les fichiers sources pour Delphi ainsi que les
scripts PHP. Ces-derniers sont regroupés dans une archive nommée "php.zip" : loginunit.zip 2-2-2. INSTALLATION PHP
Tous mes projets PHP/MySQL débutent toujours avec les 3 mêmes scripts : - config.php contient les constantes, tableaux et les variables globales du projet. - bdd.php contient les fonctions de création et d'accès de la base de données. - func.php contient diverses fonctions.
Les scripts suivants sont spécifiques à l'espace membre : - connect.php contient le code qui vérifiera la connection du client. - admin.php est la page sécurisée du programme. - font.php est en fait la police "Arial.ttf" utilisée pour les images de code.
Ces scripts sont à installer sur votre serveur, dans le dossier
de votre choix (par défaut, utilisez le nom de dossier "delphp").
2-2-3. CONFIGURATION PHP
Avant toutes choses, vous devez définir les paramètres de
configuration du programme qui se trouvent dans le script
config.php, en particulier les paramètres d'accès de la
base de données.
Ci-dessous, le détail des autres paramètres de configuration :
$cfg['mail_adm']='delphp@server.fr'; Adresse mail de l'administrateur. Cette adresse est utilisée pour définir l'expéditeur dans les mails d'activation. Elle est aussi utilisée comme destinataire pour envoyer un mail d'alerte lors d'une éventuelle attaque. Si ce paramètre est vide, aucun mail d'alerte est envoyé à l'administrateur.
$cfg['mail_act']=true; Activation de l'inscription par mail. Ce paramètre doit être activé si vous souhaitez sécuriser votre espace membre et obtenir une adresse mail valide pour chaque membre. Si ce paramètre est mis à False, les inscriptions seront automatiquement activées dès leur création.
$cfg['delay_act']=2*3600; Durée de réservation du pseudo (par défaut, 2 heures). Ce paramètre n'est valable qu'avec une activation par mail. Il permet de libérer le pseudo dans le cas où l'inscription n'est pas activée dans ce lapse de temps.
$cfg['perim_act']=true; Détermine si le mail d'activation devient inutilisable dans le cas où le lien ne serait pas exécuté dans le lapse de temps défini par la paramètre précédent "delay_act". Si ce paramètre est mis à False, la libération du pseudo est effectuée à la fin du temps imparti mais l'activation du compte reste malgré tout possible seulement si le pseudo n'est pas réutilisé par une autre inscription.
$cfg['im_protect']=true; Les inscriptions sont protégées par une image de code anti-robots. Ces images sont au format Jpeg. Elles sont enregistrées dans le dossier temporaire défini par le paramètre "tmp_dir". Lors de la toute première création d'une image de code, le dossier est créé si il n'existe pas et un fichier nommé "index.php" est ajouté dans ce dossier afin d'interdire l'affichage de son contenu et ainsi, protéger le nom de fichier des images. Le nom d'une image de code est obtenu avec le chiffrage md5 du code qu'elle contient, précédé d'un second code aléatoire (imastr). Ce-dernier est une empreinte du code de l'image et permet de reconnaître l'image sans devoir fournir le code qu'elle contient. Ces images sont automatiquement supprimées du dossier lorsque leur durée de vie est supérieure ou égale à la durée de vie d'une session, soit 5 minutes. L'image est également supprimée du dossier une fois qu'elle a été utilisée.
$cfg['max_att']=4; Nombre maximal d'échecs ou d'attaques consécutifs admissibles. Ce paramètre est utilisé pour bloquer le compte ou annuler l'inscription lorsque l'utilisateur fournit une suite de mots de passe ou clés d'activation invalides. Lors d'une suppression d'inscription ou de réinscription, un mail d'alerte contenant toutes les informations possibles sur l'attaque est envoyé à l'administrateur. Si ce paramètre est égal à zéro, le compte n'est pas bloqué et le nombre d'échec est illimité. Néanmoins, un délai de 3 secondes est ajouté à chaque essai afin de freiner le robot en cas de tentative de piratage du mot de passe par force brute. Concernant l'activation du compte si ce paramètre est égal à zéro, l'utilisateur ne disposera que d'un seul essai.
$cfg['delay_att']=15*60; Durée de blocage du compte (par défaut, 15 minutes). Lorsque le temps de blocage est dépassé, l'utilisateur dispose d'un nouvel essai.
$cfg['max_newmdp']=3; Nombre maximal de réinscriptions admissibles utilisé pour pouvoir effectuer une demande de nouveau mot de passe. Si ce paramètre est égal à zéro, le membre ne pourra pas changer de mot de passe. Dans ce cas, le formulaire de perte de mot de passe est désactivé.
$cfg['max_compte']=3; Nombre maximal de compte pour un poste. Le programme utilise l'IP et/ou l'adresse mail pour déterminer si il s'agit d'un même poste ou non. Si ce paramètre est égal à zéro, les inscriptions ne seront plus permises.
$ses['ses_name']='delphp'; Nom utilisé pour la session. Ce paramètre est également utilisé pour nommer l'expéditeur dans le mail d'activation.
$ses['lifetime']=5*60; Durée de vie de la session (par défaut, 5 minutes). Ce paramètre est aussi utilisé pour la durée de vie des images de code. Ainsi, toutes les images de code qui ont plus de 5 minutes sont automatiquement supprimées du dossier temporaire. Cela signifie aussi que l'utilisateur ne disposera que de 5 minutes pour s'inscrire. Dans le cas contraire, une nouvelle image de code lui sera fournie.
SMTP :
Pour pouvoir sécuriser correctement cet espace membre, vous devez
définir le paramètre SMTP de votre serveur de façon à ce qu'il
puisse envoyer des mails. Ce paramètre se trouve dans le fichier
php.ini. De la même manière, vous devez activer
l'extension GD2 pour pouvoir utiliser les images de code avec la
police Arial. N'oubliez pas qu'il est nécessaire de redémarrer
votre serveur pour que ces changements soient pris en compte.
Si vous souhaitez utiliser un serveur SMTP distant, je vous
conseille l'utilisation de la librairie PHPMailer.
2-2-4. SESSIONS PHP
Les sessions permettent de mémoriser l'identification. Une session
sera valable 5 minutes, durée définie dans le script config.php.
Il y a en tout 4 fonctions dédiées aux sessions : Création, test
de connection, destruction, regénération du SID. Elles sont
déclarées dans le script func.php.
Le composant THttpCli d'ICS utilise l'événement OnCookie
pour récupérer le SID et le retransmettre automatiquement au
serveur. Le SID est redéfini à chaque connection par le script
PHP pour contrer le vol de session. Le SID intègre le pseudo et
un code aléatoire unique pour ne permettre qu'une seule
connection possible par pseudo.
Petite parenthèse, surtout si vous débutez avec PHP, sachez que : 1) Les fonctions de sessions fonctionnent comme pour les headers : Il n'est pas possible d'utiliser les fonctions session_start ou header si le script PHP a déjà affiché quelque chose. Dans ce cas, vous aurez un message d'erreur du genre : Warning: Cannot modify header information - headers already sent by (output started at... 2) A propos des messages d'erreur PHP justement, je vous rappelle qu'un arobas @ qui précède une fonction permettra de masquer les messages d'erreur PHP de cette fonction. Ne l'utilisez que si vous êtes sûr de votre code ou que si vous gérez vous-même l'affichage des erreurs. 2-2-5. DROITS D'ACCES
Pour protéger n'importe quel script PHP, il suffira de placer au
tout début du script, le code suivant :
Ainsi, seuls les membres authentifiés auront la permission
d'utiliser ce script.
Il serait facile d'attribuer des droits pour chacun des membres
en ajoutant un champs supplémentaire dans la table de données et
un test dans le code PHP... Une autre possibilité plus simple
est d'utiliser directement le pseudo. Par exemple, vous devez
vous inscrire avec le pseudo d'accès de votre base de données
(root) pour vous réserver les droits d'administration et ainsi
interdire l'accès d'une fonction si le membre ne s'est pas
identifié comme l'administrateur :
2-2-6. TABLE DE DONNEES
Voici une rapide description du contenu de la table «membres».
Cette table est créée automatiquement, comme la base de données
d'ailleurs, si elles n'existent pas. A noter que la commande
"IF NOT EXISTS" n'est disponible qu'à partir de la version 4 de
MySQL. Voici la structure de cette table :
Le champs newmdp (n°4) est utilisé lors d'une demande d'un
nouveau mot de passe. L'ancien mot de passe reste
valide tant que le nouveau mot de passe n'est pas complètement
activé. La clé contenue dans le champs newmdp intègre 4 éléments
séparés par le caractère "|". Le mail d'activation fournit juste
le premier élément de cette clé. Ces éléments sont dans l'ordre :
La clé d'activation composée d'un code aléatoire et du pseudo
codé en hexadécimal (ASCII), le nouveau mot de passe chiffré
avec md5, la date de la demande du nouveau mot de passe utilisée
pour calculer la durée de vie de cette demande, et enfin, du
nombre d'échec d'activation du nouveau mot de passe.
Le champs compte (n°5) contient le nombre de compte activé
pour un poste. L'IP et l'adresse mail sont utilisées pour
identifier le poste.
Le champs ip (n°10) contient l'IP du membre suivi d'un
séparateur "|" et de l'Host.
Lors d'une inscription activée par mail, la clé
d'activation est enregistrée dans le champs active (n°11).
Cette clé est composée d'un code aléatoire et du pseudo codé en
hexadécimal (ASCII). Le mail d'activation fournit juste cette
première partie de la clé. La clé détient également le nombre
d'échec d'activation séparé par le caractère "|". Le champs
"active" est mis à 0 lorsque le compte est bloqué et à 1
lorsque le compte est activé.
Le champs attack (n°12) est dédié à l'enregistrement
d'échecs d'identification et fournit le nombre d'essai encore
disponible.
2-2-7. INSTALLATION DELPHI
L'espace membre s'intègre facilement dans un projet. Il suffit
d'ajouter l'unité LoginUnit.pas à votre fiche principale de votre
projet dans le gestionnaire de projet. Ainsi, l'espace membre se
comportera comme une boîte de dialogue modale. Dans le fichier
DPR, vous obtenez l'ordre de création suivant :
De cette manière, la fiche de l'espace membre est créée juste
après et détruite juste avant la fiche principale du projet.
L'ouverture du dialogue peut se faire soit manuellement en
exécutant la méthode ShowFormulaire ou TestConnection, soit
automatiquement à la création de la fiche ou lorsque le programme
accède à un script PHP sécurisé et que l'utilisateur n'est pas
encore identifié.
2-2-8. CONFIGURATION DELPHI
Le principal paramètre du programme est l'url du serveur utilisé
pour accéder aux scripts PHP. Cette adresse se trouve dans le
code source du programme, mais il est également possible de
définir cette url dans le fichier INI du programme. De la même
manière, vous pouvez redéfinir le port et la valeur du TimeOut.
Il conviendra d'adapter le programme à votre application. En
général, vous ne donnerez pas la possibilité aux utilisateurs de
modifier ces paramètres.
D'autres paramètres sont disponibles dans l'unité LoginUnit.pas :
Il est prévu également de pouvoir choisir la couleur du dialogue.
Par défaut, ces couleurs sont celles du système (clDefault).
L'image de code utilise également les couleurs du dialogue.
Voici 3 exemples de couleurs personnalisées :
3. ADMINISTRATION
Cette dernière partie de l'article montrera comment j'utilise la
connection aux scripts PHP pour effectuer des requêtes SQL précises
et récupérer le résultat avec Delphi. En particulier, lister les
tables de la base de données, afficher la structure et les données
d'une table et supprimer un ou plusieurs enregistrements dans une
table. Ces commandes sont contenues dans le script admin.php et
protégées par l'espace membre Delphp. Vous devez donc d'abord vous
identifier avant de pouvoir les utiliser.
Il serait tout à fait possible de poster la requête SQL complète pour
permettre au programme Delphi de pouvoir effectuer n'importe quelle
requête, mais je préfère définir les requêtes avec PHP, le programme
Delphi fournissant juste les paramètres de ces requêtes. Je trouve
cette méthode plus sécurisante.
Il serait également possible d'utiliser le format XML ou CSV ou un
autre format perso pour récupérer et afficher les données des tables...
Bref, il appartient au développeur de choisir la manière dont il
communiquera avec la base de données. Pour ma part, côté PHP, je
sérialise les données séparées par le caractère nul #0, puis côté
Delphi, j'utilise la fonction StrExplode pour obtenir le tableau de
données (TStrings).
3-1. LISTER LA BASE
Le programme Delphi poste la commande "act=getbase" avec la
méthode StartPost. Le résultat de cette requête est la liste
des tables de la base sérialisée dans la variable HttpPost1.StringResult.
La fonction StrExplode scinde cette chaîne pour obtenir la
liste déroulante finale des tables :
3-2. STRUCTURE DE LA TABLE
Avec la commande "act=gettable" et le nom de la table en
paramètre, le script PHP retourne la structure de la table (le nom
et le type de chaque colonne). Comme pour obtenir la liste des
tables, StrExplode scinde le résultat dans une variable de
type TStrings nommée "structure" :
3-3. DONNEES DE LA TABLE
De la même manière, avec la commande "act=getdata", le
programme récupère les données et les stocke dans la variable de
type TStrings nommée "Donnees". La structure de la table
récupérée auparavant permettra de démultiplexer ces données. Dans
cette commande sont prévus en tout 5 paramètres pour définir la
requête SELECT. Les paramètres porder et pdesc
permettront d'effectuer le tri des données par colonne.
3-4. ACCEDER A UN ENREGISTREMENT
Ce code est destiné à vous montrer comment j'utilise les données
téléchargées pour reconstituer le paramètre WHERE d'un
enregistrement pour y accéder avec une requête SELECT, DELETE ou
UPDATE... Vous remarquerez l'utilisation de la fonction
AddSlashes pour échapper les caractères spéciaux qui
pourraient se trouver dans les données. Dans le code suivant,
Y représente le numéro de la ligne de la grille où se
trouve l'enregistrement :
3-5. SOURCES
Télécharger le code du programme d'administration :
admindemo.zip 1) Installer les scripts php sur votre serveur 2) Définir l'url du script "admin.php" dans la propriété URL de l'objet HttpPost1 3-6. REMERCIEMENTS
Si vous avez des remarques et suggestions intéressantes pour
améliorer le code ou des questions concernant cet article, je suis
à votre disposition sur le forum. N'oubliez pas que vous disposez
de la FAQ et du forum PHP de Developpez.com pour toutes questions
concernant la programmation dans ce language.
Merci à François Piette et les membres du forum web et Delphi de
Developpez.com pour leur participation (pardon si j'en oublie) :
Archibal29, chaours, ero-sennin, giloutho, Giovanny Temgoua,
Laurent Dardenne, mussara, pedro, rezuss, [Silk], sjrd, Yogui
et wilco.
à+
Ce document est issu de http://www.developpez.com et reste la propriété
exclusive de son auteur. La copie, modification et/ou distribution par
quelque moyen que ce soit est soumise à l'obtention préalable de
l'autorisation de l'auteur.
|