Introduction au PHP

From Deimos.fr / Bloc Notes Informatique
Jump to: navigation, search

Contents

1 Introduction

PHP (acronyme récursif pour PHP: Hypertext Preprocessor), est un langage de scripts libre principalement utilisé pour produire des pages web dynamiques via un serveur HTTP, mais pouvant également fonctionner comme n'importe quel langage interprété de façon locale, en exécutant les programmes en ligne de commande. PHP est un langage impératif disposant depuis la version 5 de fonctionnalités de modèle objet complètes[3]. En raison de la richesse de sa bibliothèque, on désigne parfois PHP comme une plate-forme plus qu'un simple langage.

2 Bases

  • Dans des pages contenant essentiellement du HTML, il est possible d'insérer des petits bouts de PHP pour faciliter la vie. Il suffit de mettre des balies de type :
<html>
<head><title>PHP says hello</title></head>
<body>
<b>
<?php
print "Hello, World!";
?>
</b>
</body>
</html>

Cela produira :

<html>
<head><title>PHP says hello</title></head>
<body>
<b>
Hello, World!
</b>
</body>
</html>
  • Nous pouvons également inverser l'exemple ci dessus afin de mettre du code HTML dans une page PHP :
<?php
print <<<_HTML_
<form method="post" action="$_SERVER[PHP_SELF]">
 Your Name: <input type="text" name="user">
 <br/>
 <input type="submit" value="Say Hello">
 </form>
_HTML_;
?>

La variable $_SERVER[PHP_SELF] a été appellée, elle est spéciale au PHP. Elle sert à obtenir l'URL du lien appellée mais sans le protocole, ni le nom d'hôte. Ex :

https://www.deimos.fr/blocnotesinfo/index.php?title=Introduction_au_PHP

Seul ce qui est en gras est gardé.

Pour vous donner de ce qui est disponible, vous pouvez créer un fichier avec ceci :

<?php
echo "<table border=\"1\">";
echo "<tr><td>" .$_SERVER['argv'] ."</td><td>argv</td></tr>";
echo "<tr><td>" .$_SERVER['argc'] ."</td><td>argc</td></tr>";
echo "<tr><td>" .$_SERVER['GATEWAY_INTERFACE'] ."</td><td>GATEWAY_INTERFACE</td></tr>";
echo "<tr><td>" .$_SERVER['SERVER_ADDR'] ."</td><td>SERVER_ADDR</td></tr>";
echo "<tr><td>" .$_SERVER['SERVER_NAME'] ."</td><td>SERVER_NAME</td></tr>";
echo "<tr><td>" .$_SERVER['SERVER_SOFTWARE'] ."</td><td>SERVER_SOFTWARE</td></tr>";
echo "<tr><td>" .$_SERVER['SERVER_PROTOCOL'] ."</td><td>SERVER_PROTOCOL</td></tr>";
echo "<tr><td>" .$_SERVER['REQUEST_METHOD'] ."</td><td>REQUEST_METHOD</td></tr>";
echo "<tr><td>" .$_SERVER['REQUEST_TIME'] ."</td><td>REQUEST_TIME</td></tr>";
echo "<tr><td>" .$_SERVER['QUERY_STRING'] ."</td><td>QUERY_STRING</td></tr>";
echo "<tr><td>" .$_SERVER['DOCUMENT_ROOT'] ."</td><td>DOCUMENT_ROOT</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_ACCEPT'] ."</td><td>HTTP_ACCEPT</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_ACCEPT_CHARSET'] ."</td><td>HTTP_ACCEPT_CHARSET</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_ACCEPT_ENCODING'] ."</td><td>HTTP_ACCEPT_ENCODING</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_ACCEPT_LANGUAGE'] ."</td><td>HTTP_ACCEPT_LANGUAGE</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_CONNECTION'] ."</td><td>HTTP_CONNECTION</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_HOST'] ."</td><td>HTTP_HOST</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_REFERER'] ."</td><td>HTTP_REFERER</td></tr>";
echo "<tr><td>" .$_SERVER['HTTP_USER_AGENT'] ."</td><td>HTTP_USER_AGENT</td></tr>";
echo "<tr><td>" .$_SERVER['HTTPS'] ."</td><td>HTTPS</td></tr>";
echo "<tr><td>" .$_SERVER['REMOTE_ADDR'] ."</td><td>REMOTE_ADDR</td></tr>";
echo "<tr><td>" .$_SERVER['REMOTE_HOST'] ."</td><td>REMOTE_HOST</td></tr>";
echo "<tr><td>" .$_SERVER['REMOTE_PORT'] ."</td><td>REMOTE_PORT</td></tr>";
echo "<tr><td>" .$_SERVER['SCRIPT_FILENAME'] ."</td><td>SCRIPT_FILENAME</td></tr>";
echo "<tr><td>" .$_SERVER['SERVER_ADMIN'] ."</td><td>SERVER_ADMIN</td></tr>";
echo "<tr><td>" .$_SERVER['SERVER_PORT'] ."</td><td>SERVER_PORT</td></tr>";
echo "<tr><td>" .$_SERVER['SERVER_SIGNATURE'] ."</td><td>SERVER_SIGNATURE</td></tr>";
echo "<tr><td>" .$_SERVER['PATH_TRANSLATED'] ."</td><td>PATH_TRANSLATED</td></tr>";
echo "<tr><td>" .$_SERVER['SCRIPT_NAME'] ."</td><td>SCRIPT_NAME</td></tr>";
echo "<tr><td>" .$_SERVER['REQUEST_URI'] ."</td><td>REQUEST_URI</td></tr>";
echo "<tr><td>" .$_SERVER['PHP_AUTH_DIGEST'] ."</td><td>PHP_AUTH_DIGEST</td></tr>";
echo "<tr><td>" .$_SERVER['PHP_AUTH_USER'] ."</td><td>PHP_AUTH_USER</td></tr>";
echo "<tr><td>" .$_SERVER['PHP_AUTH_PW'] ."</td><td>PHP_AUTH_PW</td></tr>";
echo "<tr><td>" .$_SERVER['AUTH_TYPE'] ."</td><td>AUTH_TYPE</td></tr>";
echo "</table>"
?>
  • Pour des formulaires de type HTML correspondant à ceci :
<form method="POST" action="sayhello.php">
Your Name: <input type="text" name="user">
<br/>
<input type="submit" value="Say Hello">
</form>

Va donner en PHP cela :

<?php
print "Hello, ";
// Print what was submitted in the form parameter called 'user'
print $_POST['user'];
print "!";
?>

$_POST contient les valeurs des paramètres du formulaire, telles qu'elles ont été soumises. En termes de programmation, il s'agit d'une variable ainsi nomée parce que vous pouvez modifier les valeurs qu'elle contient. En fait c'est une variable tableau car elle peut contenir plusieurs valeurs simultanément.

Lorsque $_SERVER[PHP_SELF] est l'action du formulaire, vous pouvez placer dans la même page le code d'affichage d'un formulaire et le code de traitement des données saisies :

<?php
// Print a greeting if the form was submitted
if ($_POST['user']) {
    print "Hello, ";
    // Print what was submitted in the form parameter called 'user'
    print $_POST['user'];
    print "!";
} else {
    // Otherwise, print the form
    print <<<_HTML_
<form method="post" action="$_SERVER[PHP_SELF]">
Your Name: <input type="text" name="user">
<br/>
<input type="submit" value="Say Hello">
</form>
_HTML_;
}
?>
  • Pour des commentaires, vous pouvez utiliser :
    • // : Pour une ligne à commenter
    • /* à */ : pour commenter un paragraphe, nous revindrons là dessus plus bas.
  • Maintenant voici un exemple de code PHP qui se connecte à un serveur de base de données et récupère une liste de plats avec leurs prix en fonction de la valeur du paramètre rpas, puis affiche ces plats et leurs prix dans une table HTML :
<?php
require 'DB.php';
// Connect to MySQL running on localhost with username "menu"
// and password "good2eaT", and database "dinner"
$db = DB::connect('mysql://menu:[email protected]/dinner');
// Define what the allowable meals are
$meals = array('breakfast','lunch','dinner');
// Check if submitted form parameter "meal" is one of
// "breakfast", "lunch", or "dinner"
if (in_array($meals, $_POST['meal'])) {
    // If so, get all of the dishes for the specified meal
    $q = $dbh->query("SELECT dish,price FROM meals WHERE meal LIKE '" .
                     $_POST['meal'] ."'");
    // If no dishes were found in the database, say so
    if ($q->numrows == 0) {
        print "No dishes available.";
    } else {
        // Otherwise, print out each dish and its price as a row
        // in an HTML table
        print '<table><tr><th>Dish</th><th>Price</th></tr>';
        while ($row = $q->fetchRow( )) {
            print "<tr><td>$row[0]</td><td>$row[1]</td></tr>";
        }
        print "</table>";
    }
} else {
    // This message prints if the submitted parameter "meal" isn't
    // "breakfast", "lunch", or "dinner"
    print "Unknown meal.";
}
?>

3 Manipulation de données textuelles et numériques

Le chaines peuvent etre délimitées par des "". Elles fonctionnent comme les chaines entourées par des ', mais permettent plus de caractères spéciaux :

Character Meaning
\n Newline (ASCII 10)
\r Carriage return (ASCII 13)
\t Tab (ASCII 9)
\\ \
\$ $
\" "
\0 .. \777 Octal (base 8) number
\x0 .. \xFF Hexadecimal (base 16) number

Un petit exemple pour clarifier le tout. Imaginons $user vaut Pierre :

  • 'Bonjour $user' : Affichera : Bonjour $user
  • "Bonjour $user" : Affichera : Bonjour Pierre

Pour combiner 2 chaines, il faut utliser un "." qui permet de concaténer des chaines :

print 'bread' . 'fruit';
print "It's a beautiful day " . 'in the neighborhood.';
print "The price is: " . '$3.95';
print 'Inky' . 'Pinky' . 'Blinky' . 'Clyde';

Ceci affichera :

breadfruit
It's a beautiful day in the neighborhood.
The price is: $3.95
InkyPinkyBlinkyClyde

3.1 Manipulation de texte

3.1.1 Validation des chaînes

La fonction trim() supprime les espaces situés au début ou à la fin d'une chaine. Combiné à strlen(), qui vous renseigne sur la longueur d'une chaine, vous pouvez connaitre la longueur d'une valeur soumise par un formulaire tout en ignorant les espaces de tête et de fin.

// $_POST['zipcode'] holds the value of the submitted form parameter
// "zipcode"
$zipcode = trim($_POST['zipcode']);
// Now $zipcode holds that value, with any leading or trailing spaces
// removed
$zip_length = strlen($zipcode);
// Complain if the ZIP code is not 5 characters long
if ($zip_length != 5) {
   print "Please enter a ZIP code that is 5 characters long.";
}

On peut faire plus court en combinant les fonctions. Un peu comme Final fantasy quand on combine la mana :

if (strlen(trim($_POST['zipcode'])) != 5) {
   print "Please enter a ZIP code that is 5 characters long.";
}

Pour comparer les chaines avec l'opérateur dégalité, utilisez (==) :

if ($_POST['email'] == '[email protected]') {
  print "Welcome, Mr. President.";
}

Pour comparer des chaînes sans tenir compte de la casse, utilisez la fonction strcasecmp(). Elle renvoie 0 si les 2 chaînes fournies à strcasecmp() sont égales (à la casse près) :

if (strcasecmp($_POST['email'], '[email protected]') == 0) {
   print "Welcome back, Mr. President.";
}

3.1.2 Formatage du texte

printf() donne plus de contrôle que print sur l'aspect de sortie :

$price = 5; $tax = 0.075;
printf('The dish costs $%.2f', $price * (1 + $tax));

Ceci affichera :

The dish costs $5.38

Le "%.2fé est remplacée par la valeur de $price * (1 + $tax)) et formatée pour avoir 2 chiffres après la virgule.

Les règles de format commencent par %. On peut ensuite placer des modificateurs optionneles qui affectent le comportement de la règle :

  • Un caractère de remplissage : Si la chaine remplaçant la règle de format est trop courte, ce caractère permettra de la remplir. Utilisez un espace pour remplir avec des espaces ou un 0 pour remplir avec des zéros.
  • Un signe : Pour les nombres, un + placera un + avant les nombres positifs (ils sont normalement affichés sans signe). Pour les chaînes, un - fera que la chaîne sera justifiée à droite (par défaut, les chaînes sont justifiées à gauche).
  • Une largeur minimale : la taille minimale que devra avoir la valeur remplçant la règle de format. Si elle est plus courte, le caractère de remplissage servira à combler le vide.
  • Un point et un nombre de décimales : Pour les nombres à virgule flottante, cela contrôle le nombre de chiffres après la virgule. Dans l'exemple ci dessus, le .2 formate $price * (1 + $tax)); avec 2 décimales.

Voici un exemple de remplissage par des zéros avec printf() :

$zip = '6520';
$month = 2;
$day = 6;
$year = 2007;
printf("ZIP is %05d and the date is %02d/%02d/%d", $zip, $month, $day, $year);

Affichera :

ZIP is 06520 and the date is 02/06/2007

Affichage des signes avec printf() :

$min = -40;
$max = 40;
printf("The computer can operate between %+d and %+d degrees Celsius.", $min, $max);

Affichera :

The computer can operate between -40 and +40 degrees Celsius.

Pour découvrir d'autres règle avec printf, consultez http://www.php.net

Les fonctions strtolower() et strtoupper() produisent , respectivement, des versions tout en minuscules ou tout en majuscules d'une chaîne.

print strtolower('Beef, CHICKEN, Pork, duCK');
print strtoupper('Beef, CHICKEN, Pork, duCK');

Affichera :

beef, chicken, pork, duck
BEEF, CHICKEN, PORK, DUCK

La fonction ucwords() met en majuscule la première lettre de chaque mot d'une chaîne :

print ucwords(strtolower('JOHN FRANKENHEIMER'));

Affichera :

John Frankenheimer

Troncature d'une chaîne avec substr() :

// Grab the first thirty characters of $_POST['comments']
print substr($_POST['comments'], 0, 30);
// Add an ellipsis
print '...';

Affichera :

The Fresh Fish with Rice Noodle was delicious, but I didn't like the Beef Tripe.

Les 3 paramèters de substr() sont respectivement, la chaîne concernée, la position de départ de la sous-chaîne à extraire et le nombre de caractère à extraire.
La chaîne commence à la position 0, et non 1 : substr($_POST['comments'], 0, 30) signifie donc "extraire 30 caractères de $_POST['comments'] en partant du début de cette chaîne".

Extraction de la fin d'une chaîne avec substr() :

print 'Card: XX';
print substr($_POST['card'],-4,4);

Si le paramètre du formulaire vaut 4000-1234-5678-9101, ceci affichera :

Card: XX9101

C'est donc un exemple très pratique pour les cartes de crédit.

Pour abréger, vous pouvez utiliser substr($_POST['card'],-4) au lieu de substr($_POST['card'], -4,4). Si vous ne fournissez pas le dernier paramètre, substr() renverra tout ce qui se trouve entre la position de départ (qu'elle soit positive ou négative) et la fin de la chaîne.

Utilisation de str_replace() :

print str_replace('{class}',$my_class,
                  '<span class="{class}">Fried Bean Curd<span>
                   <span class="{class}">Oil-Soaked Fish</span>');

Affichera :

<span class="lunch">Fried Bean Curd<span>
<span class="lunch">Oil-Soaked Fish</span>

3.2 Opérateurs arithmétiques

Quelques opérations élémentaires en php :

print 2 + 2;
print 17 - 3.5;
print 10 / 3;
print 6 * 9;

Affichera :

4
13.5
3.3333333333333
54

Outre les signes +, -,/ et *, php dispose du module % qui renvoie le reste d'une division :

print 17 % 3;

affichera :

2

3.3 Variables

Voici un exemple de variables acceptables :

$size
$drinkSize
$my_drink_size
$_drinks
$drink4you2

Et non acceptable :

Variable name Flaw
Begins with a number $2hot4u
Unacceptable character: - $drink-size
Unacceptable characters: @ and . [email protected]
Unacceptable character: ! $drink!lots
Unacceptable character: + $drink+dinner

Les noms des variables sont sensibles à la casse !!!

3.4 Opérations sur les variables

Quelques opérations sur les variables :

<?php
$price = 3.95;
$tax_rate = 0.08;
$tax_amount = $price * $tax_rate;
$total_cost = $price + $tax_amount;
$username = 'james';
$domain = '@example.com';
$email_address = $username . $domain;
print 'The tax is ' . $tax_amount;
print "\n"; // this prints a linebreak
print 'The total cost is ' .$total_cost;
print "\n"; // this prints a linebreak
print $email_address;
?>

Addition combinée à l'affectation :

// Add 3 the regular way
$price = $price + 3;
// Add 3 with the combined operator
$price += 3;

Incrémentation et décrémentation :

// Add one to $birthday
$birthday = $birthday + 1;
// Add another one to $birthday
++$birthday;
// Subtract 1 from $years_left
$years_left = $years_left - 1;
// Subtract another 1 from $years_left

3.5 Variables placées dans les chaînes

Interpolation dans un document sur place :

$page_title = 'Menu';
$meat = 'pork';
$vegetable = 'bean sprout';
print <<<MENU
<html>
<head><title>$page_title</title></head>
<body>
<ul>
<li> Barbecued $meat
<li> Sliced $meat
<li> Braised $meat with $vegetable
</ul>
</body>
</html>
MENU;

Affichera :

<html>
<head><title>Menu</title></head>
<body>
<ul>
<li> Barbecued pork
<li> Sliced pork
<li> Braised pork with bean sprout
</ul>
</body>

Interpolation avec accolades :

$preparation = 'Braise';
$meat = 'Beef';
print "{$preparation}d $meat with Vegetables";

Affichera :

Braised Beef with Vegetables

Sans les accolades, l'instruction print de l'exemple ci dessus aurait été :

print "$preparationd $meat with Vegetables";

4 Prises de décision et répétitions

Dans ce chapitre, nous allons voir comment :

  • Afficher un menu spécial si un utilisateur doté des droits d'admin est connecté.
  • Afficher un en-tête de page différent en fonction du moment de la journée.
  • Prévenir un user s'il a reçu de nouveaux messages depuis sa dernière connection.

Lorsqu'il prends des décisions, l'interpréteur PHP ramène une expression à une valeur true ou false.

La valeur d'une affectation est la valeur affectée. L'expression $prix = 5 vaut 5 : ce prix a été affecté à $prix. Comme l'affectatiion produit un ésultat, vous pouvez enchaîner les affectations pour affecter la même valeur à plusieurs variables :

$prix = $quantite = 5;

4.1 Prise de décision

Utilisation du elseif() :

if ($logged_in) {
    // This runs if $logged_in is true
    print "Welcome aboard, trusted user.";
} elseif ($new_messages) {
    // This runs if $logged_in is false but $new_messages is true
    print "Dear stranger, there are new messages.";
} elseif ($emergency) {
    // This runs if $logged_in and $new_messages are false
    // But $emergency is true
    print "Stranger, there are no new messages, but there is an emergency.";
} else {
    // You can put what you want
}

4.2 Création de décisions complexe

L'opérateur d'égalité :

if ($new_messages == 10) {
   print "You have ten new messages.";
}
if ($new_messages == $max_messages) {
   print "You have the maximum number of messages.";
}
if ($dinner == 'Braised Scallops') {
   print "Yum! I love seafood.";
}

L'opérateur de différence :

if ($new_messages != 10) {
   print "You don't have ten new messages.";
}
if ($dinner != 'Braised Scallops') {
   print "I guess we're out of scallops.";
}

Faites attention à ne pas utiliser = lorsque vous voulez utiliser ==. Un seul signe égal affecte une valeur et renvoie la valeur affectée , tandis que deux signes égal testent l'égalité et renvoient true si les valeurs sont égales. Si vous oubliez le second signe égal, vous obtiendrez généralement un test if() qui vaudra toujorus true :

Exemple d'affectation qui aurait dû être une comparaison :

if ($new_messages = 12) {
   print "It seems you now have twelve new messages.";
}

Un moyen d'éviter l'utilisation malencontreuse de = à la place de == consiste à placer la variable à droite de la comparaison et le littéral à gauche :

if (12 == $new_messages) {
   print "You have twelve new messages.";
}

Opérateurs inférieur et supérieur :

if ($age> 17) {
    print "You are old enough to download the movie.";
}
if ($age >= 65) {
    print "You are old enough for a discount.";
}
if ($celsius_temp <= 0) {
    print "Uh-oh, your pipes may freeze.";
}
if ($kelvin_temp < 20.3) {
    print "Your hydrogen is a liquid or a solid now.";
}

Les nombres à virgule flottante ont une représentation interne qui peut être légèrement différente de la valeur qui leur a été affectée (la représentation interne de 50.0 par exmeple, pourrait être 50.000000002). Pour tester si 2 nombres à virgule flottante sont égaux, vérifiez si la différence entre ces 2 nombres est inférieure à un seuil raisonnablement petit, au lieu d'utiliser l'opérateur d'égalité. Si vous comparez les valeurs monétaires, par exemple, un seuil acceptable serait 0.00001.

Comparaisons de nombres à virgule flottante :

if(abs($price_1 - $price_2) < 0.00001) {
    print '$price_1 and $price_2 are equal.';
} else {
    print '$price_1 and $price_2 are not equal.';
}

La fonction abs() renvoie la valeur absolue de son paramètre. Avec abs(), la comparaison fonctionne correctement, que $price_1 soit plus grand ou non que $price_2.

Les codes ASCII des chiffres sont inférieurs à ceux des majuscules, eux même inférieurs aux codes des minuscules, les codes des lettres accentuées sont la partie "étendue", donc supérieurs à tous les codes de l'ASCII international.

Généralement les chaînes sont comparées selon l'ordre alphabétique (caramel < chocolat).

Comparaison de chaînes :

if ($word < 'baa') {
    print "Your word isn't cookie.";
}
if ($word>= 'zoo') {
    print "Your word could be zoo or zymurgy, but not zone.";
}

Si vous voulez être sûr que l'interpréteur PHP compare les chaînes dans effectuer de conversion numérique en coulisse, utilisez la fonction strcmp() qui compare toujours ses paramètres selon l'ordre de la table ASCII.

La fonction strcmp() prend deux chaînes en paramètres. Elle renvoie un nombre positif si la première chaîne est plus grande que la seconde ou un nombre négatif si la première chaîne est inférieure à la seconde. L'ordre est celui de la table ASCII étendue. Cette fonction renvoie 0 si les 2 chaînes sont égales.

Comparaisons de chaînes avec strcmp() :

$x = strcmp("x54321","x5678");
if ($x > 0) {
    print 'The string "x54321" is greater than the string "x5678".';
} elseif ($x < 0) {
    print 'The string "x54321" is less than the string "x5678".';
}

Dans l'exemple ci dessous, strcmp() trouve que la chaîne "54321" est inférieur à "5678" car les seconds caractères des 2 chaînes diffèrent et que "4" est avant "6". L'ordre alphabétique est seulement ce qui importe à la fonction strcmp(), peut importe que numériquement ce soit l'inverse.

// These values are compared using numeric order
if ("54321" > "5678") {
    print 'The string "54321" is greater than the string "5678".';
} else {
    print 'The string "54321" is not greater than the string "5678".';
}

Utilisation de l'opérateur de négation :

if (! strcasecmp($first_name,$last_name)) {
   print '$first_name and $last_name are equal.';
}

Grâce aux opérateurs logiques, vous pouvez combiner plusieurs expressions dans une même instruction if(). L'opérateur logique ET, &, teste si 2 expressions sont toutes les 2 vraies.
L'opérateur logique OU, ||, teste si l'une au moins des 2 expressions est vraie :

if (($age >= 13) && ($age < 65)) {
   print "You are too old for a kid's discount and too young for the senior's discount.";
}
if (($meal == 'breakfast') || ($dessert == 'souffle')) {
   print "Time to eat some eggs.";
}

4.3 Répétitions

Production d'un menu <select> avec while() :

$i = 1;
print '<select name="people">';
while ($i <= 10) {
    print "<option>$i</option>\n";
    $i++;
}
print '</select>';

Affichera :

<select name="people"><option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>

Production d'un menu <select> avec for() :

print '<select name="people">';
for ($i = 1; $i <= 10; $i++) {
    print "<option>$i</option>";
}
print '</select>';

La troisième expression ($i++) est l'expression d'itération. Elle est exécutée après chaque exécution du corps de la boucle.

Plusieurs expressions dans for() :

print '<select name="doughnuts">';
for ($min = 1, $max = 10; $min < 50; $min += 10, $max += 10) {
    print "<option>$min - $max</option>\n";
}
print '</select>';

5 Utilisation des tableaux

Dans les exemples qui vont suivre, voici le tableau type sur lequel nous allons nous appuyer :
Php tab.jpg

5.1 Création d'un tableau

  • Création de tableaux :
// An array called $vegetables with string keys
$vegetables['corn'] = 'yellow';
$vegetables['beet'] = 'red';
$vegetables['carrot'] = 'orange';
// An array called $dinner with numeric keys
$dinner[0] = 'Sweet Corn and Asparagus';
$dinner[1] = 'Lemon Chicken';
$dinner[2] = 'Braised Bamboo Fungus';
// An array called $computers with numeric and string keys
$computers['trs-80'] = 'Radio Shack';
$computers[2600] = 'Atari';
$computers['Adam'] = 'Coleco';

Les clés et les valeurs des tableaux s'écrivent exactement comme les autre chaînes et nombre d'un programme PHP : avec des apostrophes autour des chaînes, mais pas autour des nombres.

  • Création de tableaux avec array() :
$vegetables = array('corn' => 'yellow',
                    'beet' => 'red',
                    'carrot' => 'orange');
$dinner = array(0 => 'Sweet Corn and Asparagus',
                1 => 'Lemon Chicken',
                2 => 'Braised Bamboo Fungus');
$computers = array('trs-80' => 'Radio Shack',
                   2600 => 'Atari',
                   'Adam' => 'Coleco');

Avec array(), vous précisez une liste de paires clé/valeur séparées par des virgules. La clé et la valeur sont séparées par =>. La syntaxe array() st plus concise lorsque l'on ajoute plusieurs éléments à la fois à un tableau. La syntaxe des crochets est préférable lorsque l'on ajoute les éléments un à un.

5.2 Création d'un tableau indicé par des nombres

Si vous créez un tableau avec array() en ne précisant qu'une liste de valeurs au lieu de paires clé/valeurs, l'interpréteur PHP affecte automatiquement une clé numérique à chaque valeur. Les clés commencent à 0 et augmentent de 1 à chaque élément. L'exemple ci dessous utilise cette technique pour créer le tableau $dinner :

$dinner = array('Sweet Corn and Asparagus',
                'Lemon Chicken',
                'Braised Bamboo Fungus');
print "I want $dinner[0] and $dinner[1].";

Affichera :

I want Sweet Corn and Asparagus and Lemon Chicken.

PHP utilise automatiqumet des nombres incrémentés pour les clés lorsque l'on crée un tableau ou que l'on ajoute des éléments à un tableau avec la syntaxe des crochets vides :

// Create $lunch array with two elements
// This sets $lunch[0]
$lunch[] = 'Dried Mushrooms in Brown Sauce';
// This sets $lunch[1]
$lunch[] = 'Pineapple and Yu Fungus';
// Create $dinner with three elements
$dinner = array('Sweet Corn and Asparagus', 'Lemon Chicken',
                'Braised Bamboo Fungus');
// Add an element to the end of $dinner
// This sets $dinner[3]
$dinner[] = 'Flank Skin with Spiced Flavor';

Si le tableau n'existe pas encore, les crochets vides le créent en ajoutant un élément de clé 0.

5.3 Trouver la taille d'un tableau

La fonction count() renvoie le nombre d'éléments d'un tableau :

$dinner = array('Sweet Corn and Asparagus',
                'Lemon Chicken',
                'Braised Bamboo Fungus');
$dishes = count($dinner);
print "There are $dishes things for dinner.";

Affichera :

There are 3 things for dinner.

Lorsqu'on lui passe un tableau vide (c'est à dire un tableau ne contenant aucun élément), count() renvoie 0. Un tableau vide est également évalué comme false dans une expression de test.

5.4 Parcours des tableaux

  • Parcours avec foreach() :
$meal = array('breakfast' => 'Walnut Bun',
              'lunch' => 'Cashew Nuts and White Mushrooms',
              'snack' => 'Dried Mulberries',
              'dinner' => 'Eggplant with Chili Sauce');
print "<table>\n";
foreach ($meal as $key => $value) {
    print "<tr><td>$key</td><td>$value</td></tr>\n";
}
print '</table>';

Affichera :

<table>
<tr><td>breakfast</td><td>Walnut Bun</td></tr>
<tr><td>lunch</td><td>Cashew Nuts and White Mushrooms</td></tr>
<tr><td>snack</td><td>Dried Mulberries</td></tr>
<tr><td>dinner</td><td>Eggplant with Chili Sauce</td></tr>
</table>
  • Pour alterner les couleurs de lignes d'une table :
$row_color = array('red','green');
$color_index = 0;
$meal = array('breakfast' => 'Walnut Bun',
              'lunch' => 'Cashew Nuts and White Mushrooms',
              'snack' => 'Dried Mulberries',
              'dinner' => 'Eggplant with Chili Sauce');
print "<table>\n";
foreach ($meal as $key => $value) {
    print '<tr bgcolor="' . $row_color[$color_index] . '">';
    print "<td>$key</td><td>$value</td></tr>\n";
    // This switches $color_index between 0 and 1
    $color_index = 1 - $color_index;
}
print '</table>';

Affichera :

<table>
<tr bgcolor="red"><td>breakfast</td><td>Walnut Bun</td></tr>
<tr bgcolor="green"><td>lunch</td><td>Cashew Nuts and White Mushrooms</td></tr>
<tr bgcolor="red"><td>snack</td><td>Dried Mulberries</td></tr>
<tr bgcolor="green"><td>dinner</td><td>Eggplant with Chili Sauce</td></tr>
</table>
  • Modification d'un tableau avec foreach() :
$meals = array('Walnut Bun' => 1,
               'Cashew Nuts and White Mushrooms' => 4.95,
               'Dried Mulberries' => 3.00,
               'Eggplant with Chili Sauce' => 6.50);
foreach ($meals as $dish => $price) {
    // $price = $price * 2 does NOT work
    $meals[$dish] = $meals[$dish] * 2;
}
// Iterate over the array again and print the changed values
foreach ($meals as $dish => $price) {
    printf("The new price of %s is \$%.2f.\n",$dish,$price);
}
  • Utilisation de foreach() avec les tableaux indicés :
$dinner = array('Sweet Corn and Asparagus',
                'Lemon Chicken',
                'Braised Bamboo Fungus');
foreach ($dinner as $dish) {
    print "You can eat: $dish\n";
}
  • Parcours d'un tableau indicé avec for() :
$dinner = array('Sweet Corn and Asparagus',
                'Lemon Chicken',
                'Braised Bamboo Fungus');
for ($i = 0, $num_dishes = count($dinner); $i < $num_dishes; $i++) {
  print "Dish number $i is $dinner[$i]\n";
}
  • Alterner les couleurs des lignes d'une table avec for() :
$row_color = array('red','green');
$dinner = array('Sweet Corn and Asparagus',
                'Lemon Chicken',
                'Braised Bamboo Fungus');
print "<table>\n";
for ($i = 0, $num_dishes = count($dinner); $i < $num_dishes; $i++) {
    print '<tr bgcolor="' . $row_color[$i % 2] . '">';
    print "<td>Element $i</td><td>$dinner[$i]</td></tr>\n";
}
print '</table>';
  • Pour garantir un accès aux éléments selon l'ordre nuémrique de leurs clés, utilisez for() :
for ($i = 0, $num_letters = count($letters); $i < $num_letters; $i++) {
    print $letters[$i];
}

Pour savoir s'il existe un élément ayant une clé donnée, utilisez array_key_exists() :

meals = array('Walnut Bun' => 1,
               'Cashew Nuts and White Mushrooms' => 4.95,
               'Dried Mulberries' => 3.00,
               'Eggplant with Chili Sauce' => 6.50,
               'Shrimp Puffs' => 0); // Shrimp Puffs are free!
$books = array("The Eater's Guide to Chinese Characters",
               'How to Cook and Eat in Chinese');
// This is true
if (array_key_exists('Shrimp Puffs',$meals)) {
    print "Yes, we have Shrimp Puffs";
}
// This is false
if (array_key_exists('Steak Sandwich',$meals)) {
    print "We have a Steak Sandwich";
}
// This is true
if (array_key_exists(1, $books)) {
    print "Element 1 is How to Cook in Eat in Chinese";
}
  • La fonction array_search() est similaire à in_array(), mais si elle trouve un élément elle renvoie sa clé plutôt que true. Dans l'exemple ci dessous, array_search() renvoie le nom du plat qui coûte 6,50 euros :
$meals = array('Walnut Bun' => 1,
               'Cashew Nuts and White Mushrooms' => 4.95,
               'Dried Mulberries' => 3.00,
               'Eggplant with Chili Sauce' => 6.50,
               'Shrimp Puffs' => 0);
$dish = array_search(6.50, $meals);
if ($dish) {
    print "$dish costs \$6.50";
}

5.5 Modification des tableaux

  • Interpolation des éléments de tableaux dans les chaînes entre apostrophes doubles :
$meals['breakfast'] = 'Walnut Bun';
$meals['lunch'] = 'Eggplant with Chili Sauce';
$amounts = array(3, 6);
print "For breakfast, I'd like $meals[breakfast] and for lunch, ";
print "I'd like $meals[lunch]. I want $amounts[0] at breakfast and ";
print "$amounts[1] at lunch.";

La fonction unset() permet de supprimer un élément d'un tableau :

unset($dishes['Roast Duck']);

Supprimer un élément avec unset() est différent de simplement lui affecter 0 ou la chaîne vide. Lorque l'on utilise unset(), l'élément n'est plus là lorsque l'on parcourt le tableay ou que l'on compte le nombre de ses éléments.
Utiliser unset() sur un tableau qui représente un inventaire revient à dire que le magasin n propose plus un produit. Fixer la valeur de l'élément à 0 ou lui affecter la chaîne vide revient à dire que cet élément n'est plus en stock pour le moment.

  • Création d'une chaîne à partir d'un tableau avec implode() :
$dimsum = array('Chicken Bun','Stuffed Duck Web','Turnip Cake');
$menu = implode(', ', $dimsum);
print $menu;

Affichera :

Chicken Bun, Stuffed Duck Web, Turnip Cake

Pour convertir un tableau sans ajouter de délimiteur, utilisez la chaîne vide comme premier paramètre d'implode() :

$letters = array('A','B','C','D');
print implode(,$letters);

Affichera :

ABCD
  • Production des lignes d'une table HTML avec implode() :
$dimsum = array('Chicken Bun','Stuffed Duck Web','Turnip Cake');
print '<tr><td>' . implode('</td><td>',$dimsum) . '</td></tr>';

Affichera :

<tr><td>Chicken Bun</td><td>Stuffed Duck Web</td><td>Turnip Cake</td></tr>

Comme vous l'avez certainement vu, cela évite d'écrire une boucle.

  • Conversion d'un chaîne en tableau avec explode() :
$fish = 'Bass, Carp, Pike, Flounder';
$fish_list = explode(', ', $fish);La f
print "The second fish is $fish_list[1]";

Affichera :

The second fish is Carp

5.6 Tri de tableaux

La fonction sort() trie un tableau selon les valeurs de ses éléments. Elle ne devrait être utilisée que sur les tableaux ayant des lcés numériques car elle réinitialise ces clés lors du tri. Voici quelques tableaux avant et après unappel à sort().

Tri avec sort() :

$dinner = array('Sweet Corn and Asparagus',
                'Lemon Chicken',
                'Braised Bamboo Fungus');
$meal = array('breakfast' => 'Walnut Bun',
              'lunch' => 'Cashew Nuts and White Mushrooms',
              'snack' => 'Dried Mulberries',
              'dinner' => 'Eggplant with Chili Sauce');
print "Before Sorting:\n";
foreach ($dinner as $key => $value) {
    print " \$dinner: $key $value\n";
}
foreach ($meal as $key => $value) {
    print "   \$meal: $key $value\n";
}
sort($dinner);
sort($meal);
print "After Sorting:\n";
foreach ($dinner as $key => $value) {
    print " \$dinner: $key $value\n";
}
foreach ($meal as $key => $value) {
    print "   \$meal: $key $value\n";
}

Affichera :

Before Sorting:
$dinner: 0 Sweet Corn and Asparagus
$dinner: 1 Lemon Chicken
$dinner: 2 Braised Bamboo Fungus
  $meal: breakfast Walnut Bun
  $meal: lunch Cashew Nuts and White Mushrooms
  $meal: snack Dried Mulberries
  $meal: dinner Eggplant with Chili Sauce
After Sorting:
$dinner: 0 Braised Bamboo Fungus
$dinner: 1 Lemon Chicken
$dinner: 2 Sweet Corn and Asparagus
  $meal: 0 Cashew Nuts and White Mushrooms
  $meal: 1 Dried Mulberries
  $meal: 2 Eggplant with Chili Sauce
  $meal: 3 Walnut Bun
  • Pour trier un tableau associatif, utilisez asort(), qui conserve les clés et les valeurs :
$meal = array('breakfast' => 'Walnut Bun',
              'lunch' => 'Cashew Nuts and White Mushrooms',
              'snack' => 'Dried Mulberries',
              'dinner' => 'Eggplant with Chili Sauce');
print "Before Sorting:\n";
foreach ($meal as $key => $value) {
    print "   \$meal: $key $value\n";
}
asort($meal);
print "After Sorting:\n";
foreach ($meal as $key => $value) {
    print "   \$meal: $key $value\n";
}

Affichera :

Before Sorting:
   $meal: breakfast Walnut Bun
   $meal: lunch Cashew Nuts and White Mushrooms
   $meal: snack Dried Mulberries
   $meal: dinner Eggplant with Chili Sauce
After Sorting:
   $meal: lunch Cashew Nuts and White Mushrooms
   $meal: snack Dried Mulberries
   $meal: dinner Eggplant with Chili Sauce
   $meal: breakfast Walnut Bun
  • Alors que sort() et asort() trient les tableaux selon les valeurs de leurs éléments, ksort() permet de trier selon leurs clés : les paires clé/valeur restent identiques, mais sont ordonnées selon les clés.

Les fonctions rsort(), arsort() et krsort() sont les contreparties respectives de sort(), asort() et ksort() pour les tris dans l'ordre décroissant. Elles fonctionnent exactement de la même façon, sauf que c'est la plus grande clé ou valeur (ou la dernière d'un point de vue alphabétique) qui apparara en premier dans le tableau trié et que les éléments suivants seront placés dans un ordre décroissant.

5.7 Utilisation de tableau multidimensionnels

  • Création de t'ableaux multidimentionnels avec array() :
$meals = array('breakfast' => array('Walnut Bun','Coffee'),
               'lunch'     => array('Cashew Nuts', 'White Mushrooms'),
               'snack'     => array('Dried Mulberries','Salted Sesame Crab'));
$lunches = array( array('Chicken','Eggplant','Rice'),
                  array('Beef','Scallions','Noodles'),
                  array('Eggplant','Tofu'));
$flavors = array('Japanese' => array('hot' => 'wasabi',
                                     'salty' => 'soy sauce'),
                 'Chinese' => array('hot' => 'mustard',
                                     'pepper-salty' => 'prickly ash'));

On accède aux éléments de ces tableaux en utilisant des paires de crochets supplémentaires pour les identifier : chaque paire descend d'un niveau dans le tableau complet.

Accès aux éléments d'un tableau multidimensionnel :

print $meals['lunch'][1]; // White Mushroomsprint $meals['snack'][0];           // Dried Mulberries
print $lunches[0][0];               // Chicken
print $lunches[2][1];               // Tofu
print $flavors['Japanese']['salty'] // soy sauce
print $flavors['Chinese']['hot'];   // mustard
  • Manipulation de tableaux multidimentionnel :
$prices['dinner']['Sweet Corn and Asparagus'] = 12.50;
$prices['lunch']['Cashew Nuts and White Mushrooms'] = 4.95;
$prices['dinner']['Braised Bamboo Fungus'] = 8.95;
$prices['dinner']['total'] = $prices['dinner']['Sweet Corn and Asparagus'] +
                             $prices['dinner']['Braised Bamboo Fungus'];
$specials[0][0] = 'Chestnut Bun';
$specials[0][1] = 'Walnut Bun';
$specials[0][2] = 'Peanut Bun';
$specials[1][0] = 'Chestnut Salad';
$specials[1][1] = 'Walnut Salad';
// Leaving out the index adds it to the end of the array
// This creates $specials[1][2]
$specials[1][] = 'Peanut Salad';
  • Parcours d'un tableau multidimentionnel avec foreach) :
$flavors = array('Japanese' => array('hot' => 'wasabi',
                                     'salty' => 'soy sauce'),
                 'Chinese' => array('hot' => 'mustard',
                                     'pepper-salty' => 'prickly ash'));
// $culture is the key and $culture_flavors is the value (an array)
foreach ($flavors as $culture => $culture_flavors) {
    // $flavor is the key and $example is the value
    foreach ($culture_flavors as $flavor => $example) {
        print "A $culture $flavor flavor is $example.\n";
    }
}

Affichera :

A Japanese hot flavor is wasabi.
A Japanese salty flavor is soy sauce.
A Chinese hot flavor is mustard.
A Chinese pepper-salty flavor is prickly ash.

La première boucle foreach() parcourt la première dimension de $flavors. Les clés stockées dans $culture sont les chaînes Japanese et Chinese et les valeurs stockées dans $culture_flavors sont les tableaux qui sont les éléments de cette dimension.
Le foreach() suivant parcourt ces tableaux en copiant les clés comme piquant et salé dans $flavors et les valeurs comme wasabu et soy sauce dans $example. Le bloc de codde du deuxième foreach() utilise les variables des deux instructions foreach() our produire un message complet.

Tout comme les boucles foreach() imbriquées parcourent un tableau associatif multidimensionnel, les boucles for() imbriquées permettent de prcourir un tableau multidimensionnel avec des indices numériques :

$specials = array( array('Chestnut Bun', 'Walnut Bun', 'Peanut Bun'),
                      array('Chestnut Salad','Walnut Salad', 'Peanut Salad') );
// $num_specials is 2: the number of elements in the first dimension of $specials
for ($i = 0, $num_specials = count($specials); $i < $num_specials; $i++) {
    // $num_sub is 3: the number of elements in each sub-array
    for ($m = 0, $num_sub = count($specials[$i]); $m < $num_sub; $m++) {
        print "Element [$i][$m] is " . $specials[$i][$m] . "\n";
    }
}

Affichera :

Element [0][0]   is  Chestnut Bun
Element [0][1]   is  Walnut Bun
Element [0][2]   is  Peanut Bun
Element [1][0]   is  Chestnut Salad
Element [1][1]   is  Walnut Salad
Element [1][2]   is  Peanut Salad

Pour interpoler la valeur d'un tableau multidimensionnel dans une chaîne entre apostrophes doubles ou un document sur place, on doit utiliser la syntaxe pour produire le même résultat que l'exemple précédent : en fait, la seule différence est l'inzstruction print :

Interpolation d'un tableau multidimentionnel :

$specials = array( array('Chestnut Bun', 'Walnut Bun', 'Peanut Bun'),
                   array('Chestnut Salad','Walnut Salad', 'Peanut Salad') );
// $num_specials is 2: the number of elements in the first dimension of $specials
for ($i = 0, $num_specials = count($specials); $i < $num_specials; $i++) {
    // $num_sub is 3: the number of elements in each sub-array
    for ($m = 0, $num_sub = count($specials[$i]); $m < $num_sub; $m++) {
        print "Element [$i][$m] is {$specials[$i][$m]}\n";
    }
}

6 Fonctions

6.1 Déclarations et appels de fonctions

  • Déclaration d'une fonction appellée page_header() :
function page_header() { 
   print '<html><head><title>Welcome to my site</title></head>'; 
   print '<body bgcolor="#ffffff">'; 
}
  • Appel d'une fonction :
page_header(); 
print "Welcome, $user"; 
print "</body></html>";
  • Définitions de fonctions avant ou après leur appel :
function page_header( ) { 
    print '<html><head><title>Welcome to my site</title></head>'; 
    print '<body bgcolor="#ffffff">'; 
} 
 
page_header( ); 
print "Welcome, $user"; 
page_footer( ); 
 
function page_footer( ) { 
    print '<hr>Thanks for visiting.'; 
    print '</body></html>'; 
}

Je vous recommande plus que fortement de coder "propre". En effet, si vous mettez des fonctions n'importe ou dans votre code, ça va vite devenir le bordel. Il faut donc regrouper les fonctions ensemble et les mettre au début de votre code. Je ne suis pas un puriste (...quoi que), mais les personnes repassant derrière votre code, ou vous même si vous le reprenez quelques mois après, vous aprécirez reprendre rapidement le code.

6.2 Passage des paramètres aux fonctions

  • Déclaration d'une fonction avec un paramètre (ici $color) :
function page_header2($color) { 
   print '<html><head><title>Welcome to my site</title></head>'; 
   print '<body bgcolor="#' . $color . '">'; 
}

En appelant la fonction comme ceci :

page_header2('cc00cc'); 

On obtiendra :

<html><head><title>Welcome to my site</title></head><body bgcolor="#cc00cc">

Lorsque l'on définit une fonction prenant un paramètre, on doit passer un paramètre à cette fonction lors de son appel. Dans le cas contraire, l'interpréteur PHP produira un message d'avertissement pour s'en plaindre. Si par exemple, vous appelez page_header2() de la façon suivante :

page_header2(); 

Il s'affichera :

PHP Warning:  Missing argument 1 for page_header2()
  • Utilisation d'une valeur par défaut pour un paramètre :

Pour éviter cet avertissement, faites en sorte que cette fonction puisse être appellée sans paramètre en fournissant une valeur par défaut ans la déclaration de la fonction. En ce cas, si la fonction est appellée sans paramètres, c'est cette valeur par défaut qui sera prise comme valeur de paramètre. Pour fournir une valeur par défaut, placez-la après le nom du paramètre. Ici cette valeur est cc3399 :

function page_header3($color = 'cc3399') { 
   print '<html><head><title>Welcome to my site</title></head>'; 
   print '<body bgcolor="#' . $color . '">'; 
} 

Les valeurs par défaut des paramètres doivent être des littéraux, par exemple 12, cc3399 ou une chaîne ; elles ne peuvent pas être des variables :

$my_color = '#000000'; 
 
// This is incorrect: the default value can't be a variable. 
function page_header_bad($color = $my_color) { 
    print '<html><head><title>Welcome to my site</title></head>'; 
    print '<body bgcolor="#' . $color . '">'; 
}
  • Définition d'une fonction avec 2 paramètres :
function page_header4($color, $title) { 
   print '<html><head><title>Welcome to ' . $title . '</title></head>'; 
   print '<body bgcolor="#' . $color . '">'; 
} 
  • Appel d'une fonction a 2 paramètres :
page_header4('66cc66','my homepage');
  • Définition de plusieurs paramètres facultatifs :
// One optional argument: it must be last 
function page_header5($color, $title, $header = 'Welcome') { 
   print '<html><head><title>Welcome to ' . $title . '</title></head>'; 
   print '<body bgcolor="#' . $color . '">'; 
   print "<h1>$header</h1>"; 
} 
// Acceptable ways to call this function: 
page_header5('66cc99','my wonderful page'); // uses default $header 
page_header5('66cc99','my wonderful page','This page is great!');
// no defaults 

// Two optional arguments: must be last two arguments 
function page_header6($color, $title = 'the page', $header = 'Welcome') { 
   print '<html><head><title>Welcome to ' . $title . '</title></head>'; 
   print '<body bgcolor="#' . $color . '">'; 
   print "<h1>$header</h1>"; 
}
// Acceptable ways to call this function: 
page_header6('66cc99'); // uses default $title and $header 
page_header6('66cc99','my wonderful page'); // uses default $header 
page_header6('66cc99','my wonderful page','This page is great!');
// no defaults

// All optional arguments 
function page_header6($color = '336699', $title = 'the page', $header = 'Welcome') { 
   print '<html><head><title>Welcome to ' . $title . '</title></head>'; 
   print '<body bgcolor="#' . $color . '">'; 
   print "<h1>$header</h1>"; 
} 
// Acceptable ways to call this function: 
page_header7( ); // uses all defaults 
page_header7('66cc99'); // uses default $title and $header 
page_header7('66cc99','my wonderful page'); // uses default $header 
page_header7('66cc99','my wonderful page','This page is great!');
// no defaults

6.3 Valeurs de retour des fonctions

Capture d'une valeur de retour :

$number_to_display = number_format(285266237); 
print "The population of the US is about: $number_to_display"; 

Ce qui affichera :

The population of the US is about: 285,266,237

Pour renvoyer des valeurs à partir de vos propres fonctions, utilisez le mot clé return, suivit de la valeur à renvoyer. L'exécution d'une fonction s'arrête dès la rencontre du mot-clé return et renvoie alors la valeur indiquée. L'exemple suivant définit une fonction renvoyant le montant total d'un repas après avoir ajouter la T.V.A et le pourboire. Renvoie d'une valeur à partir d'une fonction :

function restaurant_check($meal, $tax, $tip) { 
    $tax_amount = $meal * ($tax / 100); 
    $tip_amount = $meal * ($tip / 100); 
    $total_amount = $meal + $tax_amount + $tip_amount; 
 
    return $total_amount; 
}

Une instruction return ne peut renvoyer q'une seule valeur : une syntaxe comme return 15, 23 n'est pas autorisée. Si vous voulez qu'une fonction renvoie plusieurs valeurs, placez-les dans un tableau et renvoyez celui-ci.

Voici une version modifiée de la version restaurant_check() qui renvoie un tableau a 2 éléments, correspondant au montant total avant et après l'ajout du pourboire.

  • Renvoie d'un tableau à partir d'une fonction :
function restaurant_check2($meal, $tax, $tip) { 
    $tax_amount  = $meal * ($tax / 100); 
    $tip_amount  = $meal * ($tip / 100); 
    $total_notip = $meal + $tax_amount; 
    $total_tip   = $meal + $tax_amount + $tip_amount; 
    return array($total_notip, $total_tip);
  }
  • Utilisation d'un tableau renvoyé par une fonction :
$totals = restaurant_check2(15.22, 8.25, 15); 
 
if ($totals[0] < 20) { 
    print 'The total without tip is less than $20.'; 
} 
if ($totals[1] < 20) { 
    print 'The total with tip is less than $20.'; 
}
  • Utilisation des valeurs de retours avec un if()
if (restaurant_check(15.22, 8.25, 15) < 20) { 
    print 'Less than $20, I can pay cash.'; 
} else { 
    print 'Too expensive, I need my credit card.'; 
}
  • Fonctions renvoyant true ou false :
function can_pay_cash($cash_on_hand, $amount) { 
    if ($amount > $cash_on_hand) { 
        return false; 
    } else { 
        return true; 
    } 
} 
 
$total = restaurant_check(15.22,8.25,15); 
if (can_pay_cash(20, $total)) { 
    print "I can pay in cash."; 
} else { 
    print "Time for the credit card."; 
}

Depuis une fonction, il y a 2 façons d'accéder à une variable globale. La méthode la plus directe consiste à les rechercher dans un tableau spécial appelé $GLOBALS, car toute variable globale est accessible comme élément de ce tableau. Voici comment utiliser le tableau $GLOBALS :

$dinner = 'Curry Cuttlefish'; 
 
function macrobiotic_dinner( ) { 
    $dinner = "Some Vegetables"; 
    print "Dinner is $dinner"; 
    // Succumb to the delights of the ocean 
    print " but I'd rather have "; 
    print $GLOBALS['dinner']; 
    print "\n"; 
} 
 
macrobiotic_dinner( ); 
print "Regular dinner is: $dinner";

Ce qui affichera :

Dinner is Some Vegetables but I'd rather have Curry Cuttlefish 
Regular dinner is: Curry Cuttlefish

La 2ème façon d'accéder à une variable globale depuis une fonction consiste à utiliser le mot-clé global, qui indique à l'interpréteur PHP que l'utilisation ultérieur, dans la fonction, de la variable indiquée portera sur cette variable locale, et non sur une variable locale : c'est ce que l'on appelle "placer une variable dans la portée locale". Le mot clé global :

$dinner = 'Curry Cuttlefish'; 
 
function vegetarian_dinner( ) { 
    global $dinner; 
    print "Dinner was $dinner, but now it's "; 
    $dinner = 'Sauteed Pea Shoots';  
    print $dinner; 
    print "\n"; 
} 
 
print "Regular Dinner is $dinner.\n"; 
vegetarian_dinner( ); 
print "Regular dinner is $dinner";

Affichera :

Regular Dinner is Curry Cuttlefish. 
Dinner was Curry Cuttlefish, but now it's Sauteed Pea Shoots 
Regular dinner is Sauteed Pea Shoots

On peut également utiliser global avec plusieurs noms de variables, séparés par des virgules :

global $dinner, $lunch, $breakfast; 

7 Création de formulaires HTML

Afficher un "Hello" :

if (array_key_exists('my_name',$_POST)) { 
    print "Hello, ". $_POST['my_name']; 
} else { 
    print<<<_HTML_
<form method="post" action="$_SERVER[PHP_SELF]"> 
 Your name: <input type="text" name="my_name"> 
<br/> 
<input type="submit" value="Say Hello"> 
</form> 
_HTML_; 
}
  • Récupération et affichage du formulaire :

Recup form php.png

  • Soumission du formlaire et affichage du résultat :

Soum form php.png

Le formulaire est renvoyé à la même URL que celle qui l'a initialement demandé car l'attribut action de la valise <form> est initialisé avec la variable spéciale $_SERVER[PHP_SELF]. Le tableau super-global $_SERVER contient un certain nombre d'informations concernant votre serveur ainsi que la requête qui est en cours de traitement par l'interpréteur PHP. L'élément PHP_SELF de ce tableau, notamment, contient la composante chemin de l'URL de la requête : si par exemple, un script PHP est accédé par http://www.example.com/magazin/catalogue.php, $_SERVER['PHP_SELF'] vaudra /magasin/catalogue.php dans cette page.

Le tableau $_POST est une variable super-globale contenant les données soumises par le formulaire. Ses clés sont les noms des éléments du formulaire et les valeurs correspondantes sont celles de ces éléments. Lorsque l'on clique sur le bouton de soumission, la valeur de $_POST['my_name'] est initialisée avec ce qui a été saisi dans le champ dont l'attribut name vaut my_name.

Ainsi, en testant s'il existe une clé my_name dans le tableau $_POST, on peut savoir si une paramètre nommé my_name a été soumis par le formulaire. Même si ce paramètre a été laissé vide, array_key_exists() renverra true et le message de bienvenue s'affichera.

Attention : Si vous commencez a faire des formulaires accessibles depuis l'extérieur, l'appel à my_name est dangereux si vous ne le protégez pas car il est possible dy insérer du javascript ou du code HTML. Nous verrons plus loin comment s'en protéger. Vous pouvez également regarder les autres documentations PHP dont celles parlant de la sécurité.

7.1 Variables utiles concernant le serveur

Outre PHP_SELF, le tableau super-global $_SERVER contient un certain nombre d'éléments utiles qui fournissent des informations sur le serveur web et la requête en cours de traitement, en voici quelques uns :

Elément Exemple Description
QUERY_STRING http://www.example.com/catalog/store.php?category=kitchen&price=5 La partie de l'URL située après le ? et contenant les paramètres de l'URL
PATH_INFO http://www.example.com/catalog/store.php/browse Informations supplémentaires sur le chemin, placées après le / à la fin de l'URL. Cela permet de passer des informations à un script sans utiliser la chaîne de requête
SERVER_NAME http://www.example.com/catalog/store.php FQDN du site. Si le serveur héberge plusieurs virtualhosts, c'est celui qui est utilisé actuellement qui sera prit.
DOCUMENT_ROOT /var/www Répertoire contenant les documents du site web sur le serveur. Si /var/www est la racine du serveur web, alors http://www.example.com/catalog/store.php correspond à /var/www/catalog/store.php.
REMOTE_ADDR 175.56.28.3 IP du client (IP source)
REMOTE_HOST pool0560.cvx.dialup.verizon.net Si le serveur web est configurer pour faire de la résolution de noms, cette requête est utile, cependant très peu de serveur web s'en servent (traitement trop coûteux en temps)
HTTP_REFERER http://directory.google.com/Top/Shopping/Clothing/ Si l'URL courante a été atteinte a l'aide d'un lien, HTTP_REFER contient l'URL de la page contenant ce lien. Attention : cette valeur peut être falsifiée !
HTTP_USER_AGENT Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Informations sur le navigateur du client, ainsi que l'OS utilisé.

7.2 Accès aux paramètres des formulaires

Les paramètres des URL et des formulaires qui utilisent la méthode GET sont placés dans $_GET, tandis que les paramètres des formulaires utilisant la méthode POST sont mis dans $_POST.
L'URL http://www.example.com/catalog.php?product_id=21&category=fryingpan placera donc 2 valeurs da,s $_GET : $_GET['product_id'] sera initialisé avec 21 et $_GET['category'] avec fryingpan.
La soumission du formulaire ci dessous placera ces mêmes valeurs dans $_POST, en supposant que l'on ait entré 21 dans le champ de saisie et que Frying Pan ait été choisi dans le menu.

  • Formulaire contenant 2 éléments :
<form method="POST" action="catalog.php"> 
<input type="text" name="product_id"> 
<select name="category"> 
<option value="ovenmitt">Pot Holder</option> 
<option value="fryingpan">Frying Pan</option> 
<option value="torch">Kitchen Torch</option> 
</select> 
<input type="submit" name="submit"> </form>
  • Affichage des paramètres soumis par un formulaire :
<form method="POST" action="catalog.php"> 
<input type="text" name="product_id"> 
<select name="category"> 
<option value="ovenmitt">Pot Holder</option> 
<option value="fryingpan">Frying Pan</option> 
<option value="torch">Kitchen Torch</option> 
</select> 
<input type="submit" name="submit"> 
</form> 
Here are the submitted values: 
 
product_id: <?php print $_POST['product_id']; ?> 
<br/> 
category: <?php print $_POST['category']; ?>

Ce qui donne :
Form affiche php.png
Le nom d'un élément de formulaire pouvant contenir plusieurs valeurs doit se terminer par [] afin d'indiquer à l'interpréteur PHP qu'il doit traiter les différentes valeurs comme les éléments d'un tableau. Ainsi, les valeurs soumises pour le menu <select> de l'exemple ci dessous seront placées dnas $_POST['lunch'].

  • Eléments de formulaires multivalués :
<form method="POST" action="eat.php"> 
<select name="lunch[  ]" multiple> 
<option value="pork">BBQ Pork Bun</option> 
<option value="chicken">Chicken Bun</option> 
<option value="lotus">Lotus Seed Bun</option> 
<option value="bean">Bean Paste Bun</option> 
<option value="nest">Bird-Nest Bun</option> 
</select> 
<input type="submit" name="submit"> 
</form>
  • Accès aux valeurs d'un élément multivalué :
<form method="POST" action="eat.php"> 
<select name="lunch[  ]" multiple> 
<option value="pork">BBQ Pork Bun</option> 
<option value="chicken">Chicken Bun</option> 
<option value="lotus">Lotus Seed Bun</option> 
<option value="bean">Bean Paste Bun</option> 
<option value="nest">Bird-Nest Bun</option> 
</select> 
<input type="submit" name="submit"> 
</form> 
Selected buns: 
<br/> 
<?php 
foreach ($_POST['lunch'] as $choice) { 
    print "You want a $choice bun. <br/>"; 
} 
?>

Ce qui donne :
Php multival.png

7.3 Traitement des formulaires avec des fonctions

Pour savoir si un formulaire a été soumis, on peut utiliser des paramètres cachés. Si un paramètre caché se trouve dans $_POST, on traitera le formulaire; sinon, on l'affichera. On utilise cette technique dans l'exemple ci dessous avec le paramètre caché "_submit_check" :

// Logic to do the right thing based on  
// the hidden _submit_check parameter 
if ($_POST['_submit_check']) { 
    process_form( ); 
} else { 
    show_form( ); 
} 
 
// Do something when the form is submitted 
function process_form( ) { 
    print "Hello, ". $_POST['my_name']; 
} 
 
// Display the form 
function show_form( ) { 
    print<<<_HTML_ 
<form method="POST" action="$_SERVER[PHP_SELF]"> 
Your name: <input type="text" name="my_name"> 
<br/> 
<input type="submit" value="Say Hello"> 
<input type="hidden" name="_submit_check" value="1"> 
</form> 
_HTML_; 
}
  • Validation des données d'un formulaire :
// Logic to do the right thing based on  
// the hidden _submit_check parameter 
if ($_POST['_submit_check']) { 
    if (validate_form( )) { 
        process_form( ); 
    } else { 
        show_form( ); 
    } 
} else { 
    show_form( ); 
} 
 
// Do something when the form is submitted 
function process_form( ) { 
    print "Hello, ". $_POST['my_name']; 
} 
 
// Display the form 
function show_form( ) { 
    print<<<_HTML_ 
<form method="POST" action="$_SERVER[PHP_SELF]"> 
Your name: <input type="text" name="my_name"> 
<br/> 
<input type="submit" value="Say Hello"> 
<input type="hidden" name="_submit_check" value="1"> 
</form>
_HTML_; 
} 
 
// Check the form data 
function validate_form( ) { 
    // Is my_name at least 3 characters long? 
    if (strlen($_POST['my_name']) < 3) { 
        return false; 
    } else { 
        return true; 
   }
}

Il faut TOUJOURS valider les informations soumises par un formulaire avant de les traiter. Ne JAMAIS les balancer directement à l'exécution. De l'injection de code étant possible, il est beaucoup plus prudent de vérifier.

  • Affichage de messages d'erreur du formulaire :
// Logic to do the right thing based on  
// the hidden _submit_check parameter 
if ($_POST['_submit_check']) { 
    // If validate_form( ) returns errors, pass them to show_form( ) 
    if ($form_errors = validate_form( )) { 
        show_form($form_errors); 
    } else { 
        process_form( ); 
    } 
} else { 
    show_form( ); 
} 
 
// Do something when the form is submitted 
function process_form( ) { 
    print "Hello, ". $_POST['my_name']; 
} 
 
// Display the form 
function show_form($errors = '') { 
    // If some errors were passed in, print them out 
    if ($errors) { 
        print 'Please correct these errors: <ul><li>'; 
        print implode('</li><li>', $errors); 
        print '</li></ul>'; 
    } 
 
    print<<<_HTML_
<form method="POST" action="$_SERVER[PHP_SELF]"> 
Your name: <input type="text" name="my_name"> 
<br/> 
<input type="submit" value="Say Hello"> 
<input type="hidden" name="_submit_check" value="1"> 
</form> 
_HTML_;
} 
 
// Check the form data 
function validate_form( ) { 
    // Start with an empty array of error messages 
    $errors = array( ); 
 
    // Add an error message if the name is too short 
    if (strlen($_POST['my_name']) < 3) { 
        $errors[  ] = 'Your name must be at least 3 letters long.'; 
    } 
 
    // Return the (possibly empty) array of error messages 
    return $errors; 
}

7.4 Eléments obligatoires

Pour vérifier qu'un élément obligatoire a bien été saisi, contrôlez sa longueur avec la fonction strlen() :

if (strlen($_POST['email']) =  = 0) { 
   $errors[  ] = "You must enter an email address."; } 
}

7.5 Eléments numériques ou chaînes

Pour garantir qu'une valeur saisie est un nombre entier ou flottant, utilisez les fonctions de conversion intval() ou floatval(). Elles vous renverront le nombre (entier ou flottant). contenu dans une chaîne, ensupprimant tout texte superflu ou d'autres formats numériques.

Pour utiliser ces fonctions afin de valider des formulaires, comparez la valeur soumise avec ce que vous obtiendrez si vous la passiez à intval() ou floatval(), puis à strval(). Cette dernière fonction reconvertit le nombre nettoyé en chaîne, ce qui permet une comparaison avec l'élément concerné de $_POST. Si la chaîne soumise et la chaîne nettoyée ne correspondent pas, c'est qu'il y a quelque chose d'anormal dans la valeur soumise : vous devriez donc la rejeter. Dans l'exemple ci dessous, nous voyons comment vérifier q'un élément soumis est bien un entier.

  • Vérification d'un élément pour savoir si c'est un entier :
if ($_POST['age'] != strval(intval($_POST['age'])) { 
    $errors[  ] = 'Please enter a valid age.'; 
}

Si $_POST['age'] est un entier comme 59, 0 ou -32, intval($POST['age']) renverra, respectivement 59, 0 ou -32. Les 2 valeurs correspondront et rien ne sera ajouté à $erreurs. Par contre, si $_POST['age'] vaut 52-poussières, intval($_POST['age']) vaudra 52. Ces 2 valeurs étant différentes, l'expression de test du if() sera vérifiée et un message sera ajouté à $erreurs. Si $_POST['age'] ne contient aucun chiffre, intval($POST['age']) renverra 0. Si, par exemple vieux est la valeur soumise pour $_POST['age'], intval($_POST['age']) reverra 0.

  • Vérification d'un élément pour savoir si c'est un réel :
if ($_POST['price'] != strval(floatval($_POST['price']))) { 
    $errors[  ] = 'Please enter a valid price.'; 
}

Lorsque l'on valide des éléments - tout particulièrement les chaînes de caractères, il est souvent utile de supprimer les espaces de début et de fin avec la fonction trim().
Ainsi, pour empêcher la saisie d'une chaîne ne contenant que des espaces dans un élément obligatoire, vous pouvez combiner l'appel de trim() avec celui de strlen(), comme le montre l'exemple ci dessous :

if (strlen(trim($_POST['name'])) =  = 0) { 
    $errors[  ] = "Your name is required."; 
}

7.6 Intervalles numériques

  • Tester qu'une valeur appartient à un intervalle numérique :
if ($_POST['age'] != strval(intval($_POST['age']))) { 
    $errors[  ] = "Your age must be a number."; 
} elseif (($_POST['age'] < 18) || ($_POST['age'] > 65)) { 
    $errors[  ] = "Your age must be at least 18 and no more than 65.";
}

7.7 Adresses de courrier électronique

Si vous ne souhaitez pas cous lancer dans cette opération de vérification par envoi de message, vous pouvez quand même effectuer quelques tests de syntaxe dans le code de validation du formulaire pour éliminer les adresses mal formées.
Ainsi, l'expression régulière suivante :

^[^@\s][email protected]([-a-z0-9]+\.)+[a-z]{2,}$

correspond aux adresses de courrier les plus fréquentes et rejettera la plupart des mauvaises. Comme le montre l'exemple ci dessous, vous pouvez utiliser dnas un appel à preg_match() :

if (! preg_match('/^[^@\s][email protected]([-a-z0-9]+\.)+[a-z]{2,}$/i',  
                 $_POST['email'])) { 
    $errors[  ] = 'Please enter a valid e-mail address'; 
}

7.8 Menu <select>

Lorsque l'on utilise un menu <select> dans un formulaire, il faut s'assurer que la valeur soumise pour celui-ci fait partie des choix possible du menu. Bien qu'avec un navigateur classique comme Firefox ou IE (et oui malheureusement), un utilisateur ne puisse pas soumettre une valeur qui ne fait pas partie du menu, un pirate peut très bien ne pas utiliser de navigateur et construire de toutes pièces une requête contenant n'importe quelle valeur.

  • Affichage d'un menu <select>
$sweets = array('Sesame Seed Puff','Coconut Milk Gelatin Square', 
                 'Brown Sugar Cake','Sweet Rice and Meat'); 
 
// Display the form 
function show_form( ) { 
    print<<<_HTML_ 
<form method="post" action="$_SERVER[PHP_SELF]"> 
Your Order: <select name="order"> 
 
_HTML_; 
foreach ($GLOBALS['sweets'] as $choice) { 
    print "<option>$choice</option>\n"; 
} 
print<<<_HTML_
</select> 
<br/> 
<input type="submit" value="Order"> 
<input type="hidden" name="_submit_check" value="1"> 
</form> 
_HTML_;
}

Ce qui affichera :

<form method="post" action="order.php"> 
Your Order: <select name="order"> 
<option>Sesame Seed Puff</option> 
<option>Coconut Milk Gelatin Square</option> 
<option>Brown Sugar Cake</option> 
<option>Sweet Rice and Meat</option> 
</select> 
<br/> 
<input type="submit" value="Order"> 
<input type="hidden" name="_submit_check" value="1"> 
</form>

Pour des soucis de sécurité, il est important de vérifier son code, voici comment procéder :

if (! array_key_exists($_POST['order'], $GLOBALS['sweets'])) { 
    $errors[  ] = 'Please choose a valid order.'; 
}

7.9 HTML et Javascript

Le livre d'or facilite la tâche d'un utilisateur malveillant qui peut ainsi mettre sur le serveur du code HTML ou Javascript qui sera ensuite exécuté par un navigateur sans que son utilisateur s'en aperçoive. Ce type de problème est appelé attaqe de type cross scripting car ce livre d'or mal écrit permet à du code provenant d'une certaine source (utilisateur mal intentionné) de faire croire qu'il vient d'ailleurs (le site du livre d'or).

Pour empêcher ce type d'attaque, n'affichez jamais les données provenant de l'extérieur sans les avoir préalablement vérifiées. Supprimez les parties suspectes (les balises HTML, par exemple) ou encodez les caractères spéciaux pour que les navigateurs ne peuvent agir sur du code HTML ou Javascript qui aurait été intégré. PHP vous offre 2 fonctions pour simplifier ces opérations : strip_tags() supprime les marqueurs HTML d'une chaîne et htmlentities() encode les caractères spéciaux et HTML.

  • Suppression des balise HTML d'une chaîne :
// Remove HTML from comments 
$comments = strip_tags($_POST['comments']); 
// Now it's OK to print $comments 
print $comments;
  • Encodage des entités HTML d'une chaîne :
$comments = htmlentities($_POST['comments']); 
// Now it's OK to print $comments 
print $comments;

Dans la pluspart des applications, vous devriez utiliser htmlentities() pour nettoyer les textes qui proviennent de l'extérieur, car cette fonction ne supprime aucun contenu tout en vous protégeant contre les attaques de cross-site scripting.

7.10 Affichage de valeurs par défaut

Lorsque l'on réaffiche un formulaire à cause d'une erreur, préserver les informations déjà saisies par l'utilisateur peut s'avérer pratique.

  • Construction d'un tableau de valeurs par défaut :
if ($_POST['_submit_check']) { 
    $defaults = $_POST; 
} else { 
    $defaults = array('delivery'  => 'yes', 
                      'size'      => 'medium', 
                      'main_dish' => array('taro','tripe'), 
}

Si $_POST['_submit_check'] est initialisé, cela signifie que le formulaire a été soumis : en ce cas, les valeurs par défaut devraient être celles envoyées par l'utilisateur. Dans le cas contraire, nous pouvons configurer nos propres valeurs par défaut.

  • Configurer une valeur par défaut pour un champ de saisie :
print '<input type="text" name="my_name" value="' .  
htmlentities($defaults['my_name']). '">';
  • Configurer une valeur par défaut pour une zone de texte multi-ligne :
print '<textarea name="comments">'; 
print htmlentities($defaults['comments']); 
print '</textarea>';
  • Configurer une valeur par défaut dans un menu <select> :
$sweets = array('puff' => 'Sesame Seed Puff', 
                'square' => 'Coconut Milk Gelatin Square', 
                'cake' => 'Brown Sugar Cake', 
                'ricemeat' => 'Sweet Rice and Meat'); 
 
print '<select name="sweet">'; 
// $val is the option value, $choice is what's displayed 
foreach ($sweets as $option => $label) { 
    print '<option value="' .$option .'"'; 
    if ($option =  = $defaults['sweet']) { 
        print ' selected="selected"'; 
    } 
    print "> $label</option>\n"; 
} 
print '</select>';

8 Utilisation des bases de données pour le stockage d'informations

L'essentiel de ce chapitre utilise PEAR DB, une couche d'abstraction pour l'accès aux bases de donnée qui se greffe sur PHP afin de simplifier les communications entre vos programmes et les logiciels de base de données.

Voici ce que nous allons utiliser :

ID Name Price Is Spicy ?
1 Fried Bean Curd 5.50 0
2 Braised Sea Cucumber 9.95 0
3 Walnut Bun 1.00 0
4 Eggplant with Chilli Sauce 6.50 1

8.1 Connexion à un système de bases de données

  • Chargement d'un fichier externe avec require :
require 'DB.php';

Cette ligne demande à l'interpréteur PHP 'exécuter tout le code de DB.php, qui est le fichier principal de paquetage PEAR DB et qui définit les fonctions que vous utiliserez pour dialoguer avec votre base de données.
Include peut être utilsé à la place de require. La différence est que include ne quittera pas votre programme si le fichier n'existe pas contrairement à requiere.

Après le chargement du module DB, vous devez étalbir une connexion à la base de données à l'aide de la fonction DB::connect() :

require 'DB.php'; 
$db = DB::connect('mysql://penguin:top^[email protected]/restaurant');

Explication de la dernière ligne (DSN : Data Source Name) :

db_program://user:[email protected]/database
  • Voici les valeurs possible pour les SGDB :
db_program Database program
dbase dBase
fbsql FrontBase
ibase InterBase
ifx Informix
msql Mini SQL
mssql Microsoft SQL Server
mysql MySQL (version <= 4.0)
mysqli MySQL (verison >= 4.1.2)
oci8 Oracle (version 7,8 et 9)
odbc ODBC
pgsql PostgreSQL
sqlite SQLite
sybase Sybase

Un appel a DB:connect() renvoie un objet qui vous permettra d'interagir avec la vase de données. En cas de problème de connexion, cette fonction renverra un type d'objet différent, contenant des informations sur les raisons de l'échec. Avant d'aller plus loin, utilisez la fonction DB:isError().

  • Contrôle des erreurs de conexion :
require 'DB.php'; 
$db = DB::connect('mysql://penguin:top^[email protected]/restaurant'); 
if (DB::isError($db)) { die("Can't connect: " . $db->getMessage( )); }

Dans l'exemple ci dessus, le message est "Can't connect:" suivit de "$db->getMessage( )" qui renvoie plus d'informations sur l'erreur.

Après avoir appelé DB:connect(), vous pouvez utiliser les fonctions de l'objet obtenu pour interagir aec la base de données, ainsi, $db->getMessage( ) signifie "appelle la fonction getMessage( ) qui se trouve dans l'objet $db". Ici, $db contient les informations d'erreur et la fonction getMessage() en affiche certaines. Ex :

Can't connect: DB Error: connect failed

8.2 Création d'une table

  • Création d'une table dishes :
CREATE TABLE dishes ( 
    dish_id INT, 
    dish_name VARCHAR(255), 
    price DECIMAL(4,2), 
    is_spicy INT 
)

Certains types de colonnes incluent une longueur ou des informations de format entre parenthèses :

  • VARCHAR(255) : Chaîne de longueur variable de 255 caractères maximum.
  • DECIMAL(4,2) : Nombre décimal de quatre chiffres, dont 2 après la virgule.
  • Types fréquement utilisés pour les colonnes d'une table :
Type de la colonne Description
VARCHAR(longueur) Chaîne de longueur variable. longueur=caractères maximum.
INT entier
BLOB (PostgreSQL appelle ce type BYTEA) Chaîne de données binaires, d'au plus 64 Ko
DECIMAL(total_chiffres,nb_décimale) Nombre décimal de total_chiffres chiffres, dont nb_décimales après la virgule (La virgule décimale est représentée par un point, et non une virgule).
DATETIME (Oracle appelle ce type DATE) Date et heure : 2008-09-07 21:38:48 par exemple
  • Envoie d'une commande CREATE TABLE au système de base de données :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
if (DB::isError($db)) { die("connection error: " . $db->getMessage( )); } 
$q = $db->query("CREATE TABLE dishes ( 
        dish_id INT, 
        dish_name VARCHAR(255), 
        price DECIMAL(4,2), 
        is_spicy INT 
)");
  • Suppression d'une table :
DROP TABLE dishes

8.3 Stockage d'informations dans une base de données

8.3.1 Insert

Pour stocker des données dans la base, il suffit de passer une instruction INSERT à la fonction query() de l'objet :

require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
if (DB::isError($db)) { die("connection error: " . $db->getMessage( )); } 
$q = $db->query("INSERT INTO dishes (dish_name, price, is_spicy)     VALUES ('Sesame Seed Puff', 2.50, 0)");

Pour plus d'explications sur la fonction INSERT d'SQL, reportez vous à l'introduction d'SQL.

Au lieu d'appeller DB:isError après chaque requête, il est plus pratique d'utiliser la fonction setErrorHandling() pour mettre en place un comportement par défaut pour la gestion des erreurs : il suffit de passer la constante PEAR_ERROR_DIE à setErrorHandling() pour que votre programme affiche automatiquement un message d'rreur et s'arrête en cas d'échec d'une requête.

  • Gestion automatique des erreurs avec setErrorHandling() :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
if (DB::isError($db)) { die("Can't connect: " . $db->getMessage( )); } 
// print a message and quit on future database errors 
$db->setErrorHandling(PEAR_ERROR_DIE); 
$q = $db->query("INSERT INTO dishes (dish_size, dish_name, price, is_spicy) 
    VALUES ('large', 'Sesame Seed Puff', 2.50, 0)"); 
print "Query Succeeded!";  
}

Ce qui affichera :

DB Error: syntax error

Le programme se terminant dès qu'il rencontre l'erreur, la dernière ligne de l'exemple ne s'exécutera jamais : le message "Succès de la requête !" ne s'affichera donc pas.

La fonction setErrorHandling() appartient à l'objet $db : vous devez donc d'abord appeler DB::connect() afin d'obtenir cet objet.

8.3.2 Update

Pour plus d'explications sur la fonction UPDATE d'SQL, reportez vous à l'introduction d'SQL.

Voici un exemple de modification de données avec query() :

require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
if (DB::isError($db)) { die("connection error: " . $db->getMessage( )); } 
// Decrease the price some some dishes 
$db->query("UPDATE dishes SET price=price - 5 WHERE price > 20"); 
print 'Changed the price of ' . $db->affectedRows( ) . 'rows.';

8.3.3 Delete

Pour plus d'explications sur la fonction DELETE d'SQL, reportez vous à l'introduction d'SQL.

  • Sppression des données avec query() :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
if (DB::isError($db)) { die("connection error: " . $db->getMessage( )); } 
// remove expensive dishes 
if ($make_things_cheaper) { 
    $db->query("DELETE FROM dishes WHERE price > 19.95"); 
} else { 
    // or, remove all dishes 
    $db->query("DELETE FROM dishes"); 
}

La fonction affectedRows() indique le nombre de lignes qui ont été modifiées ou supprimées par une instruction UPDATE ou DELETE. Pour connaître le nombre de lignes affectées par ces requêtes, appelez-la immédiatement après l'appel à query().

  • Connaître le nombre de lignes affectées par un UPDATE ou un DELETE :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
if (DB::isError($db)) { die("connection error: " . $db->getMessage( )); } 
// Decrease the price some some dishes 
$db->query("UPDATE dishes SET price=price - 5 WHERE price > 20"); 
print 'Changed the price of ' . $db->affectedRows( ) . 'rows.';

8.4 Inserion sécurisée de données provenant de formulaires

L'affichage de données non vérifiées provenant de formulaires peut vous exposer, ainsi que vos utilisateurs à une attaque de type cross-site scripting. Dans des requêtes SQL, ces données peuvent posr un problème similaire, appellé "Attaque par injection SQL".

En soumettant par un formulaire une valeur savamment construite, un utilisateur mal intentionné peut injecter des requêtes SQL quelconques dans votre système de base de données. Pour empêcher ce type d'attaques, vous devez protéger les caractères spéciaux (surtout l'apostrophe) dans les requêtes SQL. PEAR DB fournit une fonctionnalité très utile appellée marqueurs d'emplacement, qui rend tout cela très facile.

La fonctionnalité "apostrophes magiques' est activée par la directive "magic_quotes_gpc" de la configuration de PHP. Pour une gestion plus efficace et plus lisible des paramètres de formulaire, désactivez magic_quotes_gpc et utilisez plutôt des marqueurs d'emplacement ou une fonction de protection lorsque vous devez préparer des données externes pour qu'elles soient utilisées dans une requête de base de données.

Pour utiliser un marque d'emplacement dans une requête, mettez un "?" dans celle-ci à chaque endroit où vous souhaitez mettre une valeur.

  • Exemple d'insertion de données non sûres, provenant d'un formulaire :
$db->query("INSERT INTO dishes (dish_name) VALUES ('$_POST[new_dish_name]')"); 
  • Exemple d'insertion sûre de données provenant d'un formulaire :
$db->query('INSERT INTO dishes (dish_name) VALUES (?)', array($_POST['new_dish_name']));

Vous n'avez pas besoin d'entourer d'apostrophes les marqueurs d'emplacement dans la requête. DB s'en occupe également pour vous.

  • Utilisation de plusieurs marqueurs d'emplacement :
$db->query('INSERT INTO dishes (dish_name,price,is_spicy) VALUES (?,?,?)', array($_POST['new_dish_name'], $_POST['new_price'], $_POST['is_spicy']));

8.5 Génération d'identifiants uniques

Les séquences de PEAR DB vous aideront a produire des identifiants entiers uniques. En effet, lorsque l'on demande l'identifiant suivant d'une séquence particulière, on obtient un nombre dont on est sûr qu'il sera unique dans cette séquence. Même si 2 scripts PHP s'exécutent simultanément et demandent au même instant l'identifiant suivant dans une séquence, chacun d'eux obtiendra une valeur différente.

  • Obtention d'un identifiant d'une séquence :
$dish_id = $db->nextID('dishes'); 
$db->query("INSERT INTO orders (dish_id, dish_name, price, is_spicy)
    VALUES ($dish_id, 'Fried Bean Curd', 1.50, 0)");

8.6 Récupération des données stockées dans la base

Lorsque la fonction query() effectue avec succès une commande SELECT, query() renvoie un objet donnant accès donnant aux lignes obtenues et, à chaque fois que appelerez la fonction fetchRow() sur cet objet, vous obtiendrez la ligne suivante du résultat de la requête. Lorsqu'il n'y a plus de lignes, fetchRow() renvoie une valeur considérée comme fausse, ce qui permet de l'utiliser dans une boucle while().

  • Récupération de lignes avec query() et fetchRow() :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
$q = $db->query('SELECT dish_name, price FROM dishes'); 
while ($row = $q->fetchRow( )) { 
    print "$row[0], $row[1] \n"; 
}

Quand il n'y aura plus de ligne à renvoyer, fetchRow() renverra une valeur qui sera évaluée à false et la boucle while() se terminera.
Pour connaître le nombre de lignes renvoyées par une requête SELECT (sans les parcourir toutes), utilisez la fonction numrows() de l'objet renvoyé par query().

  • Comptage des lignes avec numrows() :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
$q = $db->query('SELECT dish_name, price FROM dishes'); 
print 'There are ' . $q->numrows( ) . ' rows in the dishes table.';

La fonction getAll() exécute une requête SELECT et renvoie un tableau contenant toutes les lignes du résultat.

  • Récupération des lignes avec getAll() :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
$rows = $db->getAll('SELECT dish_name, price FROM dishes'); 
foreach ($rows as $row) { 
    print "$row[0], $row[1] \n"; 
}

Ce qui affichera :

Walnut Bun, 1.00 
Cashew Nuts and White Mushrooms, 4.95 
Dried Mulberries, 3.00 
Eggplant with Chili Sauce, 6.50

8.6.1 Select

Pour plus d'explications sur la fonction SELECT d'SQL, reportez vous à l'introduction d'SQL.

Si vous n'attendez qu'une ligne en résultat d'une requête, utilisez plutôt getRow() : cette fonction exécute SELECT et ne renvoie qu'une seule ligne.

  • Récupération d'une ligne avec getRow() :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
$cheapest_dish_info = $db->getRow('SELECT dish_name, price 
                                   FROM dishes ORDER BY price LIMIT 1'); 
print "$cheapest_dish_info[0], $cheapest_dish_info[1]";

Si vous ne vous intéressez qu'a une seule colonne d'une seule ligne, utilisez la fonction getOne(). Elle envoie une requête SELECT et renvoie une valeur simple : la première colonne de la première ligne renvoyée.

  • Récupération d'une valeur avec getOne() :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
$cheapest_dish = $db->getOne('SELECT dish_name, price FROM dishes ORDER print "The cheapest dish is $cheapest_dish";

8.7 Modification du format des lignes du résultat

Pour plus d'explications sur la fonction Order By et Limit d'SQL, reportez vous à l'introduction d'SQL.

Jusqu'a maintenant, fetchRow(), getAll() et getOne() ont renvoyées des lignes de la base de données sous la forme de tablaux indicés ar des entiers. Cela permet d'interpoler facilement et rapidement les valeurs dans des chaînes entre apostrophes doubles, mais savoir, par exemple, à quelle colonne de la reqête SELECT correspond l'élément 6 du tableau est une opération délicate et sujette aux erreurs. Pour éviter cela, PEAR DB permet de récupérer chaque ligne du résultat dans un tableau indicé par des chaînes ou sous la forme d'un objet.

Le mode de récupération, positionné par la fonction setFetchMode(), contrôle le format des lignes du résultat.

En passant DB_FETCHMODE_ASSOC comme paramètre, on obtient les lignes du résultat sous la forme de tableaux indicés par des chaines.

  • Récupération des lignes sous la forme de tableaux indicés par des chaines :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
 
// Change the fetch mode to string-keyed arrays 
$db->setFetchMode(DB_FETCHMODE_ASSOC); 
 
print "With query( ) and fetchRow( ): \n"; 
// get each row with query( ) and fetchRow( ); 
$q = $db->query("SELECT dish_name, price FROM dishes"); 
while($row = $q->fetchRow( )) { 
    print "The price of $row[dish_name] is $row[price] \n"; 
} 
 
print "With getAll( ): \n"; 
// get all the rows with getAll( ); 
$dishes = $db->getAll('SELECT dish_name, price FROM dishes'); 
foreach ($dishes as $dish) { 
    print "The price of $dish[dish_name] is $dish[price] \n"; 
} 
 
print "With getRow( ): \n"; 
$cheap = $db->getRow('SELECT dish_name, price FROM dishes 
    ORDER BY price LIMIT 1');
print "The cheapest dish is $cheap[dish_name] with price $cheap[price]";

Ceci affichera :

With query( ) and fetchRow( ): 
The price of Walnut Bun is 1.00 
The price of Cashew Nuts and White Mushrooms is 4.95 
The price of Dried Mulberries is 3.00 
The price of Eggplant with Chili Sauce is 6.50 
With getAll( ): 
The price of Walnut Bun is 1.00 
The price of Cashew Nuts and White Mushrooms is 4.95 
The price of Dried Mulberries is 3.00 
The price of Eggplant with Chili Sauce is 6.50 
With getRow( ): 
The cheapest dish is Walnut Bun with price 1.00

Les lignes renvoyées par ces fonctions sont désormais indicées par des chaines représentant les noms des colonnes de la table des plats.

Pour obtenir des lignes sous la forme d'objets, passez en paramètre la constante DB_FETCHMODE_OBJECT à setFetchMode(). Chaque ligne de résultat sera alors un objet dont les attributs porteront les noms des colonnes de la table (comme les clés du tableau lorsque l'on utilise le mode de récupération DB_FETCHMODE_ASSOC).
Par rapport aux tableaux indicés par des chaînes, le mode de récupération DB_FETCHMODE_OBJECT permet d'utiliser une syntaxe pour désigner les données plus concise et plus simple à interpoler : on donne le nom de l'objet suivit de -> puis du nom de l'information souhaitée. $plat->nom_plat, par exemple, désigne linformation nom_plat qui se trouve dans l'objet $plat.

  • Récupération de lignes sous la forme d'objets :
require 'DB.php'; 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
 
// Change the fetch mode to objects 
$db->setFetchMode(DB_FETCHMODE_OBJECT); 
 
print "With query( ) and fetchRow( ): \n"; 
// get each row with query( ) and fetchRow( ); 
$q = $db->query("SELECT dish_name, price FROM dishes"); 
while($row = $q->fetchRow( )) { 
    print "The price of $row->dish_name is $row->price \n"; 
} 
 
print "With getAll( ): \n"; 
// get all the rows with getAll( ); 
$dishes = $db->getAll('SELECT dish_name, price FROM dishes'); 
foreach ($dishes as $dish) { 
    print "The price of $dish->dish_name is $dish->price \n"; 
} 
 
print "With getRow( ): \n";
$cheap = $db->getRow('SELECT dish_name, price FROM dishes 
    ORDER BY price LIMIT 1'); 
print "The cheapest dish is $cheap->dish_name with price $cheap->price";

8.8 Récupération sécurisée des données d'un formulaire

Lorsque l'on utilise dans la clause WHERE d'une commande SELECT, UPDATE ou DELETE des données provenant d'un formulaire ou de toute autre source externe, il faut vérifier que les caractères jockers de SQL sont correctement désactivés dans ces données.

Pour que les caractères jockers de SQL saisis dans un formulaire soient désactivés dans les reqêtes, vous devez renoncer au confort et à la facilité que procurent les marqueurs d'emplacement et utiliser 2 autres fonctions :

  • quoteSmart() et DB
  • strtr(), fournie par PHP

Appliquez d'abord quoteSmart() à la valeur soumise, ce qui aura le même effet sur les apostrophes, qu'un marqueur d'emplacement : cet appel remplacera par exemple, 'Homard à l'américaine' par 'Homard à l\'américaine'. L'étape suivant consiste à utiliser strtr() pour désactiver les caractère jockers de SQL, % et _.
La valeur avec les apostrophes protégées et les caractères jockers désactivés peut ensuite être utilise dans une requête en toute sécurité.

  • Commande SELECT sans marqueurs d'emplacement :
// First, do normal quoting of the value 
$dish = $db->quoteSmart($_POST['dish_search']); 
// Then, put backslashes before underscores and percent signs 
$dish = strtr($dish, array('_' => '\_', '%' => '\%')); 
// Now, $dish is sanitized and can be interpolated right into the query 
$matches = $db->getAll("SELECT dish_name, price FROM dishes WHERE dish_name LIKE $dish");

Ici, vous ne pouvez pas utiliser un marqeur d'emplacement, car la désactivation des caractères jockers doit intervenir après la protection des apostrophes. En effet, celle-ci place des antislash avant les apostrophes simples, mais également devant les antislash avant les apostrophes simples, mais également devant les antislash : si strtr() ou avec les marqueurs d'emplacement) la retransformerait en '\\%homard\\%' Cette valeur sera interprétée par la base de données comme un antislash littéral, suivit d'un jocker %. Si quoteSmart() est d'abord appellée, par contre, %homard% sera transformé en '%homard%', puis strtr() le retransofmera en '%homard%'.

Cette valeur sera interprétée par la base de données comme un pour cent littéral, suivi de hommard, suivi d'un autre pour-cent littéral ce qui est ce que l'utilisateur avait saisi.

Des caractères jockers non désactivés peuvent avoir un effet encore plus terrible dans la clause WHERE d'une commande UPDATE ou DELETE. L'exemple ci dessous est l'exemple de ce qui ne faut surtout pas faire. Il montre une requête utilisant incorrectement des marqueurs d'emplacement afin d'autoriser une valeur extérieure à contrôler les plats qui seront vendus 1 euro.

  • Utilisation incorrecte de marqueurs d'emplacement dans une commande UPDATE
$db->query('UPDATE dishes SET price = 1 WHERE dish_name LIKE ?',
            array($_POST['dish_name']));

8.9 Formulaire de consultation complet

<?php 
 
// Load PEAR DB 
require 'DB.php'; 
// Load the form helper functions. 
require 'formhelpers.php'; 
 
// Connect to the database 
$db = DB::connect('mysql://hunter:w)[email protected]/restaurant'); 
if (DB::isError($db)) { die ("Can't connect: " . $db->getMessage( )); } 
 
// Set up automatic error handling 
$db->setErrorHandling(PEAR_ERROR_DIE); 
 
// Set up fetch mode: rows as objects 
$db->setFetchMode(DB_FETCHMODE_OBJECT); 
 
// Choices for the "spicy" menu in the form 
$spicy_choices = array('no','yes','either'); 
 
// The main page logic: 
// - If the form is submitted, validate and then process or redisplay 
// - If it's not submitted, display 
if ($_POST['_submit_check']) { 
    // If validate_form( ) returns errors, pass them to show_form( ) 
    if ($form_errors = validate_form( )) { 
        show_form($form_errors); 
    } else { 
        // The submitted data is valid, so process it 
        process_form( ); 
    } 
} else { 
    // The form wasn't submitted, so display 
    show_form( ); 
} 
 
function show_form($errors = '') { 
    // If the form is submitted, get defaults from submitted parameters 
    if ($_POST['_submit_check']) { 
        $defaults = $_POST; 
    } else { 
        // Otherwise, set our own defaults 
        $defaults = array('min_price' => '5.00', 
                      'max_price' => '25.00'); 
} 
 
    // If errors were passed in, put them in $error_text (with HTML markup) 
    if ($errors) { 
        $error_text = '<tr><td>You need to correct the following errors:'; 
        $error_text .= '</td><td><ul><li>'; 
        $error_text .= implode('</li><li>',$errors); 
        $error_text .= '</li></ul></td></tr>'; 
    } else { 
        // No errors? Then $error_text is blank 
        $error_text = ''; 
    } 
 
    // Jump out of PHP mode to make displaying all the HTML tags easier 
?> 
<form method="POST" action="<?php print $_SERVER['PHP_SELF']; ?>"> 
<table> 
<?php print $error_text ?> 
 
<tr><td>Dish Name:</td> 
<td><?php input_text('dish_name', $defaults) ?></td></tr> 
 
<tr><td>Minimum Price:</td> 
<td><?php input_text('min_price', $defaults) ?></td></tr> 
 
<tr><td>Maximum Price:</td> 
<td><?php input_text('max_price', $defaults) ?></td></tr> 
 
<tr><td>Spicy:</td> 
<td><?php input_select('is_spicy', $defaults, $GLOBALS['spicy_choices']); ?> 
</td></tr> 
 
<tr><td colspan="2" align="center"><?php input_submit('search','Search'); ?> 
</td></tr> 
 
</table> 
<input type="hidden" name="_submit_check" value="1"/> 
</form> 
<?php 
      } // The end of show_form( ) 
 
function validate_form( ) { 
    $errors = array( ); 
 
    // minimum price must be a valid floating point number 
    if ($_POST['min_price'] != strval(floatval($_POST['min_price']))) { 
        $errors[  ] = 'Please enter a valid minimum price.'; 
    } 
 
    // maximum price must be a valid floating point number 
    if ($_POST['max_price'] != strval(floatval($_POST['max_price']))) { 
        $errors[  ] = 'Please enter a valid maximum price.'; 
    } 
 
    // minimum price must be less than the maximum price 
    if ($_POST['min_price'] >= $_POST['max_price']) { 
        $errors[  ] = 'The minimum price must be less than the maximum price.'; 
    } 
 
    if (! array_key_exists($_POST['is_spicy'], $GLOBALS['spicy_choices'])) { 
        $errors[  ] = 'Please choose a valid "spicy" option.'; 
    } 
    return $errors; 
} 
 
function process_form( ) { 
    // Access the global variable $db inside this function 
    global $db; 
 
    // build up the query  
    $sql = 'SELECT dish_name, price, is_spicy FROM dishes WHERE 
            price >= ? AND price <= ?'; 
 
    // if a dish name was submitted, add to the WHERE clause 
    // we use quoteSmart( ) and strtr( ) to prevent user-entered wildcards from working 
    if (strlen(trim($_POST['dish_name']))) { 
        $dish = $db->quoteSmart($_POST['dish_name']); 
        $dish = strtr($dish, array('_' => '\_', '%' => '\%')); 
        $sql .= " AND dish_name LIKE $dish"; 
    } 
 
    // if is_spicy is "yes" or "no", add appropriate SQL 
    // (if it's "either", we don't need to add is_spicy to the WHERE clause) 
    $spicy_choice = $GLOBALS['spicy_choices'][ $_POST['is_spicy'] ]; 
    if ($spicy_choice =  = 'yes') { 
        $sql .= ' AND is_spicy = 1'; 
    } elseif ($spicy_choice =  = 'no') { 
        $sql .= ' AND is_spicy = 0'; 
    } 
 
    // Send the query to the database program and get all the rows back 
    $dishes = $db->getAll($sql, array($_POST['min_price'], 
                                      $_POST['max_price'])); 
 
    if (count($dishes) =  = 0) { 
        print 'No dishes matched.'; 
    } else { 
        print '<table>'; 
        print '<tr><th>Dish Name</th><th>Price</th><th>Spicy?</th></tr>'; 
        foreach ($dishes as $dish) { 
            if ($dish->is_spicy =  = 1) { 
                $spicy = 'Yes'; 
            } else { 
                $spicy = 'No'; 
            } 
            printf('<tr><td>%s</td><td>$%.02f</td><td>%s</td></tr>', 
                   htmlentities($dish->dish_name), $dish->price, $spicy); 
        } 
    } 
} 
?>

L'exemple ci dessus contient une ligne supplémentaire dans le code de configuration de la base de données : un appel à setFetchMode().

8.10 MySQL sans PEAR DB

PEAR DB arrondit beaucoup les angles de l'accès aux bases de donnée depuis un programme PHP, mais il y a 2 cas ou ce n'est pas toujours le meilleur choix : il peut ne pas être disponible sur certains systèmes et un programme utilisant les fnctions prédéfinies de PHP, conçues sur mesure pour une bae de données particulière, est plus rapide que s'il utilisait PEAR DB.

Les différences sont dans les détails : les fonctions disponibles et leur fonctionnement varient selon les bases de données et, en général, on doit récupérer les résultats ligne par ligne car on ne dispose pas du confort procuré par getAll(). Il n'existe pas non plus de traitement unifié des erreurs.

PEAR DB function mysqli function Comments
$db = DB::connect( DSN) $db = mysqli_connect(hostname, username, password, database)
$q = $db->query(SQL) $q = mysqli_query($db,SQL) There is no placeholder support in mysqli_query( ).
$row = $q->fetchRow( ) $row = mysqli_fetch_row($q) mysqli_fetch_row( ) always returns numerically indexed arrays. Use mysqli_fetch_assoc( ) for string-indexed arrays or mysqli_fetch_object( ) for objects.
$db->affectedRows( ) mysqli_affected_rows($db)
$q->numRows( ) mysqli_num_rows($q)
$db->setErrorHandling(ERROR_MODE) None You can't set automatic error handling with mysqli, but mysqli_connect_error( ) gives you the error message if something goes wrong connecting to the database program, and mysqli_error($db)gives you the error message after a query or other function call fails.
  • Focntion traiter_form() utilisant mysqli :
function process_form( ) { 
    // Access the global variable $db inside this function 
    global $db; 
 
    // build up the query  
    $sql = 'SELECT dish_name, price, is_spicy FROM dishes WHERE '; 
 
    // add the minimum price to the query 
    $sql .= "price >= '" . 
            mysqli_real_escape_string($db, $_POST['min_price']) . "' "; 
 
    // add the maximum price to the query 
    $sql .= " AND price <= '" . 
            mysqli_real_escape_string($db, $_POST['max_price']) . "' "; 
 
    // if a dish name was submitted, add to the WHERE clause 
    // we use mysqli_real_escape_string( ) and strtr( ) to prevent 
    // user-entered wildcards from working 
    if (strlen(trim($_POST['dish_name']))) { 
        $dish = mysqli_real_escape_string($db, $_POST['dish_name']); 
        $dish = strtr($dish, array('_' => '\_', '%' => '\%')); 
        // mysqli_real_escape_string( ) doesn't add the single quotes 
        // around the value so you have to put those around $dish in 
        // the query: 
        $sql .= " AND dish_name LIKE '$dish'"; 
    } 
 
    // if is_spicy is "yes" or "no", add appropriate SQL 
    // (if it's either, we don't need to add is_spicy to the WHERE clause) 
    $spicy_choice = $GLOBALS['spicy_choices'][ $_POST['is_spicy'] ]; 
    if ($spicy_choice =  = 'yes') { 
        $sql .= ' AND is_spicy = 1'; 
    } elseif ($spicy_choice =  = 'no') { 
        $sql .= ' AND is_spicy = 0'; 
    } 
 
    // Send the query to the database program and get all the rows back 
    $q = mysqli_query($db, $sql); 
 
    if (mysqli_num_rows($q) =  = 0) { 
        print 'No dishes matched.'; 
    } else { 
        print '<table>'; 
        print '<tr><th>Dish Name</th><th>Price</th><th>Spicy?</th></tr>'; 
        while ($dish = mysqli_fetch_object($q)) { 
            if ($dish->is_spicy
                $spicy = 'Yes';
            } else { 
                $spicy = 'No'; 
            } 
            printf('<tr><td>%s</td><td>$%.02f</td><td>%s</td></tr>', 
                   htmlentities($dish->dish_name), $dish->price, $spicy); 
        } 
    } 
}

Les marqueurs d'emplacement de PEAR DB n'étant pas disponible ici, les prix minimum et maximum sont directement placés dans la variable $sql qui contient la requête, mais après avoir été protégés par mysqli_real_escape_string(). Cette même fonction sert également à protégéer $_POST['dish_name']. Enfin, les fonctions servant à passer la requête à la base et à récupérer les résultats sont différentes : la fonction mysqli_query() envoie la requête, mysqli_num_rows() renvoie le nombre de lignes du résultat et mysqli_fetch_object() récupère chaque ligne de ce résultat dans un objet.

9 Mémorisation des utilisateurs grâce aux cookies et aux sessions

Un seul cookie est parfait pour mémoriser une même information mais, souvent, vous devrez conserver plusieurs données pour un même utilisateur (le contenu de son caddie virtuel par exemple). L'utilisation de plusieurs cookies dans ce but implique un traitement lourd : les sessions de PHP permettent alors de résoudre ce problème.

Une session utilise un cookie pour différencie les utilisateurs et facilite la mémorisation d'un ensemble temporaire de données pour chacun d'eux sur le serveur. Ces données persistent entre les requêtes : lors d'une requête, vous pouvez ajouter une variable à la session d'un utilisateur (comme lorsque l'on ajoute un article dans le caddie virtuel) et, à la suivante, vous pouvez récupérer ce qui se trouve dans cette session (comme sur la page de validation d'une commande, lorsque vous devez énumérer tout ce qui se trouve dans le caddie). Dans la section Stockage et récupération des informations, nous verrons comment les utiliser.

10 Débogage

Débogage et profiling de code PHP

11 Ressources

Livre d'Introduction à PHP 5
Pear et les librairies PHP