Foire Aux Questions PHP

Erreurs, pages blanches, PHP pas interprété, caractères spéciaux, accents, encodage, é, �, etc.

a marqué ce sujet comme résolu.

Comment vérifier la validité du domaine d’une adresse email ?

Là aussi, vous pouvez vous aider de ceci, qui se base sur la fonction checkdnsrr() :

<?php
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");
}

if (verif_email('zestedesavoir@hotmail.com')) {
    echo 'hotmail.com existe bien';
} else {
    echo 'hotmail.com n\'existe pas';
}
Fonction de vérification d’un enregistrement MX et exemple d’utilisation

hotmail.com existe bien

Résultat

La fonction checkdnsrr() n’était pas disponible sur système Windows avant PHP 5.3

Dans le cas où vous avez un environnement 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.

De quoi éviter des erreurs sous Windows avec PHP avant 5.3
<?php
if (!function_exists('checkdnsrr')) {
    function checkdnsrr() {
        return true;
    }
}
Alternative pour Windows sous PHP < 5.3
+0 -0

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. Ce qui implique que si aucune case n’est cochée, aucune valeur ne sera envoyée, et l’index correspondant dans $_POST n’existera pas — voir ce message

<form action="" method="post">
    <p>
        <input type="checkbox" name="plop[]" value="10" />
        <input type="checkbox" name="plop[]" value="20" />
    </p>
    <p>
        <button type="submit">Test</button>
    </p>
</form>
Exemple d’utilisation des crochets dans l’attribut name pour le cas de listes d’options

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
)
Résultat de print_r($_POST['plop']) si les deux cases ont été cochées

Le résultat de print_r($_POST['plop']) vaudra, si seulement la seconde des deux cases a été cochée :

Array
(
    [0] => 20
)
Résultat de print_r($_POST['plop']) dans le cas où seule la seconde case a été cochée

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>

Il est possible de spécifier des index directement dans les champs du formulaire, en les mettant entre les crochets bien entendu.

<input type="checkbox" name="questions[1][]" value="Oui" />
<textarea name="questions[commentaires]"></textarea>
Exemple d’index placés directement dans le HTML. Notez cependant que des index sous forme de chaîne n’ont pas besoin d’être entourés de guillemets, ni simples, ni doubles.

Exemples

Un système pour changer des états en gros (articles publiés ou non)
<?php
$sql = 'SELECT id, etat FROM uneTable ORDER BY id DESC';
$result = $pdo->query($sql);
echo '
<form action="" method="post">
<p>
';
while ($l = $result->fetch(PDO::FETCH_ASSOC)) {
    echo '<label for="' . $l['id'] . '">' . $l['id'] . '</label>';
    $checked = $l['etat'] == 1 ? ' checked="checked"' : '';
    echo '<input id="' . $l['id'] . '" type="checkbox" name="listeId[]"' . $checked . ' />';
}
echo '</p>
<p>
<button type="submit">Modifier les états"</button>
</p>
</form>';
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

Que l’on pourrait traiter simplement par :

<?php
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);
}
Exemple de traitement du formulaire proposé ci-dessus
Un cas d’upload multiple
<?php
$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>
<button type="submit">Téléverser les images"</button>
</p>
</form>';
Exemple de formulaire d’upload avec un champ par fichier

Que l’on pourrait vérifier avec :

<?php
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
    }
}
Exemple de traitement d’un formulaire d’upload multiple avec un champ par fichier
+0 -0

Mes cookies ne fonctionnent pas, quelles peuvent-en être les raisons ?

A savoir, un cookie n’est disponible uniquement après (re-)chargement d’une page, que ce soit la même ou une autre1

Par étape :

  • Vérifiez les options de votre navigateur : est-il configuré de façon à accepter les cookies2 ?
  • Toujours sur votre navigateur, vérifiez si oui ou non vos cookies y sont présents3
  • Vérifiez que vous avez bien spécifié une durée de vie du cookie correcte
    Elle doit être 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 /4

  1. Et après avoir créé ledit cookie, bien entendu 

  2. Voir les options de votre navigateur 

  3. Idem 

  4. / désigne la racine du site 

+0 -0

Comment afficher la date au format français ?

Utilisez la classe DateTime qui, si vous avez intl et ICU disponibles et activées (ce qui est habituel), peut être utilisée en conjonction avec la classe IntlDateFormatter

<?php
/* Vous pouvez passer en paramètre une date
 * - brute de base de données MySQL
 * - comme retournée par un champ de type datetime-local
 * - au format ISO (AAAA-MM-JJ)
 */
$date = new DateTime();
$metteurEnForme = new IntlDateFormatter(
    'fr',
    IntlDateFormatter::FULL,
    IntlDateFormatter::NONE
);
echo $metteurEnForme->format($date);
Exemple de génération d’une date au format français avec DateTime et IntlDateFormatter
mardi 27 août 2013
Résultat
+0 -0

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 qui fait payer chaque exécution.

Autre possibilité, pour des tâches ne nécessitant pas trop de ressources : vous préparez un script qui sera embarqué sur toutes les pages de votre application. Ce script va vérifier s’il doit lancer la tâche selon la dernière exécution.
Ainsi, ce seront les utilisateurs qui déclencheront l’exécution de la tâche.

+0 -0

Comment obtenir l'URL du site d'où vient le visiteur ?

Cette information est contenue dans une variable superglobale : $_SERVER['HTTP_REFERER'] On peut donc faire comme ceci :

1
2
<?php
echo 'Vous venez du site : ' . htmlspecialchars($_SERVER['HTTP_REFERER']);

Exemple d'utilisation de $_SERVER['HTTP_REFERER']

Ne vous fiez pas à cette valeur : le visiteur peut refuser de fournir cette information ou la modifier

+0 -0

Quelle est la différence entre == et === ?

== effectue une comparaison "paresseuse". Cette comparaison ne tient pas compte du type de ce qui est comparé : PHP va prendre les deux parties et les convertir en deux valeurs du même type pour voir si elles correspondent. Voici un tableau qui permet de voir ce qu’il en résulterait

Table de vérité de ==
$a == $b $b = '' $b = 1 $b = 0 $b = ' ' $b = 'a' $b = null $b = false $b = true
$a = '' true false true false false true true false
$a = 1 false true false false false false false true
$a = 0 true false true true true true true false
$a = ' ' false false true true false false false true
$a = 'a' false false true false true false false true
$a = null true false true false false true true false
$a = false true false true false false true true false
$a = true false true false true true false false true
Table de vérité de $a == $b pour plusieurs valeurs

Avec ===, PHP va effectuer une comparaison stricte, et ne va faire aucune conversion, ce qui veut dire que le type de valeur est pris en compte. Le même tableau appliqué à === se présente ainsi :

Table de vérité de ===
$a == $b $b = '' $b = 1 $b = 0 $b = ' ' $b = 'a' $b = null $b = false $b = true
$a = '' true false false false false false false false
$a = 1 false true false false false false false false
$a = 0 false false true false false false false false
$a = ' ' false false false true false false false false
$a = 'a' false false false false true false false false
$a = null false false false false false true false false
$a = false false false false false false false true false
$a = true false false false false false false false true
Table de vérité de $a === $b pour plusieurs valeurs

Donc $a === $b vaut true uniquement si $a et $b sont exactement identiques (même valeur et même type

Cas particulier des objets

Les objets se comportent un peu différemment des types dits primitifs que sont les entiers, flottants, booléens et chaînes de caractères. Si on peut les comparer avec == comme avec ===, il est important de bien comprendre comment sont effectuées les comparaisons entre deux objets.

Deux objets comparés avec == sont égaux si :

  • ils sont de la même classe
  • ils ont les mêmes attributs
  • ces attributs ont les mêmes valeurs

Si vous avez des objets composés d’autres objets et que vous les comparez avec ==, la comparaison de ses attributs va se faire avec l’opérateur == aussi, et donc se passer comme pour les deux objets initiaux (comparaison de la classe, des attributs et valeurs de ceux-ci), et ce pour chaque propriété objet rencontrée parmi les enfants, petits-enfants, etc.. Notez donc que cela demandera des ressources.
En conséquence, si vous avez une relation circulaire entre vos deux objets comparés, cela va résulter en

PHP Fatal error: Nesting level too deep - recursive dependency? in…

En revanche, deux objets comparés avec === sont identiques s’ils sont la même instance de la même classe. Cela n’est donc possible que si l’on compare un objet avec lui-même. Deux objets ayant des attributs identiques et de valeurs identiques ne sont pas identiques, on l’a vu, c’est le cas de d’égalité mentionné ci-dessus.
C’est là la particularité des objets.

Code d’exemple et table de vérité pour le cas des objets
<?php
class Flag
{
    public $flag;

    function Flag($flag = true) {
            $this->flag = $flag;
    }
}

class OtherFlag
{
    public $flag;

    function OtherFlag($flag = true) {
            $this->flag = $flag;
    }
}
Deux classes pour l’exemple
$a = new Flag() $b = new OtherFlag() $b = new Flag() $b = clone $a $b = $a
$a == $b false true true true
$a === $b false false false true
Table de vérité pour la comparaison d’objets
+0 -0
Problèmes d’interprétation du PHP

Pourquoi est-ce que mon code n’est pas interprété et je le vois dans la page ?
Pourquoi est-ce que mon code PHP se télécharge plutôt qu’il ne s’éxécute ?
Pourquoi est-ce que mes echo n’affichent rien, mais je n’ai aucune erreur ?

L’URL a son importance

Si vous voyez au début de l’adresse

  • file://
  • C:\ (ou toute autre lettre majuscule suivie de :\)
  • un simple slash / ou antislash \

ET  qu'il n’y a pas http quand vous copiez-collez l’adresse, vous n’accédez pas correctement à vos fichiers.
Même les fichiers HTML de votre site ne doivent pas être ouverts avec le double-clic dès qu’il y a des pages PHP qui entrent en jeu

Le PHP ayant besoin d’être interprété par le serveur (ce qui n’est pas le cas du HTML), il faut qu’il soit quelque part où WAMP sait qu’il doit traiter du PHP, soit dans le dossier www de votre installation de WAMP. Vous devez y accéder avec une adresse commençant par http://, sans quoi vous ne passerez pas par WAMP.
Pour plus d’informations, lisez cette partie du tutoriel sur WAMP

Hé, j’y accède correctement, pourquoi ça ne fonctionne quand-même pas ?!

  1. Utilisez l’extension .php pour vos fichiers de code PHP, même si ceux-ci génèrent du HTML. Du code PHP dans un fichier avec l’extension .html peut soit s’afficher tel quel dans la page, soit ne pas être visible du tout

  2. Utilisez bien les marques ouvrantes PHP complètes <?php. Si vous souhaitez pouvoir utiliser les versions courtes <? (et <?= sous PHP < 5.4), il vous faut activer l’option short open tag pour PHP. Pour ce faire, cliquez sur l’icône de WAMP dans la zone de notifications, et allez sur PHP > Configuration PHP > short open tag.

    Avant PHP 5.4, <?= était impacté par ce même paramètre

    Si vous avez des documents XML sur vos sites, surtout si vous les générez dynamiquement, activer cette option vous force à insérer la déclaration XML avec echo '<?xml version="1.0" encoding="utf-8" ?>'

  3. La balise <?php ne doit pas contenir d’espace. En revanche, elle doit absolument être suivie d’un caractère blanc (espace ou retour à la ligne). Par exemple :

    <?phpecho $truc; // ne fonctionnera pas, echo est "collé" à <?php
    <? php echo $truc; // ne fonctionnera pas, php n'est pas "collé" à <?
    
+0 -0

Comment récupérer l’id de l’enregistrement qui vient d’être inséré dans une table ?

Il faut utiliser la méthode de l’objet PDO lastInsertId()

Exemple d’utilisation de PDO::lastInsertId
<?php
$pdo = new PDO($dsn, $user, $passwd);
$pdo->exec("INSERT INTO ma_table (colonne1, colonne2) VALUES('$var_1', '$var_2')");
$id = $pdo->lastInsertId();
Exemple d’utilisation de PDO::lastInsertId

Selon la base de données et le driver utilisé, il est possible que le retour de cette fonction PDO soit totalement arbitraire

Avec l’API MySQLi, c’est la propriété mysqli#insert_id qui contient l’information.

Exemple d’utilisation de mysqli insert_id
$mysqli = new mysqli($host, $user, $password, $databaseName);
$mysqli->query("INSERT INTO ma_table (colonne1, colonne2) VALUES('$var_1', '$var_2')");
$id = $mysqli->insert_id;

// Ou, avec le style procédural
$mysqli = mysqli_connect($host, $user, $password, $databaseName);
mysqli_query($mysqli, "INSERT INTO ma_table (colonne1, colonne2) VALUES('$var_1', '$var_2')");
$id = mysqli_insert_id($mysqli);
Exemple d’utilisation de mysqli#insert_id
+0 -0

Comment connaître le nombre d’enregistrements affectés par une requête ?

Pas pour les requêtes SELECT

Les méthodes ci-dessous ne s’utilisent pas pour compter des enregistrements récupérés avec une requête SELECT, car l’information retournée n’est pas fiable. Dans le cas où il vous faut compter des enregistrements à sélectionner, préférez une requête supplémentaire SELECT count(…) FROM … ou l’équivalent de votre SGBD.
Si vous voulez vous assurer que votre requête qui doit ne fournir qu’un résultat en a bien retourné un, faites simplement if ($result = $statement->fetch())

Pour les requêtes INSERT, UPDATE et DELETE, la méthode de l’objet PDOStatement rowCount() sert à cela

Avec PDO : PDOStatement::rowCount
$pdo = new PDO($dsn, $user, $passwd);
$stmt = $pdo->prepare('UPDATE `message` SET `view` = `view` + 1 WHERE `sujet_id` = 37690510');
$stmt->execute();
$number = $stmt->rowCount();
Exemple d’utilisation de PDOStatement::rowCount

Vous pouvez l’utiliser pour des requêtes de type INSERT, UPDATE et DELETE

Avec MySQLi, il y a la propriété mysqli#affected_rows

Avec mysqli : mysqli#affected_rows
$mysqli = new mysqli($host, $user, $password, $databaseName);
$mysqli->query('UPDATE `message` SET `view` = `view` + 1 WHERE `sujet_id` = 37690510');
$number = $mysqli->affected_rows;

// Ou, avec le style procédural
$mysqli = mysqli_connect($host, $user, $password, $databaseName);
mysqli_query($mysqli, 'UPDATE `message` SET `view` = `view` + 1 WHERE `sujet_id` = 37690510');
$number = mysqli_affected_rows($mysqli);
Exemple d’utilisation de mysqli#affected_rows

Vous pouvez l’utiliser pour des requêtes de type INSERT, UPDATE et DELETE.

Cas un peu spécial de mysqli : il est possible d’avoir une information fiable pour les requêtes SELECT, c’est la propriété mysqli_result#num_rows qui doit être utilisée.

Ne faites pas une requête SELECT * FROM … juste pour utiliser mysqli_result#num_rows, auquel cas reportez-vous au bloc erreur mentionnée en haut de message.
La solution ci-dessous n’a de sens que si vous utilisez vraiment les informations sélectionnées par la requête dans votre code

$mysqli = new mysqli($host, $user, $password, $databaseName);
$mysqli_result = $mysqli->query('SELECT * FROM `message` WHERE `sujet_id` = 37690510');
$number = $mysqli_result->num_rows;

// Ou, avec le style procédural
$mysqli = mysqli_connect($host, $user, $password, $databaseName);
$mysqli_result = mysqli_query($mysqli, 'SELECT * FROM `message` WHERE `sujet_id` = 37690510');
$number = mysqli_num_rows($mysqli_result);
Exemple d’utilisation de mysqli_result#num_rows
+0 -0

Comment faire fonctionner les sessions sur free.fr ?

Il faut simplement créer un dossier sessions à la racine du site, et vérifier qu’il soit accessible en lecture, écriture et exécution par l’utilisateur qui fait fonctionner le serveur.

+0 -0

J’ai modifié mon php.ini, mais ça ne change rien. Que se passe-t-il ?

Vous n’avez probablement pas redémarré Apache, ou pas modifié au bon endroit, ou sinon pas modifié le bon fichier. ^^
Il se peut que vous ayez plusieurs versions de PHP sur votre machine, ou que vous ayez modifié un fichier qui n’était pas pour "le bon environnement" (le bon SAPI1). Il y a cependant moyen de savoir quel fichier modifier rapidement.

Pour votre serveur HTTP (accès par navigateur)

Si vous utilisez WAMP avant sa version 3.2.8, c’est le fichier qu’il vous est proposé de modifier en passant par le menu de l’icône (voir le dernier bloc « Attention »). Depuis la version 3.2.8, il y a deux éléments de menu, celui pour le module apache est php.ini [apache module]

Regardez dans le phpinfo (vous pouvez vous créer une page ne contenant que <?php phpinfo() si besoin) aux lignes suivantes :

  • Loaded Configuration File
    Si vous êtes en local et que changer la configuration pour toutes vos applications PHP ne vous pose pas de problème, c’est le fichier à modifier.
    N’oubliez pas de redémarrer Apache après cette modification.
Voici d’autres lignes qu’il n’est pas toujours nécessaire de vérifier
  • Scan this dir for additional .ini files
    Si vous êtes chez votre hébergeur et que la valeur de cette ligne est bien un chemin, il peut être intéressant de voir si vous pouvez vous rendre dans le dossier qui est mentionné (il y aura probablement des parties à remplacer par votre nom d’utilisateur ou un identifiant quelconque), afin d’y créer votre fichier php.ini. Ce fichier peut devoir être nommé d’une certaine manière, surtout au niveau de l’extension.
    Pour savoir cela, regardez plus bas dans les phpinfo pour trouver la ligne user_ini.filename. Par défaut, les fichiers php.ini par utilisateur sont à nommer avec la double extension .user.ini.

    Tout n’est pas paramétrable avec de tels fichiers. Conformez-vous à la colonne « Modifiable » de la page listant les directives du php.ini

  • Additional .ini files parsed
    Ça, c’est justement pour voir s’il n’y a pas déjà un php.ini existant et qui vous serait propre. Dans le cas où il y a un fichier d’indiqué et que vous pouvez y accéder, c’est là que vous pourrez faire vos modifications. Si vous ne pouvez pas y accéder, il y a de fortes chances que votre hébergeur puisse et soit d’accord de le faire pour vous. Soyez néanmoins convaincants ;)

Au final, si votre hébergement fonctionne avec Apache, vous avez aussi la possibilité de définir des valeurs de PHP dans des fichiers .htaccess.

Pour la ligne de commandes

Depuis WampServer 3.2.8, il y a un nouvel élément de menu php.ini [FCGI - CLI] qui permet de modifier ce fichier

Hé oui, il y a parfois (et même souvent) plusieurs php.ini, un par SAPI. En général, ils ne sont pas nommés de la même manière ou ne sont pas enregistrés au même endroit.

Là, c’est très simple, il suffit de taper une commande qui va directement donner le chemin complet du fichier à modifier : la commande php --ini.
En revanche, il est extrêmement rare que les hébergeurs laissent modifier celui-ci.

Avec l’exécutable binaire symfony

Histoire de faire simple, cet exécutable utilise une version de PHP (et donc du php.ini) qu’il enregistre dans un fichier de configuration, et non pas la configuration prévue pour le terminal/l’invite de commandes. D’une part, lors du lancement de symfony check:requirements, une des premières informations qui s’affiche est le chemin du php.ini à modifier dans ce cas, et d’autre part, le fichier de configuration de l’exécutable binaire peut probablement être modifié/adapté pour que ce soit un autre php.ini qui soit utilisé.


  1. Plus d’informations à ce sujet sur Wikipédia
+2 -0
Jeux de caractères et encodage (2)

Pourquoi est-ce que les fonctions sur mes chaînes de caractères ne me retournent rien ?
Pourquoi est-ce que tous les caractères de mes chaînes ne sont pas mis en majuscules/minuscules ?
Pourquoi est-ce que mes chaînes de caractères sont tronquées quand j’utilise certaines fonctions ?

Concerne aussi le point 3 de cette entrée

Aussi surprenant que cela puisse paraître, c’est un souci de jeux de caractères et donc de caractères spéciaux.
Le jeu de caractères interne de PHP et celui de votre chaîne à traiter ne sont pas cohérents : vous envoyez des données dans un jeu particulier alors que ces fonctions attendent ou traitent comme s’il s’agissait d’un autre. Ne pouvant traiter la chaîne correctement, elles retournent des valeurs qui vous surprennent.

Ceci concerne les fonctions htmlentities(), html_entity_decode(), htmlspecialchars(), json_encode(), json_decode(), et la plupart des fonctions str*(), qui sont prévues pour retourner des chaînes de caractères dans un jeu précis, et n’acceptent que ce jeu précis comme entrée

Fonctions (liste non exhaustive)

Jeux de caractères par défaut

PHP < 5.4

5.4 ⩽ PHP < 5.6

5.6 ⩽ PHP < 7.2

PHP ⩾ 7.2

Si le jeu de caractères de votre application n’est pas celui de votre version de PHP

htmlentities(), html_entity_decode(), htmlspecialchars()

ISO 8859–1

UTF-8

default_charset

Spécifier les deuxième et troisième paramètres

Fonctions str*()

ISO-8859–1(5) (caractères sur un octet)

Utiliser les équivalents mb_str*() ou activer mbstring.func_overload pour le "groupe 2"

Utiliser les équivalents mb_str*()

json_encode()

UTF-8

Pas d’autre choix que de fournir des données en UTF-8 valides

Quelques solutions

En complément, regardez ce message pour d’autres éléments à vérifier en relation avec les jeux de caractères.

+0 -0

Comment vérifier si un pseudo ou une adresse mail (ou toute autre valeur) est déjà utilisée ? Je n'aimerais pas de doublons.

Il y a au moins deux possibilités pour gérer cela.

Vérifier le nombre d'occurrences existantes

L'idée est de faire une requête qui va compter dans la base de données le nombre d'occurrences de la valeur. Le test ressemblera à ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
$declarationRequete = $pdo->prepare(
    'SELECT count(`id`) FROM `une_table` WHERE `la_colonne` = :la_valeur'
);
$declarationRequete->execute(array('la_valeur' => $laValeur));

if ($declarationRequete->fetchColumn() > 0) {
    // On a un ou plusieurs résultats, la valeur ne peut être enregistrée
} else {
    // On n'a aucun résultat, on va pouvoir faire INSERT
}

Vérification si une valeur n'est pas déjà dans la BDD (à répéter autant de fois que de valeurs)

Notez que si vous avez plus d'un résultat ($declarationRequete->fetchColumn() retourne un nombre plus élevé que 1), vous avez un problème.  :-°

Cette méthode vous permet, en cas de plusieurs valeurs qui doivent être uniques, de savoir exactement lesquelles le le sont pas.
En revanche, elle demande une requête supplémentaire par valeur à garder unique.

Ajouter des index d'unicité sur la ou les colonnes contenant les valeurs qui doivent être uniques

L'idée est que ce ne soit plus vous qui vérifiez l'unicité dans votre programme, mais votre moteur SQL. Ainsi, à l'insertion des données, vous vérifiez si celle-ci s'est bien passée, soit en capturant l'exception levée1, soit en testant le retour de l'exécution de la requête.

La requête pour ajouter une contrainte d'unicité ressemble à ceci :

1
CREATE UNIQUE INDEX unique_ma_valeur ON `une_table` (`la_colonne`)

Création d'une contrainte d'unicité sur une colonne avec MySQL (à répéter autant de fois que de valeurs à conserver uniques)

La partie PHP, elle, ne change que très peu :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
$declarationRequete = $pdo->prepare('INSERT INTO `personne` VALUES (NULL, :pseudo, :email)');
$declarationRequete->bindParam('pseudo', $_POST['pseudo']);
$declarationRequete->bindParam('email', $_POST['email']);

// PDO en mode silencieux
if ($declarationRequete->execute()) {
    /* L'insertion s'est effectuée sans problème */
} else {
   /* Il y a eu un problème à l'insertion */
}

// PDO en "mode d'erreur exceptions"
try {
    $declarationRequete->execute();
    /* Le code à partir de cette ligne et avant la 18 ne sera 
     * effectué que si la requête n'a pas généré d'erreur */
} catch(\Exception $e) {
    /* Il y a eu un problème à l'insertion */
}

Deux manières de vérifier l'insertion avec des contraintes d'unicité

Vous ne pourrez pas savoir de manière aisée quelle valeur a posé problème, donc cette méthode est plus adaptée à une seule valeur à vérifier.
Cependant, vous n'avez dans tous les cas qu'une seule requête.


  1. Notez que ceci devrait être fait, car la requête peut toujours générer une exception.
    Notez encore qu'il faut avoir demandé à l'API de connexion de notifier des erreurs SQL. 

+0 -0

Mon code fonctionne en local, mais pas sur le serveur final, pourquoi ?

Il peut y avoir beaucoup de paramètres à la base de ce problème, mais tous ont un dénominateur commun : la version et les paramètres de PHP.

Comparez un phpinfo() en local et sur le serveur pour voir les différences. Si certaines ne porteront pas nécessairement à conséquence pour votre code, une simple différence de version mineure (le second chiffre) peut poser problème, sans parler des autres paramètres.

Il arrive aussi que la casse pose problème à différents niveaux, que ce soit au niveau du nom des fichiers ou des tables/colonnes de la base de données.

Dans bien des cas, l’activation des messages d’erreur sur le serveur distant reste un bon moyen de savoir ce qu’il se passe et d’avoir des pistes.

+1 -0

Comment remplacer des antislashs ou backslash (\\) par des slashs (/) avec preg_replace().

Dans un premier temps, vous seriez tentés de l'écrire de cette façon :

1
2
3
4
<?php
$string = 'D:\\wamp\\www\\';
$foo    = preg_replace('/\\/', '/', $string); // A ne pas faire
echo $foo;

Sauf que vous aurez le droit à une erreur du type : Message: preg_replace(): No ending delimiter '/' found.

Il faut, comme indiqué dans la documentation officielle, doubler les antislashs.

1
2
3
4
<?php
$string = 'D:\\wamp\\www\\';
$foo    = preg_replace('/\\\\/', '/', $string);
echo $foo;  # D:/wamp/www/
Edit Ymox

Echappement des antislashes dans la déclaration de $string

Edit viki53

Fix typo

+0 -0

Comment faire pour que mon script puisse être utilisé n’importe où, que ce soit à la racine d’un hébergement ou dans un sous-dossier ?

Vous pouvez utiliser la fonction path() avec le code ci-dessous sur vos liens. Elle ajoutera la partie qui peut varier d’un environnement à l’autre au besoin.

Codez tout comme si vous travailliez à la racine d’un nom de domaine. Vous pouvez ensuite utiliser la fonction path() sur tous vos liens absolus dans votre code PHP/HTML.

Code de la fonction path()
<?php
// On récupère les dossiers dans l'URI de la requête
$uri = preg_split('`/|\\\`', $_SERVER['REQUEST_URI'], -1, PREG_SPLIT_NO_EMPTY);

// On regarde ce qu'elle a en commun d'avec le chemin du script
$baseUrl = array_intersect(
    $uri,
    preg_split(
        '`/|\\\`',
        realpath(__DIR__),
        /* Si d'aventure vous utilisez une version de PHP avant 5.3,
         * remplacez __DIR__ ci-dessus par dirname(__FILE__) */
        -1,
        PREG_SPLIT_NO_EMPTY
    )
);
if (count($baseUrl)) {
    // S'il y a des trucs en commun, on se construit une base d'URL
    define('BASE_URL', '/' . implode('/', $baseUrl));
} else {
    // Sinon, c'est qu'on est à la racine de l'hébergement
    define('BASE_URL', '');
}

/**
 * Permet de rendre des liens absolus portables
 * @param string $link Le lien à traiter
 */
function path($link)
{
    // Si on a un URL absolu…
    if (preg_match('`^/`', $link)) {
        // … on ajoute BASE_URL devant.
        $link = BASE_URL . $link;
    }
    // On retourne le lien
    return $link;
}
De quoi permettre de rendre des codes PHP portables

Par sécurité, les liens relatifs ne devraient pas poser de problème si traités avec cette fonction, donc vous pourriez traiter tous vos liens sans réfléchir, ce que nous ne vous conseillons cependant pas.  :p

+0 -0

Je n’arrive pas à me connecter à ma base de données, alors que je la vois dans phpMyAdmin ! Que se passe-t’il ?

Certaines solutions serveur paramètrent MySQL pour qu’il écoute sur un autre port que le 3306, qui est celui par défaut.

Une des méthodes les plus simples savoir ce qu’il y a à faire est de se connecter à phpMyAdmin.
Rendez-vous sur une page de phpMyAdmin où vous voyez vos tables. Maintenant, regardez en haut de celle-ci, un peu sur la gauche, là où il y a « ← Serveur : … ». La fin de la chaîne est importante. Si vous avez deux points et un nombre (par exemple « … :3325 ») et que ce nombre n’est pas 3306, le SGBD contenant vos tables n’écoute pas sur le port "par défaut" et il faut spécifier cela à la connexion.

Spécifier le port pour le bon SGBD

Les script de connexion utilisent, par exemple :

<?php
$pdo = new PDO('mysql:host=localhost;dbname=database;', 'user', 'password');

$mysqli = new mysqli('localhost', 'user', 'password', 'database');
// Ou en procédural
$mysqli = mysqli_connect('localhost', 'user', 'password', 'database');

Pour se connecter avec un autre port que le 3306, il faut le préciser :

<?php
$pdo = new PDO('mysql:host=localhost;dbname=database'
        . ';port=' . 3325, // Notez bien le point-virgule ;
    'user', 'password');

$mysqli = new mysqli('localhost', 'user', 'password', 'database', 3325);
// Ou en procédural
$mysqli = mysqli_connect('localhost', 'user', 'password', 'database', 3325);

WampServer

Les dernières versions en date de WampServer fournissent deux SGBD : MariaDB et MySQL, et le SGBD fonctionnant sur le port par défaut peut changer. Les deux ne peuvent de toute façon pas écouter sur le même port quand ils fonctionnent en même temps, celui sur le port par défaut n’est donc pas celui où vous avez créé vos bases de données.

Il n’est pas obligatoire d’utiliser MySQL si ce n’est pas le SGBD par défaut de votre WampServer, et il n’y a pas de différence gênante entre les deux.
A savoir qu’à terme, seul MariaDB risque d’être fourni avec WampServer.

Remplacer MySQL par MariaDB et vice-versa

Il est impératif de sauvegarder vos bases de données et utilisateurs dans des fichiers SQL par export avant de désactiver un des SGBD. C’est le seul moyen pérenne de transférer vos bases de données entre MySQL et MariaDB.
Le titre « Sauvegarde des bases de données » de la section « Sauvegarder, sauvegarder, sauvegarder ! » du tutoriel WampServer sur ce site peut vous aider.

Il existe un outil pour inverser d’un seul clic le SGBD par défaut si les deux sont activés (MySQL et MariaDB), accessible au clic droit sur l’icône de WampServer dans la barre de statut > Outils > Inverser SGBD par défaut…. L’étiquette est complétée par MySQL <-> MariaDB ou MariaDB <-> MySQL selon le SGBD par défaut.

Bien sûr, il vous reste à importer vos bases de données et utilisateurs préalablement sauvegardés.

Désactiver le serveur inutile

Vous n’êtes pas obligé de conserver l’utilisation des deux gestionnaires MySQL et MariaDB, vous pouvez ne conserver que celui qui vous convient et vous pouvez même désactiver totalement les deux gestionnaires de bases de données avec un clic droit sur l’icône de WampServer dans la barre de statut > Paramètres Wamp > décocher soit Autoriser MariaDB, soit Autoriser MySQL

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte