Dernière mise à jour le 3 décembre 2000.
Les questions prises en compte dans cette FAQ sont celles
directement liées à PHP, ainsi que quelques
questions limite ou hors sujet revenant
régulièrement sur le forum, indiquées par
:
A chaque fois que possible, un lien direct vers les versions
traduite et originale du manuel approprié sera fourni.
Tous les liens s'ouvriront dans une nouvelle fenêtre
(pour les navigateurs qui le supportent).
Toute réponse mettant en jeu du code PHP sera
accompagnée d'un exemple, testé par le
rédateur de la réponse sauf mention contraire.
Le "l" (lettre L") devant une variable (exemple $l_dad) indique
une variable locale à la fonction, ce qui est bien entendu
seulement une convention de nommage.
Le terme "unix" n'est pas restreint à linux.
Bonne lecture et bon PHP.
- Comment débuter en PHP
-
"Bienvenue chez les fous" :-) ((C)A.F. 1999)
PHP est un langage simple tant dans sa syntaxe que dans ses fonctions. Il faut
connaître le HTML (ou l'apprendre en même temps). L'achat des ouvrages
indiqués dans la section ressources (en bas de cette FAQ) est vivement
conseillé. Installez PHP et MySQL ou Postgres sur votre ordinateur par
exemple avec le package d'Emmanuel Faivre (windows) et testez vos scripts en
local. Lisez ce document, apprenez à lire le manuel de PHP, à
chercher un peu par vous même dans les multiples sites cités dans cette FAQ,
et à poser vos questions au bon endroit : fciwap pour les questions
liées à PHP, fr.comp.applications.sgbd (fcas) pour les
questions sur le langage SQL ou la configuration de votre SGBDR (MySQL, Postgres, etc...)
et fr.comp.infosystemes.www.auteurs (fciwa, sans le p de PHP) pour les questions HTML et Javascript, ainsi qu'au support technique
(aide en ligne, forums réservés) de votre hébergeur.
Partez du principe qu'il est probable que quelqu'un d'autre a déjà
été confronté au même problème : si votre question n'est pas
mentionnée dans cette FAQ, cherchez sur les archives de cd NG : sur
http://www.phpindex.com/ng/ ou
sur dejanews : http://www.deja.com/home_ps.shtml. En respectant ces règles
simples, vous aurez plus rapidement la réponse à votre question.
[Retour à la liste des réponses]
- Rappel de quelques notions de base
Bien que la plupart des questions traitées dans ce document concernent
l'utilisation de PHP de concert avec une base de données, et dans la plupart
des cas MySQL, il est faux et restrictif de penser que PHP nécessite
un Système de Gestion de Base de Données Relationnel (SGBDR), et encore plus faux de penser que MySQL est "le" SGBDR incontournable
avec PHP (on pourrait déjà discuter longtemps du qualificatif de
SGBDR pour MySQL ...) : n'oublions pas Postgres, Oracle et Sybase
pour ne citer qu'eux.
De même, la majeure partie des questions sur fciwap concernent
l'utilisation de PHP couplé à un serveur web (Apache, IIS, PWS,
Xitami, NES, etc...) mais PHP peut tout à fonctionner en tant
qu'exécutable "stand-alone" : c'est une application à
part entière.
HTTP : client serveur en mode asynchrone non connecté
Un script PHP utilisé pour générer dynamiquement une page web, comme un script ASP par exemple, s'exécute
sur le serveur web qui reçoit une demande de la part d'un navigateur client.
Le script PHP va faire certaines choses sur le serveur (mise à jour / interrogation de base de
données, écriture dans des fichiers sur le serveur,
consultation ou envoi de mail, etc...) puis va renvoyer au navigateur
le résultat (HTML, PNG...) de ses actions. La page HTML qui
revient vers le navigateur client n'a pas d'existence "physique",
elle n'est pas ce que l'on appelle une page "statique", stockée sur le serveur (par
FTP en général) et "servie", identique, au navigateur client
à la demande. Néanmoins, en recevant le code HTML,
le navigateur n'a pas moyen de savoir que c'est une page
dynamique ou statique : le client ne sait rien de ce qui s'est passé
sur le serveur où tourne PHP.
Remarque importante car à la source de nombreuses confusions :
En particulier, du JavaScript qui tourne
sur cette page dans le navigateur client n'a aucun moyen de savoir que PHP en a
généré une partie.
Ceci implique que PHP peut passer des arguments à du
JavaScript (client), (en fait, on peut tout à fait faire du JS dynamiquement généré
par du PHP), mais également que pour passer des arguments JS depuis le client vers PHP et donc le serveur,
il faudra soumettre un formulaire.
Notons ici néanmoins que PHP peut ouvrir des connexions par sockets vers d'autres serveurs.
[Retour à la liste des réponses]
- Quel hébergeur choisir avec PHP ?
-
Reportez vous au site abc-hébergement :
http://www.abchebergement.com/
[Retour à la liste des réponses]
- Des problèmes d'installation
Voici une liste de pointeurs pour l'installation de PHP avec
différents serveurs web / SGBDR.
Avec windows :
-
Le package Easy-PHP (windows 9X/NT d'apache + mysql + php + phpmyadmin), est disponible sur
http://www.manucorp.com/
A noter : il est plus judicieux de poser vos questions relatives à ce package sur la mailing list reserv´e
à cet usage qui est en place sur www.manucorp.com
- Configuration du PWS pour PHP
Un guide complet, pas à pas, avec captures d'écran :
http://davidubois.free.fr/cfg/index.html
- Installation d'Apache
http://lwest.free.fr/doc/php/configuration_NT_fr.html
- Avec Unix :
De manière générale, commencer par enlever tous les RPMs plus ou moins pre-intallés, télécharger
les tarballs et tout recompiler. Si vous faites des installations sucessives, penser à commencer par un make distclean ou carrérrement repartir des tarballs d'origine.
Pour l'installation de PHP avec Sybase, les options --with-sybase
et --with-sybase-ct ne doivent pas être utilisées
ensemble (conflit de la db et ct libs).
- Avec Macintosh MacOS X :
Deux packages sont disponibles sur http://homepage.mac.com/LightyearDesign/MacOSX/Packages/
[Retour à la liste des réponses]
- Editeurs PHP
Cette liste est fournie pour le confort des yeux.
N'importe quel éditeur ASCII fait l'affaire.
- Macintosh :
- Dos / windows 3x
- Windows NT / 9X /2000
Il nait presque un éditeur par jour pour windows. Le but n'est pas de les lister tous.
- Unix
- Emacs et
emacs win32 : "plugins"
- vim et vim
win32
[Retour à la liste des réponses]
- Passage de variable(s) entre les scripts
[HS] La solution la plus courante et la plus simple consiste
à transmettre les variables dans l'URL sous la forme
normalisée.
http://mon_url.fr/mon_beau_script.php3?variable1=valeur1&variable2=valeur2&...&variableN=valeurN
Rappelons aussi l'emploi parfois judicieux d'urlencode ( ) et de rawurlencode( ) ainsi que la
préférence de la méthode POST et non GET.
Si vous vous posez ce genre de questions, il est probable que
vous aurez aussi d'autres questions de base sur le HTML et il est
probable que créer quelques pages statiques avant de vous
intéresser à la création de pages dynamiques
serait plus logique, afin d'échelonner les
difficultés. N'hésitez pas à user et abuser de la liste
des ressources présente dans cette FAQ.
[Retour à la liste des réponses]
- Passer des variables JavaScript à PHP
-
Lire le deuxième paragraphe de cette Foire Aux Questions : "Rappel de quelques notions de base".
[Retour à la liste des réponses]
- Messages d'erreur classiques
...0 is not a valid mysql index on line...
La requête SQL a échoué et vous n'avez pas
pensé qu'il faut toujours tester la valeur de retour d'une
fonction aussi cruciale pour le résultat attendu qu'une
requête sur BD, mysql_query( ) ici. Donc le premier appel
au buffer de stockage du résultat, par mysql_fetch_*( ), provoque une erreur.
Pour trouver l'erreur dans votre requête SQL, affichez par un
appel à echo "";ou print( );
la requête passée dans l'appel à mysql_query( ); et
exécutez cette requête en ligne de commande dans MySQL.
...parse error on line 55...
Une error de parsing (en français dans le texte) est une
erreur de syntaxe php. Une erreur déclarée sur la
ligne N est très souvent causée sur la ligne N-1
sur cet exemple, la ligne 54.
L'erreur la plus courante est un oubli de ';' en fin de
ligne...
Un autre grand classique est l'oubli de '\' devant des double-quotes
ou l'oubli des double-quotes finales dans une chaîne de
caractères.
On rencontre aussi une "parse error" en fin de fichier quand on oublie une
accolade fermante } dans un bloc conditionnel. Typiquement, si
votre fichier fait 204 lignes et que vous avez une "parse error" sur
la 205eme, c'est un très probablement un problème d'accolades.
[Retour à la liste des réponses]
- Code d'un forum ou BBS en PHP
-
Il existe des projets "tout prêts" et gratuits. Par exemple
:
Si vous préférez faire le votre, un très bon
exercice, inspirez vous de leur code (ce qui est du "hacking" au
bon sens du terme).
Si vous possédez le livre de Leon Atkinson (cf en bas pour
toutes ses références), voir le chapitre 16 pour un
exemple.
[Retour à la liste des réponses]
- Code d'un caddie virtuel en PHP
-
Intéressez vous au projet en Open Source d'Alexandre Trusch :
http://www.w3-concept.net/
Et la démo de ce projet :
http://demo.w3-concept.net/
[Retour à la liste des réponses]
- Code d'un "chat" en PHP
-
Voir le travail de Nicolas Hoizey : phpMyChat sur http://www.phpHeaven.net/
[Retour à la liste des réponses]
- Gérer plusieurs langues sur un site
-
Voir le travail de Nicolas Hoizey : phpLang sur http://www.phpHeaven.net/
Par ailleurs, il est possible de définir la même variable PHP,
avec une valeur différente selon la langue simplement en se servant
de fichiers à inclure.
Soit par exemple une gestion de trois langues: allemand (DE), anglais (EN), et
français (FR). Le code de toute page PHP commencera par le code suivant :
$l_langue=fx_filtrer($i_langue);
/* On filtre toute variable arrivant du monde extérieur */
switch ($l_langue)
{
/* Profitons de la capacité de PHP à accepter des chaînes
de caractères dans les switch( ) */
case "FR" : include("FR_mesg.php3");
break;
case "EN" : include("EN_mesg.php3");
break;
case "DE" : include("DE_mesg.php3");
break;
default : print("Langue non reconnue <br>");
fx_footer("parametres divers");
exit();
/* N'oublions pas le cas par défaut qui permet de traiter TOUTES
les erreurs d'un seul coup */
}
Les fichiers contiendront une définition différente
des mêmes variables / constantes :
Dans FR_mesg.php3 : define(msg1,"Bonjour");
Dans EN_mesg.php3 : define(msg1,"Hello");
Dans DE_mesg.php3 : define(msg1,"Gunten Tag");
Dans le code du script, il suffira d'afficher la constante msg1 sans
réfléchir : la bonne langue sera automatiquement
sélectionnée.
Il est bien entendu aussi possible de stocker des messages dans une table
d'une base de données qui aura trois colonnes : l'identifiant du
message (msg1,...msgn), la langue, et le texte, la clef primaire étant bien
sûr le couple (identifiant, langue).
[Retour à la liste des réponses]
- Connaître la version du navigateur et la
résolution de l'écran
La variable globale HTTP_USER_AGENT contient la version du
navigateur ayant demandé la page (ou celle qu'il a bien voulu donner
par exemple dans le cas d'un "aspirateur").
La résolution de l'écran n'est pas transmise au
serveur par le navigateur. Si vous souhaitez vraiment vous en
servir, utilisez JavaScript.
Remarque : il n'est pas particulièrement
conseillé de faire des versions différentes d'un
site selon la configuration du client qui va le voir (version du navigateur,
résolution de l'écran...), en particulier pour
la maintenance du code. Pour plus d'informations sur
ce débat qui n'a rien à voir avec PHP, reportez vous
au newsgroup fr.comp.infosystemes.www.auteurs ou fciwa et en particulier
à ses archives sur http://www.deja.com/home_ps.shtml
[Retour à la liste des réponses]
- La différence entre include( ) et require (
)
-
Manuel pour include ( ) [en anglais] [en français]
Manuel pour require ( ) [en anglais] [en français]
include( ) comme require( ) permettent toutes les deux
d'inclure un fichier dans un script php.
Une application pratique courante est de définir des
fonctions dans un script qui sera appelé par include( ) ou
require( ) pour rendre ces fonctions disponibles dans ce
script.
L'instruction require ( ) est traitée avant
l'exécution réelle du script, par le
préprocesseur PHP.
Elle relève plus de la macro que de la fonction.
La fonction include( ) est appelée, si
nécessaire, au cours de l'exécution du
programme.
Par exemple :
if($toto)
{
include("fic1.php3");
require("fic2.php3");
}
Dans ce code, le fichier fic2.php3 sera TOUJOURS inclus dans
le script courant. En revanche, fic1.php3 ne sera inclus QUE si
le test sur $toto renvoie TRUE.
Si pour une raison quelconque vous voulez inclure un fichier juste après
l'avoir généré dynamiquement, vous êtes donc obligé de passer par include ( );
Si vous tenez *vraiment* à faire des versions
différentes de votre site selon le navigateur, ceci peut
vous permettre de définir de deux manières
différentes la même fonction PHP, en adaptant ce
qu'elle doit faire aux spécificités d'IE ou NS (
sorte de couche d'abstraction), ainsi le code du corps de votre
site reste indépendant de tout ça.
[Retour à la liste des réponses]
- Les chemins pour include( ) et require (
)
-
Les deux fonctions ont le même comportement pour aller
chercher le fichier à inclure. Si on fait un
include("../titi.inc"); dans le fichier toto.php3, alors, le
chemin de titi doit être relatif à toto.php3. Dans
cet exemple, il se trouve un répertoire au dessus.
[HS] Chez la plupart des hébergeurs , php est
configuré de manière à interdire l'include de
fichiers d'un répertoire parent.
[Retour à la liste des réponses]
- Des problèmes avec la fonction header( )
Pour tout appel à la fonction header( ),
[en anglais] [en français] il ne doit en aucun cas y avoir un
quelconque caractère retourné au navigateur avant son appel.
En particulier, faire la chasse à des espaces ou des retours à la ligne avant le tag
d'ouverture <? du script php. De même, des problèmes ont été constatés
lors de l'appel à une fonction qui faisait un return; vide dont le code de retour n'était
pas traité dans la fonction appelante, un peu comme si la valeur retournée était parasite.
[Retour à la liste des réponses]
- Mot de passe d'accès à un
répertoire
La quasi totalité des hébergeurs proposent une
interface graphique permettant de protéger l'accès
à un répertoire par un couple (login / mot de
passe).
[HS] Chez free.fr : http://support.free.fr/web/restriction_acces.html
Dans le cas où il vous faudrait faire ceci "à la
main", une réponse sera rédigée en cas de demande. Il suffit en gros de faire un "man htpasswd"
[Retour à la liste des réponses]
- [souvent HS] Problèmes de connexion à
MySQL
Manuel de MySQL (FR):
http://dev.nexen.net/docs/mysql/annotee/manuel_toc.php
Quelques messages d'erreurs rencontrés assez souvent et ce
qu'ils peuvent cacher :
Message d'erreur du genre :
Fatal error : call to unsupported or undefined function
mysql_connect() in [fichier].php3 on line [XXX]
ATTENTION : PHP4 possède un support natif de mysql, ceci n'est applicable QUE à PHP3.
Vérifier que dans le fichier php3.ini une ligne
n'est pas encore commentée à tort.
Par exemple dans ce cas, sous windows, dans la section ;Windows
Extensions il faut enlever le ; devant
extension=php3_mysql.dll (mais donc laisser cette ligne commentée avec PHP4)
Message d'erreur du genre :
- ... Can't connect to mysql server on ...
[HS] Vérifier que le "démon" mysqld (ou
mysqld-shareware) a bien été lancé en ligne
de commande, par "c:\mysql\bin\mysqld.exe --standalone" sous
windows 9x, en tant que service sous Windows NT (c'est le plus simple)
et par "$MYSQL/bin/safe_mysqld &" sous unix (en standard $MYSQL vaudra
/usr/local mais ceci dépend de votre installation).
Message d'erreur du genre :
... Access Denied for user [toto]@localhost ...
[HS]
Si votre script tourne chez un hébergeur, contactez son support
technique et lisez sa documentation interne.
Si vous avez la main sur le serveur MySQL, vérifiez les droits de
connexion de ce [toto] en vous connectant, en ligne de commande, à MySQL en tant
que user root, en faisant une fois connecté un
select * from user where user='[toto]';
et regarder tout
particulièrement la colonne Host.
Voir la section 6 du manuel [en anglais] [en français] de MySQL pour plus
d'informations.
[Retour à la liste des réponses]
- Exemple de fonction de connexion à MySQL
Cette fonction de connexion appelle une fonction fx_footer( ), que vous
devrez définir vous même, avec des arguments qui vous conviennent, par exemple dans le cas où
vous disposez d'un menu de navigation paramétrable. Sinon, un print("</BODY></HTML>"); fera l'affaire.
La terminologie DAD (Database Access Descriptor) est empruntée à Oracle.
Remarque : De manière générale,
il vaut mieux forcer les valeurs par défaut à des
valeurs que vous matrîsez.
function fx_std_connect( )
{
/* remplacer éventuellement localhost par le nom de serveur approprié.
Voir la doc de votre hébergeur. */
$l_dad=mysql_connect("localhost","votre_login","votre_password");
if ($l_dad != TRUE)
{
print("Connexion impossible.\n");
include("std_footer.php3");
fx_footer("parametre1","parametre2");
exit();
}
if(mysql_select_db("votre_base",$l_dad)!=TRUE)
{
print("Database inaccessible.\n");
include("std_footer.php3");
fx_footer("parametre3","parametre4");
exit();
}
return ($l_dad);
}
Pour chaque nouvelle connexion, appeler directement $DAD=fx_std_connect( );
Il va de soit que cette fonction doit être définie dans chaque script où elle est appelée,
le plus simple étant de faire un include("std_connect.php3"); où std_connect.php3 est le fichier qui
en contient sa définition.
Si le fait de mettre ainsi votre login et mot de passe en clair dans un fichier
vous effraie, lisez dans cette FAQ la section appropriée :
"La protection de mes mots de passe de connexion à une base".
[Retour à la liste des réponses]
- La protection de mes mots de passe de connexion
à une base
-
Il existe de nombreuses méthodes permettant de
sécuriser les informations relatives à la connexion
vers une base de données. Nous allons en présenter
ici quelques unes. En premier lieu, précisons qu'il est
pratique de placer ces informations dans un fichier et/ou une
fonction. Cette approche, modulaire, permet de procéder
à des modifications ultérieures avec souplesse
(changement du mot de passe d'accès à la base,
etc.).
Par exemple, dans le cas particulier de MySQL, un fichier
regroupant ces informations pourrait ressembler à celui-ci
:
$host="mon_host";
$user="mon_user";
$password="mon_password";
$acces_bd=mysql_connect($host, $user, $password);
** Première méthode de protection Cas où
vous n'avez pas la maîtrise du serveur qui héberge vos
scripts
Nommer ce fichier en prenant soin de lui attribuer l'extension
.php3 ou .php pour PHP4. Par exemple, base.inc.php3. Par ce simple fait, si un
utilisateur mal intentionné tente d'ouvrir ce fichier
à l'aide d'un simple navigateur, ce fichier sera de toutes
facons "parsé" (interprété) par PHP
coté serveur. Et le navigateur ne renverra rien de visible
au client.
** Deuxième méthode de protection Cas où
vous avez la maîtrise du serveur qui héberge vos
scripts
Rien ne vous empèche de placer le fichier contenant les
informations de connexion à votre base, en dehors de
l'arborescence du serveur HTTP. C'est une bonne approche. Un
serveur HTTP dispose d'une racine en aval de laquelle vont
être placés et interprétés vos scripts
et vos pages. Mais en amont, non. Par exemple, sous Apache, la
racine (DOCUMENT_ROOT) est souvent /usr/local/apache/htdocs. Les
pages et autres scripts se trouvant en aval de cette racine sont
potentiellement visible depuis un navigateur. Il n'en va pas de
même de ceux qui se trouvent en amont. Vous pouvez donc
judicieusement placer votre fichier sous /usr/local/etc par
exemple.
Une autre technique consiste à récupérer le
login et password depuis des variables shell unix par un
getenv();
** Troisième méthode de protection Cas où
vous disposez des droits d'administration de votre base
Une méthode trop souvent ignorée consiste tout
simplement à paramétrer finement les droits
d'accès à votre base. Notamment afin de n'autoriser
des connexions que depuis la machine locale (localhost). De ce
fait, même si un utilisateur mal intentionné dispose
des informations de connexion (et dans le cas où il ne
dispose pas d'accès sur la machine afin d'y déposer
des scripts, bien évidement), il ne pourra pas
accéder à la base. Reportez vous au manuel du sgbd
que vous utilisez.
** Les autres méthodes Ajoutons qu'il est aussi
possible de bricoler les fichiers de configuration des serveurs
HTTP (type Apache) afin de demander au serveur de "parser" les
fichiers .inc ou encore de jouer avec les droits d'accès
à certains répertoires ou fichiers (par le biais
des fichiers .htaccess par exemple), y compris dans des sous
répertoires si l'hébergeur interdit de "remonter"
dans l'arborescence.
[Retour à la liste des réponses]
- Le parcours des tableaux (deux
dimensions)
Réponse en cours de rédaction.
[Retour à la liste des réponses]
- Le multitasking / exécutions parallèles
(UNIX)
Si vous désirez lancer des scripts en parallèle
et/ou en asynchrone (on les lance et on les oublie, on continue
le script courant sans attendre qu'ils se terminent) vous pouvez
utiliser les fonctions PHP exec(), passthru(), ou system().
Par exemple : exec(" nohup toto.sh &
>mon_log.txt");
En revanche, il faudra analyser le résultat en
disséquant ("parser") le fichier de log : ouvrir ce
fichier avec fopen(); puis le lire ligne par ligne en cherchant
des erreurs éventuelles, etc...
[Retour à la liste des réponses]
- L'upload de fichiers
Remarque : il est inutile de stocker des fichiers complets dans une base de
données, leur chemin suffit. Une exception néanmoins si le but est de faire du
PHP dynamique avec eval() mais ce seront des "petits" fichiers.
En particulier, il est rigoureusement inutile de stocker des fichiers binaires comme des images dans une base de données.
A voir dans la doc :
http://www.php.net/manual/features.file-upload.php [en anglais] ou
http://www.php.net/manual/fr/features.file-upload.php [en français]
Prérequis dans le formulaire :
- le formulaire doit être en encodage (enctype)
multipart/form-data et en méthode POST.
< form action="script.php3" enctype="multipart/form-data" method="POST" >
- un champ (en général caché) nommé
MAX_FILE_SIZE dont la valeur sera la taille maximale
acceptée pour les fichiers, exprimée en octets. Ce
champ est facultatif.
<input type="hidden" name="MAX_FILE_SIZE" value="1000">
- un champ de type "file", le nom n'importe pas, appelé
UploadedFile pour la suite.
<input type="file" name="UploadedFile" >
Gestion dans le script :
Le script recevant le formulaire va créer 4 variables
:
- $UploadedFile qui contient le nom et chemin vers le fichier
temporaire créé sur le serveur.
- $UFile_name : le nom du fichier tel qu'il est chez le
client
- $UFile_size : la taille du fichier exprimée en
octets
- $UFile_type : le type MIME du fichier
Si la taille du fichier envoyé était
supérieur à MAX_FILE_SIZE, $UploadedFile contient "none"
et $UFile_size est nulle, le fichier n'est pas accessible.
Reste donc simplement à déplacer ou copier le
fichier temporaire dans un autre répertoire. Par exemple :
$DOCUMENT_ROOT."/upfiles/".
Le répertoire cible doit être accessible en
écriture. On peut le vérifier avec
is_writeable($DOCUMENT_ROOT."/upfiles/")
http://www.php.net/manual/function.is-writeable.php3 [en anglais] ou http://www.php.net/manual/fr/function.is-writeable.php3 [en français]
Ensuite donc, on déplace : la fonction copy ( ) est utilisée car rename( ) ne fonctionne pas toujours en multivolumes.
if (!copy($UploadedFile, $DOCUMENT_ROOT."/upfiles/".$UFile_name))
//http://www.php.net/manual/function.copy.php
//http://www.php.net/manual/fr/function.copy.php
print("Impossible de déplacer ".$UploadedFile." vers " .$DOCUMENT_ROOT."/upfiles/".$UFile_name." <br>\n");
Des problèmes ont été constatés avec le code ci-dessus sur windows.
Il semblerait que ceci soit à cause, au moins sous php3 (php4 ?) des settings de php3.ini
Merci à Alain CHABERNAUD (caribert@club-internet.fr) pour son php3.ini
Ici, php3 est installé sur le disque logique d:
Le fichier temporaire se trouve sous le répertoire racine, dans ce cas sous d:\
Il s'agit d'un fichier nommé php2, php3 etc, qui est automatiquement détruit
dès la fin du script.
;;;;;;;;;;;;;;;;;;;;;;;;;
; Paths and Directories ;
;;;;;;;;;;;;;;;;;;;;;;;;;
include_path = .;d:/php3; d:/php3/temp;c:/windows;d:/apache/server
doc_root = ; the root of the php pages, used only if nonempty
user_dir = ; the directory under which php opens the script using /~username, used only if nonempty
upload_tmp_dir = d:/ ; temporary directory for HTTP uploaded files (will use system default if not specified)
upload_max_filesize = 2097152 ; 2 Meg default limit on file uploads
extension_dir = d:/php3 ; directory in which the loadable extensions (modules) reside
[Retour à la liste des réponses]
- Gérer les sessions utilisateur
Trois solutions s'offrent à vous suivant vos besoins :
- coder votre propre gestion de session
- utiliser l'excellente PHPLib
- utiliser PHP4
Ressources :
Site officiel de la PHPLib
http://phplib.netuse.de/
NewsGroup dedié à la PHPLib
news://news.netimages.com/php3.phplib
Archives de la liste PHPLib du site PHPBuilder
http://www.geocrawler.com/lists/4/Web/195/0/
Pour gérer vous même vos sessions, il vous faut un générateur aléatoire
d'identifiants, que vous transmettrez ensuite dans l'URL.
Deux grandes méthodes sont utilisées pour coder un générateur d'identifiants. La
première consiste à se donner une liste de caractères autorisés et à "piocher"
aléatoirement dans cette liste le nombre de fois voulu. La seconde repose sur le système
d'exploitation et des "bidouilles" plus ou moins personnelles à chaque
développeur, faisant appel à des concaténations de l'heure système et du PID du
process courant par exemple.
[Retour à la liste des réponses]
- Comptabiliser le nombre courant de personnes
"connectées" sur le site
Disposant d'un identifiant unique par session, vous pouvez stocker ces
identifiants dans une table d'un SGBD, avec une colonne de fonctionnalité "timestamp" qui
permettra de savoir quand l'enregistrement a eu lieu (mis systématiquement à
l'heure système). Vous pouvez alors sélectionner toutes les sessions différentes "actives"
dans, mettons, les 3 dernières minutes : souvenons nous que HTTP sur TCP/IP est un protocole
utilisé en mode non connecté, il n'y a personne qui soit connecté (au
sens ouverture de session avec authentification et fermeture explicite de session)
à votre serveur en regardant vos pages.
Vous pouvez aussi vous servir de telles tables pour "suivre à la trace" les
visteurs par leur identifiant. Notez que l'adresse IP de votre visiteur n'est
a priori pas un identifiant fiable.
Remarque : si vous ne stockez qu'un identifiant qui n'a aucun lien direct avec
l'internaute que vous "pistez", vous n'êtes en rien en contradiction avec la
CNIL.
[Retour à la liste des réponses]
- Suivre ses visiteurs sur son site / l'adresse IP de vos visiteurs
-
La solution la plus simple consiste à utiliser des identifiants de session
transmis d'une page à l'autre.
Les autres solutions côté serveur (à l'exclusion, donc, des cookies qui sont côté
client) mettent en jeu plusieurs variables PHP :
Dans le cas où il n'y a pas de proxy(s) entre le client et le script php,
$REMOTE_ADDR est l'adresse IP du client.
Dans le cas où il y a un (au moins) proxy, les variables $HTTP_X_COMING_FROM et
$HTTP_VIA sont positionnées.
Attention donc, il n'est pas fiable d'utiliser $REMOTE_ADDR comme
identifiant.
Si le problème vous intéresse, consultez la fonction GetIdentifier
de Marc Meurrens : http://www.cgsa.net/php/?script=identifier
[Retour à la liste des réponses]
- Remplacer les retours chariots dans une
chaine
$chaine = ereg_replace("(\r|\n){1,2}", " ", $chaine);
[Retour à la liste des réponses]
- Les expressions
régulières
Sujet trop vaste pour être traité dans une FAQ de
NG. Des exemples sont présents dans cette FAQ.
[Retour à la liste des réponses]
- Tester la validité d'une adresse email
-
A titre d'exemple des regexp, on peut considérer le test ci dessous, permettant
de juger assez grossièrement si la chaîne $email semble être une adresse
valide.
$email=toto@coincoin.com;
if (ereg("^(.+)@(.+)\\.(.+)$",$email, $tableau)
{...}
Pour une fonction beaucoup plus fine, utilisez le code proposé par
Marc Meurrens en suivant ce lien : http://www.cgsa.net/php/?script=email
[Retour à la liste des réponses]
- L'affichage de résultats de requêtes par
tranches
Lorsqu'une requête SQL renvoie un grand nombre d'enregistrements,
on choisit souvent de n'afficher qu'un sous-ensemble de ceux-ci
et de proposer à l'utilisateur de naviguer entre plusieurs
pages de réponses (à la façon des moteurs de
recherche).
Pour cela, plusieurs solutions sont possibles pour afficher les
réponse $deb à $fin (deux variables passées
en paramètre dans l'URL).
Nous en présentons ici trois.
1) Faire une série de requêtes SQL classiques et
traiter en retour :
Avantages :
Compatible avec toute les bases.
On peut connaitre facilement le nombre total de réponses
avec mysql_num_rows()
Inconvénient :
cette méthode est sous-optimale en terme d'accès au
sgbd et en post-traitement
$res = mysql_query("select nom, prenom from personne where age=30");
/* Boucler sur les résultats, en filtrant à l'affichage : */
$i = 0;
while ($a = mysql_fetch_row($res))
{
if (($i >= $deb) && ($i <= $fin))
afficher_rang($a);
$i++;
}
2) Utiliser la clause LIMIT du select de MySql :
Avantage :
Utilisation optimale de MySql (et tout autre base acceptant un
mécanisme semblable)
Inconvénients :
Non applicable à la plupart des sgbdr (qui n'acceptent pas
cette notion de LIMIT)
On ne connait plus le nombre total de réponses. Pour
l'obtenir il faut effectuer une requête
supplémentaire lors avant la première tranche
à afficher :
select count(*) from personne where age=30
$query = "select nom, prenom from personne where age=30 LIMIT $deb ,$fin ";
$res = mysql_query($query);
while ($a = mysql_fetch_row($res))
affiche_row($a);
/* Lien avec $deb et $fin2 en paramètre pour la page
suivante */
$fin2 = $fin-$deb +1;
$deb=$fin2;
3) Utiliser une table temporaire / tampon :
Avantages :
Totalement compatible / portable quel que soit le sgbdr
utilisé.
Compromis correct en utilisation des ressources.
Inconvénients :
Nécessite une table supplémentaire et un
identifiant requête (ou session).
Remarque : la gestion des identifiants session est
disponible dans cette FAQ.
Ci-dessous, les grandes lignes de la méthode. Un
document plus détaillé est disponible
donnant un exemple de moteur de recherche affichant ses résultats page par page.
1 - Créer une table fille, qui contient tout les champs de
la table mère qu'on veut rendre disponible à la
requête + 3 autres champs:
- une colonne id_session, contenant l'id de session du visiteur
qui permettra d'identifier le résultat de la requête
du visiteur, clef primaire de la table avec l'ordre_session.
- une colonne ordre_session qui sera incrémentée
par chaque enregistrement d'une ligne de la requête sur la
table mère.
- une colonne temp_session de type timestamp qui permettra de
connaitre la date de création des lignes de la
requête pour les purger le moment venu.
2.1 - On fait la requête sur la table mère. Avec le
résultat on l'insère ligne par ligne dans la table
fille, en n'oubliant pas de créer pour chaque ligne un
champ ordre-session incrémenté de 1, et deux champs
id_session et temp_session identiques pour toutes les lignes de
cette requête. On peut ici limiter le nombre maximum
d'enregistrements à présenter. On dispose alors du
nombre total de lignes à afficher par tranches,
$nombre_lignes.
2.2 - On purge la table des enregistrements dont le temp_session
>= 20 minutes. (par exemple).
3 - On crée une variable borne_inferieure = 1. On
crée ensuite une variable $borne_superieure =
$borne_inferieure + $nombre_lignes;
En boucle pour chaque tranche :
4 - On fait une requête du style:
SELECT * FROM table_fille WHERE id_session='$id_visiteur'
AND ordre_session > $borne_inferieure AND ordre_session < $borne_superieure
ORDER BY ordre_session;
5 - On incrémente $borne_inferieure = $borne_superieure +
1; et $borne_superieure += $nombre_lignes;
(ou $borne_superieur=$nombre_lignes; si dépassement).
6 - On crée un lien contenant $id_session du
visiteur,$borne_inferieure, $borne_superieure et $nombre_lignes.
Retour acte - 5.
(sauf si $borne_inférieure >$nombre_lignes car
dernière page)
[Retour à la liste des réponses]
- Vérifier la présence d'un
enregistrement avant de le mettre à jour
-
(La stratégie d'update / insert, limite hors sujet )
Pour vérifier la présence d'un enregistrement avant
de le mettre à jour on peut procéder de la manière suivante :
- Faire un select dans la table appropriée.
- Tester le retour du nombre de rangs, par exemple grâce
à mysql_num_rows ()
- Si l'enregistrement n'existe pas, alors on fait un
insert.
Sinon, on fait un update.
Une méthode plus rapide est la suivante :
Lancer l'update. Si le nombre de rangs mis à jour est
égal à zéro, c'est que le rang n'existait
pas dans la base.
Il n'y a plus qu'à l'insérer.
Comparaison du code des deux méthodes :
$result=mysql_query("SELECT * FROM ma_table WHERE ma_clef='$MA_VAR'");
$nbre_rangs=mysql_num_rows( $result);
if ($nbre_rangs == 1)
{
$modif=mysql_query("UPDATE ma_table SET colonne=colonne+1 WHERE ma_clef='$MA_VAR'");
if (!$modif)
{
return(FALSE);
}
}
else
{
$modif=mysql_query("INSERT INTO ma_table VALUES ('$MA_VAR',0)");
if (!$modif)
{
return(FALSE);
}
}
Deuxième méthode :
/* $DAD = Database Access Descriptor, retour de mysql_connect() */
if (! mysql_query("UPDATE ma_table SET colonne=colonne+1 WHERE ma_clef='$MA_VAR'"),$DAD)
{
if(mysql_affected_rows($DAD)==0)
mysql_query("INSERT INTO ma_table VALUES ( '$MA_VAR', 0)",$DAD);
}
Il est à noter que le code de la deuxième
méthode, beaucoup plus compact et plus performant, est
néanmoins plus permissif car il n'intègre pas de
gestion des erreurs.
NB : dans le cas de MySQL intéressez vous à la commande REPLACE.
[Retour à la liste des réponses]
- Générer des graphiques avec
PHP
Il est possible d'afficher des statistiques sous forme de graphe
avec PHP. Intéressez vous pour ceci à la GD
LIB.
Il est à noter qu'à cause de problèmes de copyrights et de décalage entre PHP
et la GD lib, vous pouvez avoir des problèmes de compilation.
GD Lib :
http://www.boutell.com/gd/
Pour vous procurer d'anciennes versions de la GD Lib, avec support des GIFs :
http://rufus.w3.org/linux/RPM/GByName.html
Merci à Patrick Michelin (pmich@wanadoo.fr) pour ce lien.
Une bibliothèque qui s'appuie sur la GD LIB :
vh graph : www.vhconsultants.com
[Retour à la liste des réponses]
- Lancer des commandes à intervalles
réguliers ("crontab")
Commencez avant tout par vérifier si votre script doit être
absolument lancé à une heure précise en rapport direct
avec le temps newtonien. Ceci est en fait assez rare, et est en général
lié à des traitements assez longs à exécuter de
nuit.
Dans beaucoup de cas, vous pourrez vous passer de crontab. Considérons
par exemple la purge de données obsolètes. "Tous les jours à
minuit" est une approche, mais en fait, il suffit de purger avant la prise en compte
ou l'affichage de ces données. Il suffit donc d'appeller un script de purge
avant le traitement. On peut ensuite par exemple utiliser un fichier de configuration sur
le serveur (un peu comme un cookie) ou tester l'heure courante par rapport à une plage horaire
pour éviter de lancer la purge à chaque appel.
Dans certains cas, néanmoins, cette méthode n'est pas applicable.
L'idéal est bien sûr alors d'avoir accès à une crontab.
Sinon, on peut faire appel à des services de sites qui appelleront
votre script à l'heure voulue comme par exemple:
http://www.witbe.net/
Il est également parfois possible de faire un "daemon" en PHP, grâce
à une boucle infinie testant la présence d'un fichier par
exemple, mais attention aux obstacles suivants :
- Dans la plupart des cas le temps maximum d'exécution d'un script est limité, en
particulier par un paramètre de php3.ini. Ce temps semble être
du temps CPU, mais ceci est à confirmer.
- Attention à ne pas oublier de faire un appel à la fonction
clearstatcache( ) si vous utilisez effectivement un test sur la présence
d'un fichier pour arrêter votre démon ou c'est la boucle infine
garantie.
[Retour à la liste des réponses]
- Envoi d'un mail.
Utilisez ou disséquez la très bonne classe de gestion de Léo West, disponible sur http://lwest.free.fr/doc/php/lib/Mail/
[Retour à la liste des réponses]
- Comportement bizarre : un bug PHP ?
-
Quand un script se comporte étrangement, la probabilité la plus
forte est que c'est votre script qui se plante, ou que les permissions des
fichiers que vous traitez sont mauvaises. Néanmoins, il y a des bugs
(ou des "problèmes résiduels" ((C) A.F. 2000)...) aussi dans PHP, il
peut donc être intéressant de les connaître, surtout si
vous utilisez une version un peu ancienne de PHP.
La liste officielle des bugs déclarés est disponible sur le site de PHP :
http://bugs.php.net/
- Où poser des questions non directement
liées à PHP
Certaines questions sont indiquées comme HORS SUJET. Si
cette FAQ ne suffit pas à résoudre vos
problèmes sur ces questions là, voici une liste de
ressources appropriées selon le type de question :
[Retour à la liste des réponses]
- Problèmes avec un hébergeur
:
-
Avant tout, le support technique de cet hébergeur !!
[Retour à la liste des réponses]
- Référence HTML
Norme 4.0 du W3C : http://www.w3.org/TR/REC-html40/
All Html (en français) : http://www.allhtml.com/
[Retour à la liste des réponses]
- Problèmes avec du SQL, MySQL, Postgres, Oracle, Sybase, etc... :
-
Un newsgroup en français : fr.comp.applications.sgbd
http://www.mysql.org/doc.html
[Retour à la liste des réponses]
- Autres ressources et aide sur PHP
- Ouvrages "papier"
-
Programmtion web avec PHP (quatre co auteurs)
Editions Eyrolles. 360 pages. http://clauer.free.fr/livrephp.php3
- Programmation en PHP par Leon Atkinson
Editions Campus Press. 450 pages, environ 200F.
Remarque : la première édition comporte de nombreuses erreurs de traduction.
Une deuxième édition relue par Marc Meurrens est disponible.
Voir http://www.cgsa.net/php/campusPress
- Professionnal PHP programming (cinq co auteurs)
Editions Wrox. 900 pages, environ 360 F.
- Pages Web dynamiques avec ASP-PHP-SQL de Jean-Marc
Herellier et Philippe Mérigod.
Editions Campus Press.
- Sites internet, donnés sans ordre de
préférence.
- Sites officiels : (en anglais)
- Traductions des manuels PHP et MySQL chez Nexen (pouvant être encore
incomplètes) :
http://dev.nexen.net/docs/
- Archives du NG fr.comp.infosystemes.www.auteurs.php
- Sites consacrés à PHP.
[Retour à la liste des réponses]
- Points juridiques
Autorisation est donnée à quiconque le souhaite de
faire du "framing" pour afficher cette FAQ ou de la recopier et de la diffuser
sans la modifier.
N'hésitez pas à nous contacter si vous
avez besoin d'une autorisation pour en citer des parties.
La totalité des informations contenues dans cette FAQ est
disponible sur internet et considérée comme de
notoriété publique.
Tous les noms de produits et
autres marques cités dans cette FAQ sont des marques
déposées par leurs propriétaires respectifs.
L'intégralité du code cité est le fruit de
la rédaction des auteurs de cette FAQ, tiré de
code diffusé publiquement sur des forums de discussion ou avec
autorisation de l'auteur.