Si vous débutez dans le développement PHP, vous serez sans doute amené à vous posez des questions durant votre apprentissage. Cette Foire Aux Questions du forum PHP a été élaborée pour être à la fois un complément des tutoriels officiels et pour expliquer les erreurs qui reviennent de manière récurrente sur le forum.
Vous trouvez cette F.A.Q. incomplète ou vous voulez rajouter une partie ? N'hésitez pas contacter par MP l'un des contributeurs pour proposer vos propres Q/R afin de les intégrer dans cette F.A.Q. !
Si vous avez ce genre d'erreur, c'est que vous tentez de redéclarer une fonction de votre script alors qu'elle existe déjà.
Vérifiez donc que :
dans le script de votre page, vous ne l'avez pas déclarée explicitement plus d'une fois. Une seule fois suffit
la déclaration de votre fonction ne se situe pas dans une boucle. Si c'est le cas, sortez-là de cette boucle.
vous ne faites pas plusieurs include … d'un fichier contenant cette fonction (surtout si vous faites des inclusions "à tiroirs" ou "en cascade"). Afin d'éviter d'inclure plusieurs fois le même fichier, utilisez la fonction include_once, qui vérifie si le fichier est déjà inclus ou non, afin d'éviter les doublons.
Fatal error: Call to a member function fetch() on a non-object in...
Cette erreur se produit lorsque l'on appelle la méthode fetch(), fetchAll() ou équivalent sur une requête qui comporte des erreurs. Cela peut être un nom de table ou de champ incorrect, le nommage d'un champ de la table identique à un mot de la syntaxe SQL, un espace avant ou après un nom de champ, etc.
Les E_WARNING, alias Warning sont des erreurs d'exécution qui ne provoquent pas l'arrêt du script.
Quelques Warning souvent rencontrés :
Warning: Division by zero in ..
Vous tentez d'effectuer une division par 0, chose qui, vous le savez tous, est impossible
Warning : Cannot modify header information – headers already sent by
Vous tentez de modifier les en-têtes (headers) d'une page après avoir effectué une sortie vers le navigateur (envoi d'au moins un caractère au navigateur, même un espace). N'oubliez pas que le code HTML doit toujours être envoyé après la dernière modification sur les en-têtes.
Soyez tout particulièrement vigilant sur ce point lorsque vous appelez la fonction setCookie().
Si vous n'avez pas le choix, vous pouvez mettre en place un système de bufferisation avec ob_start() et ob_end_flush.
Warning : Invalid argument supplied for
Vous appelez une fonction en lui passant un argument incorrect.
Les E_NOTICE, alias Notice sont des erreurs d'exécution non critique qui ne provoquent pas, par conséquent, l'arrêt du script.
Quelques Notice souvent rencontrés :
Notice: Undefined variable: maVariableNotice: Undefined index: id
Dans le premier cas, vous avez peut être tenté d’additionner deux variables, dont une des deux n'existe pas. Dans le second cas, vous récupérez peut être une variable de type GET ou POST qui n'a pas été définie.
Pour éviter cette erreur, pensez à toujours tester vos variables - et a fortiori les variables GET et POST - avec la fonction php isset().
Notice: Uninitialized string offset
Cette erreur peut se produire lorsque vous essayez d'accéder à une case d'un tableau qui n'existe pas ou quand vous tentez d'accéder à un élément de ce que vous croyez être un tableau mais qui n'est en réalité qu'une chaîne de caractères
Notice: Use of undefined constant maVariable
Cette erreur résulte généralement de l'oubli du $ devant maVariable.
Les E_PARSE, alias Parse error sont souvent des erreurs d’inattention et résultent d'un problème de syntaxe dans le code (point-virgule oublié, parenthèse manquante, etc.)
Donc contrairement à isset(), empty() tient compte de la valeur de la variable, et renvoie false pour les valeurs suivantes :
"" (une chaîne vide)
0 (0 en tant qu'entier)
0.0 (0 en tant que nombre à virgule flottante)
"0" (0 en tant que chaîne de caractères)
null
false
array() (un tableau vide)
$var; (une variable déclarée, mais sans valeur assignée)
Table de vérité :
Valeur
isset($a)
empty($a)
$a = ''
true
true
$a = 1
true
false
$a = 0
true
true
unset($a)
false
true
$a = ' '
true
false
$a = 'a'
true
false
$a = null
false
true
$a = false
true
true
$a = true
true
false
Un champ de formulaire vide retourne une chaîne de caractères vide
Ce qui signifie que isset($_POST['monChamp']) retournera truemême si le champ n'a pas été rempli. En conséquence, utilisez !empty($_POST['monChamp']) pour vérifier si l'utilisateur a bien mis une valeur dans un champ.
Que signifient le ? et le : dans $b = isset( $a) ? $a : 0 ?
C'est une condition sous la forme ternaire.
La forme ternaire s'utilise ainsi : condition ? valeur_si_vrai : valeur_si_faux;
Un équivalent du code ci-dessus serait :
L'arobase (@) sert à masquer les erreurs que retourne php.
Il est conseillé de s'en servir uniquement si l'on est certain de gérer correctement ses erreurs, et surtout pas pour cacher les erreurs de programmation ou de conception que l'on fait.
Exemple correct :
if( $compteur = @fopen( 'compteur.txt' ) ) {
// instructions
} else {
// action à entreprendre en cas d'échec d'ouverture du fichier
}
Exemple incorrect :
echo @htmlspecialchars( $_GET['var'] ); // on cache une notice de variable indéfinie
Mes variables de sessions disparaissent après rechargement d'une page, pourquoi ?
Si vous rencontrez ce problème, il est fort probable que la configuration de php sur votre hébergement soit établi avec le register_globals activé.
Pour le vérifier, faites un :
echo ini_get('register_globals');
Si vous obtenez 1, c'est que malheureusement celui-ci est activé sur votre hébergement.
Depuis PHP 5.4, la directive register_globals n'existe plus
Qu'est-ce que le register_globals ?
C'est une directive de php qui transforme les variables super-globales ($_SESSION, $_POST, $_GET, $_COOKIE, etc..) en variables simples, c'est à dire que si l'on définit une variable de session du nom de pseudo ($_SESSION['pseudo']) , une variable $pseudo sera automatiquement créée.
En quoi cela pose t-il problème ?
Si vous avez déclaré une variable $_SESSION['pseudo'] dans une page, et que sur une seconde page vous utilisez une variable $pseudo, $_SESSION['pseudo'] sera écrasée par la variable $pseudo.
Si vous avez malencontreusement omis d'initialiser une variable dans votre script, un problème de sécurité survient, car l'utilisateur pourra la créer en l'ajoutant dans l'url de votre page
Il est vital de toujours initialiser ses variables, register_globals activé ou pas
Comment régler le problème ?
Si vous avez de la chance, votre hébergeur autorise sa modification via un fichier .htaccess. Ajoutez donc un tel fichier avec cette ligne (ou ajoutez-la au .htaccess existant) :
php_flag register_globals off
Si vous obtenez une
erreur 500 : Internal Server Error
C'est que pas de chance pour vous, vous ne pouvez pas modifier cette directive.
Dans ce cas, la meilleure des solutions est de nommer différemment les variables super-globales en les préfixant pour les distinguer des autres variables "simples" de votre script.
Ainsi $_SESSION['pseudo'] pourrait devenir par exemple $_SESSION['sess_pseudo']. De cette manière, il n'y aurait plus de risque d'écrasement.
Il faut déjà définir quel type d'encodage on se sert dans ses pages et s'y tenir pour tout.
Les éléments à vérifier lorsque l'on a ce type de problème sont les suivants :
Vérifier le type d'encodage utilisé dans votre éditeur de texte (voir les options de celui-ci) Certains éditeurs ne proposent pas l'iso-8859-1 dans les options (Notepad++ par exemple), on choisira alors pour eux le format ANSI
Vérifier que le charset de la balise <meta /> utilisée dans vos pages html est le bon
<!-- Encodage en utf-8, en XHTML -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Encodage en utf-8, en HTML 5 -->
<meta charset="utf-8" />
<!-- Encodage en iso-8859-1, en XHTML -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<!-- Encodage en iso-8859-1, en HTML 5 -->
<meta charset="iso-8859-1" />
Vérifier le type d'encodage utilisé par php par défaut s'il est établi (fichier php.ini)
echo ini_get('default_charset');
Modifier s'il ne correspond pas à votre encodage, la valeur de default_charset dans le fichier php.ini (conseillé si vous en avez la possibilité), ou en spécifiant le nouvel encodage dans l'entête avec header().
// Encodage d'une page html en utf-8
header('Content-Type: text/html; charset=utf-8');
// Encodage d'une page html en iso-8859-1
header('Content-Type: text/html; charset=iso-8859-1');
Spécifiez les variables de connexion/client de MySQL Pour cela, ajoutez ;charset=[jeu de caractères] au premier paramètre du constructeur de PDO. Le jeu de caractères à spécifier est celui dans lequel sont vos pages et scripts, indépendamment de celui dans lequel sont vos données.
Pour de l'UTF-8, on utilisera utf8 ; pour de l'iso-8859-1, latin1.
Si vous travaillez avec une version de PHP < 5.3.8, ce paramètre n'est pas pris en compte
Il faut dans ce cas ajouter une commande que PDO lancera à chaque ouverture de connexion. Passez en quatrième paramètre du constructeur de PDO un tableau comme celui-ci
// Encodage en utf-8
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'");
// Encodage en iso-8859-1
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'latin1'");
Cette solution est prévue pour MySQL uniquement (comme le dénote MYSQL dans MYSQL_ATTR_INIT_COMMAND). A vous de l'adapter pour votre SGBD
Avec la classe PDO, vous pouvez directement spécifier l'encodage utilisé pour le dialogue entre PHP et MySQL lors de la création de l'objet PDO via le DSN :
$bdd = new PDO('mysql:host=host;dbname=ma_base;charset=UTF8', 'user', 'pass');
Paramétrez l'encodage de travail des fonctions qui le permettent
Certaines fonctions (notamment htmlentities(), html_entity_decode(), htmlspecialchars(), et la plupart des fonctions str*()) retournent les chaînes de caractères dans un jeu précis, et n'acceptent que ce jeu précis comme entrée. Ainsi, alors que PHP avant 5.4 utilisait iso-8859-1, dès PHP 5.4, on est en UTF-8. Solution pour htmlentities(), html_entity_decode() et htmlspecialchars() : spécifiez les deuxième et troisième paramètres
*Solution pour les fonctions `str()** : utilisez leurs équivalents mb_str*() ou [activez mbstring.func_overload` pour le "groupe 2"](http://php.net/fr/mbstring.overload.php)
Vérifier que l'encodage de la base de données est le bon
Ce point est facultatif, mais si vous souhaitez qu'il y ait une grande cohérence entre vos scripts et vos données, cela ne peut pas faire de mal.
Pour un site en iso-8859-1, on utilisera généralement une collation latin1_swedish_ci, pour un site en utf-8 une collation en utf8_general_ci. Plus d'infos concernant les collations. On notera que, depuis MySQL 5.5.3, deux nouvelles collations ont fait leur apparition : utf8mb3, qui est la même chose que utf8, et utf8mb4, qui permet d'utiliser tout le potentiel d'UTF-8, moyennant parfois des possibilités d'enregistrement amoindries (les caractères prenant plus de place, on pourra en enregistrer moins). Cette nouvelle collation est à considérer si vous savez que votre site utilisera une large palette d'alphabets non latin, cyrillique ou grec. Pour plus d'informations, je vous conseille de lire ceci
Si vous respectez tous ces points, vous ne devriez plus avoir de problèmes d'affichages de caractères corrompus dans vos pages.
L'utilisation des fonctions utf8_encode() et utf8_decode() est à considérer comme ultime recours, dans le cas où vous ne pouvez réellement pas faire autrement
Comment utiliser une méthode d'une classe comme fonction de callback, comme le second paramètre de preg_replace_callback(), par exemple ?
Pour ce genre de cas, il faut utiliser un tableau contenant une instance de la classe puis le nom de la méthode. C'est ce tableau qui sera passé comme deuxième argument à preg_replace_callback().
Exemple :
class blabla{
function parser($matches){
return '<div class="code">'.$matches[1].'</div>';
}
function plop($content){
preg_replace_callback(
'#<code>(.+)</code>#',
array($this,'parser'),
$content
);
}
}
Notez bien que l'ordre array(instance de la classe, nom de la méthode) est important
Comment vérifier que ma variable est un nombre entier, une chaîne alphabétique ou alphanumérique ?
Il existe toute une panoplie de fonctions bien pratique pour vérifier cela : les fonctionsctype_*().
if( ctype_digit( $var ) ) {
echo '$var est une chaîne contenant des entiers';
} else if( ctype_alpha( $var ) ) {
echo '$var est une chaîne contenant les lettres de a à z (minuscules et majuscules)';
} else if( ctype_alnum( $var ) ) {
echo '$var est une chaîne contenant des chiffres et lettres';
}
$chaine = ' J\'aime pas les espaces qui servent à rien ! ';
$chaine_propre = trim($chaine); /J'aime pas les espaces qui servent à rien !/
Et si je veux enlever seulement ceux en début de chaine ?
Pas de panique il existe aussi une fonction : la fonction ltrim()PS : Pour ceux qui ne l'auraient pas vu il y a un 'l' devant pour signifier 'left' c'est à dire gauche et donc par conséquent 'enlever les espaces situées à gauche' de la chaine.
Exemple :
$chaine = ' J\'aime pas les espaces qui servent à rien ! ';
$chaine_propre = ltrim($chaine); /J'aime pas les espaces qui servent à rien ! /
Et si je veux enlever seulement ceux en fin de chaine ?
Par déduction, il suffit de rajouter un 'r' pour 'right' et de faire avec la fonction rtrim().
Bravo, c'est aussi simple que ça
Exemple :
$chaine = ' J\'aime pas les espaces qui servent à rien ! ';
$chaine_propre = rtrim($chaine); / J'aime pas les espaces qui servent à rien !/
Et si je ne veux effacer QUE les tabulations par exemple ?
Il est possible de choisir le type de caractère que l'on souhaite effacer.
Pour cela il suffit de renseigner le deuxième paramètre de la fonction trim().
Exemple :
$chaine = " J\'aime pas les tabulations ! \t";
$chaine_propre = trim($chaine, "\t"); / J\'aime pas les tabulations ! /
trim(), ltrim(), rtrim() effacent par défaut aussi les caractères suivants :
" " (ASCII 32 (0x20)), une espace ordinaire.
"\t" (ASCII 9 (0x09)), une tabulation.
"\n" (ASCII 10 (0x0A)), une nouvelle ligne (line feed).
"\r" (ASCII 13 (0x0D)), un retour de chariot (carriage return).
"\0" (ASCII 0 (0x00)), le caractère NUL.
"\x0B" (ASCII 11 (0x0B)), une tabulation verticale.
Et si je veux enlever n'importe quel autre caractère ?
C'est aussi possible, il suffit pour cela de mettre simplement celui (ou ceux) que vous souhaitez enlever en deuxième argument.
Exemple :
$chaine = 'les sssss en moinsssss';
$chaine_propre = trim($chaine, 's'); /les sssss en moin/
$chaine = 'pas de ponctuation !?';
$chaine_propre = trim($chaine, ' !?.;:'); /pas de ponctuation/
Comment faire des actions différentes sur mon formulaire en fonction du bouton submit utilisé ?
La solution est simple : il suffit de mettre l'attribut name à chaque <input type="submit" /> de votre <form>, et de tester dans votre script lequel a été utilisé.
Vous pouvez le faire directement en spécifiant une extension .phps à votre fichier dans l'url si votre hébergeur l'autorise.
Sinon, tentez d'ajouter ceci dans un fichier .htaccess :
AddType application/x-httpd-php-source .phps
Si vous êtes maître du serveur, vous pouvez même ajouter cela dans httpd.conf
Il est aussi possible de le faire uniquement en PHP, en ajoutant ces trois lignes au début d'un fichier :
function br2nl($string) {
return str_replace(nl2br("\n"), "\n", $string);
// Vous pouvez remplacer nl2br("\n") par '<br>' ou '<br />' selon votre version de php
}
Notez qu'il y a aussi la chaîne de formatage L qui, passée à date() ou à Datetime::format(), retourne 1 si l'année est bissextile, et 0 dans le cas contraire.
function verif_email($email) {
// On scinde l'adresse au niveau de la première arobase (s'il y en a deux…)
list($user, $domaine) = explode('@', $email, 2);
// On vérifie qu'il y a un enregistrement MX (Mail eXchange) pour le domaine
return checkdnsrr($domaine, "MX");
}
Exemple :
if (verif_email('siteduzero@hotmail.com)) {
echo 'hotmail.com existe bien';
} else {
echo 'hotmail.com n\'existe pas';
}
Résultat
hotmail.com existe bien
La fonction checkdnsrr() n'est disponible sur système Windows depuis PHP 5.3 seulement
Dans le cas où vous avez un environnement de test qui n'implémente pas cette fonction, vous pouvez la créer. La proposition ci-dessous ne retourne qu'un simple booléen, dans le but unique d'éviter la génération d'une erreur fatale du fait que la fonction n'existe pas.
if (!function_exists('checkdnsrr')) {
function checkdnsrr() {
return true;
}
}
Comment passer plusieurs informations dans des champs de formulaires portant le même name lors d'une soumission ?
Simplement en indiquant que l'on passe un tableau, ce que les champs de formulaires gèrent nativement.
On indique que des champs de formulaires font partie d'un tableau en ajoutant une paire de crochets dans la valeur de l'attribut name.
Dans le cas de séries de cases à cocher, seules les valeurs des éléments cochés seront envoyées
Le résultat de print_r($_POST['plop']) sera donc un tableau et vaudra, si les deux cases ont été cochées :
Array
(
[0] => 10
[1] => 20
)
Le résultat de print_r($_POST['plop']) vaudra, si seulement la première des deux cases a été cochée :
Array
(
[0] => 10
)
Il est évidemment possible de le faire avec des champs ou l'attribut type est autre que checkbox.
C'est aussi la manière de faire si vous utiliser l'attribut multiple de la balise <select>
Exemple avec des ids d'une table passées dans des cases à cocher, pour modification de l'état d'une colonne des lignes de la table :
if (!empty($_POST['listeId']) && is_array($_POST['listeId'])) {
$_POST['listeId'] = array_unique(array_map('intval', $_POST['listeId']));
// Mise à l'état actif des ids reçus
$sql = 'UPDATE uneTable SET etat=1 WHERE id IN(' . implode(',', $_POST['listeId']) . ')';
$result = $pdo->exec($sql);
// Mise à l'état inactif des ids non reçus
$sql = 'UPDATE uneTable SET etat=0 WHERE id NOT IN(' . implode(',', $_POST['listeId']) . ')';
$result = $pdo->exec($sql);
}
Autre exemple avec un upload multiple
Voici la construction d'un formulaire avec plusieurs champs d'upload
$nbChamp = 5;
// Ne pas omettre l'attribut enctype
echo '<form action="" method="post" enctype="multipart/form-data">';
for ($i=0; $i<$nbChamp; $i++) {
echo '<p><input type="file" name="image[]" /></p>';
}
echo '<p>
<input type="submit" value="Téléverser les images" />
</p>
</form>';
Que l'on pourrait vérifier avec :
if (!empty($_FILES['image']) && array_filter($_FILES['image']['tmp_name'])) {
for ($nbImg = count($_FILES['image']['tmp_name']), $i = 0; $i < $nbImg; $i++) {
// On fait nos vérifications et actions pour chaque images
// Soit :
// $_FILES['image']['name'][$i]
// $_FILES['image']['tmp_name'][$i]
// etc…
// Faites un print_r($_FILES) pour visualiser comment se présente le tableau
}
}
Il est possible de spécifier des index directement dans les champs du formulaire, en les mettant entre les crochets bien entendu. Notez cependant que des index sous forme de chaîne n'ont pas besoin d'être entourés de guillemets, ni simples, ni doubles.
Mes cookies ne fonctionnent pas, quelles peuvent-en être les raisons ?
A savoir, un cookie n'est disponible (après l'avoir créé bien entendu) uniquement après rechargement de la page en cours, ou après chargement d'une autre page
Par étape :
Vérifiez les options de votre navigateur : est-il configuré de façon à accepter les cookies ?
Toujours sur votre navigateur, vérifiez si oui ou non vos cookies y sont présents (voir les options de celui-ci)
Vérifiez que vous avez bien spécifié une durée de vie du cookie correcte (supérieure au timestamp *actuel)
Si vous créez vos cookies dans une page étant dans un sous-répertoire de votre site, et que vous en avez besoin dans une page située à sa racine, vous devez renseigner le 4ème argument de la fonction setCookie(). Dans le cas exposé, il faut y mettre un /(racine du site).
Si vous êtes en PHP 5.3 ou plus récent (ce qui devrait être le cas), que vous utilisez la classe DateTime et que vous avez intl et ICU disponibles et activées, il y a la classe IntlDateFormatter
$now = new DateTime();
$metteurEnForme = new IntlDateFormatter(
'fr',
IntlDateFormatter::FULL,
IntlDateFormatter::NONE
);
echo $metteurEnForme->format($now);
Si vous êtes sous PHP < 5.4, notez qu'il n'est pas possible d'utiliser une locale en UTF-8 sous Windows avec setLocale()
Voyez ce message, point 5, pour un peu plus d'informations.
Je désire exécuter un script à intervalles réguliers (par exemple un backup de ma base de données, ou l'envoi de mails à un certain moment), comment faire ?
Vous pouvez premièrement vous tourner vers votre hébergeur pour savoir si ces tâches automatiques (appellées cron) ne sont pas déjà comprises dans votre plan d'hébergement.
Sinon, vous pouvez utiliser des services externes tels que Online Cron job (gratuit dans sa formule de base, mais imposant leur logo sur votre site) ou WebCron au prix de 0.0001 € par exécution.
Plusieurs choses sont à prendre en compte quand vous installez WAMP :
il faut que les installations de WAMP comme des éventuelles bibliothèques Visual C++ soient faites en tant qu'administrateur
préférez un dossier à la racine d'un lecteur (C:\wamp, le plus souvent) au dossier standard des programmes (C:\Program Files\wamp)
veillez à avoir la bonne version de Visual C++ (voir le dernier point de ce message)
si vous réinstallez WAMP au même endroit que là où vous aviez une installation qui ne fonctionnait pas, vérifiez qu'il ne reste aucun fichier de configuration (Fichier INI ou fichier CONF) là ou vous le remettez.
n'installez pas WAMP en parallèle de XAMPP, AMPPS ou EasyPHP. Ces solutions ne font pas bon ménage
vérifiez que votre antivirus ou votre pare-feu ne bloque WAMP en aucune manière
J'ai une erreur "Unable to perform action (…) Le chemin spécifié n'est pas valide" au lancement de WAMP
Cela signifie que le service apache n'a pas été installé correctement. Regardez la partie à la fin du message suivant
J'ai une erreur "Impossible de démarrer le programme car il manque MSVCR110.dll sur votre ordinateur. Essayez de réinstaller le programme pour corriger ce problème"
Il vous manque la version correcte de Microsivt Visual C++ Redistribuable pour WAMP ou l'un de ses éléments, selon sa version (surtout si vous installez d'autres version de PHP ou d'apache).
Les installations de WAMP (ou les addons apache ou PHP pour WAMP) comprennent souvent un code dans leur nom original, permettant d'identifier la version de Visual C++ nécessaire à leur bon fonctionnement. Si ce code n'y figure pas, il est très probable qu'une indication se trouve sur la page de téléchargement.
Référez-vous à ce tableau pour trouver la correspondance entre le code et le nom complet.
Notez que si vous installez WAMP x64, vous devrez installer les version 64 bits (x64)ET32 bits (x86)
Dois-je modifier mon fichier hosts pour accéder à localhost ?
Comme il l'est écrit dans le fichier hosts depuis Windows 7, il n'est pas nécessaire de mettre ou décommenter les lignes 127.0.0.1 localhost et ::1 localhost dans le fichier hosts sous Windows 7http://support.microsoft.com/kb/972034/fr#LetMeFixItMyselfAlways, partie "Windows 7 et versions antérieurs de Windows", premier exemple de code, dernières lignes (dernier accès le 27 mars 2020)et ultérieurmême source, voir pour votre version de Windows.
Testé et vérifié, fonctionne sous Windows 7 Pro SP1 x64, sans aucune connexion à internet, cache DNS préalablement vidé.