________    __    __    ________
                   |        |  |  |  |  |  |        |
                   |   __   |  |  |__|  |  |   __   |
                   |  |__|  |  |        |  |  |__|  |
                   |   _____|  |   __   |  |   _____|
                   |  |        |  |  |  |  |  |
                   |__|        |__|  |__|  |__|
                     Cours PHP6 - développement web



                          php.txt  07/04/2024
                            ultimecool.com

Sommaire


  CHAPITRE 1 - Notions élémentaires
      1.1. Variables et types de données
      1.2. Structure de programmation
      1.3. Traduction des notions de classes et objets
      1.4. passage de paramètres par réference
      1.5. passage d'une fonction en paramètre
      1.6. Exceptions
      1.7. SimpleXML
      1.8. Opérations avancées sur les chaines de caractères
      1.9. base de donnees avec MySQL
     1.10. base de donnees avec SQLite
     1.11. Optimisations
     1.12. Compression Web
     1.13. Caches code PHP
     1.14. Utilisation de PHP avec Ajax
    
  CHAPITRE 2 - Notions avancées
      2.1. Tableaux et Dates
      2.2. Expressions régulières

  CHAPITRE 2 - Architecture web
      2.1. Nom de domaine et Hébergement
      2.2. Protection d'un répertoire par .htaccess
      2.3. urlrewriting
      2.4. sitemap
      2.5. Serveur Apache sous Linux
      2.6. Serveur IIS sous Windows
      2.7. Serveur Apache sous Windows

  CHAPITRE 3 - Framework Symfony
      3.1. Introduction
      3.2. Développez votre première application Symfony

CHAPITRE 1 - Notions élémentaires

1.1. Variables et types de données

pas de typage fort; la variable s'adapte a l'opérateur

  • déclaration : global $a; $a = []; $obj = [ 'id' => 1, 'val' => [ 0 => 12 ] ]
  • affectation : $a = 'tete a toto'; $i = 15+17*3; $obj['id'] = 1;
  • lecture : echo "$a";
  • operations : iv = 7 < (16/2); iv = 2*5;
  • operandes : + - * / % . < > <= >= != == || && ! or and === !==
  • commentaires : /* */ //

chaines: '$a\n' tel quel "$a\n" interprété

Une chaîne de caractères n'est pas considérée comme un tableau de caractères. Si $tab n'est pas un tableau, count() retourne 1, si $tab n'est pas défini: 0.

Tableaux :


Tableaux simples                            Tableau associatif
                                            clé <=> valeur table de hachage
$t = array();
$u = array(3,"bonjour",NULL,array());       $v=array(
$t[]="toto"; /* ajoute en fin de $t */        "rouge" => 0xff0000,
                                              "vert" => 0x00ff00,
/* lecture */                                 "bleu" => 0x0000ff);
for($i=0;$i<count($u);$i++)                 echo $v["rouge"];
  echo $u[$i]
/* suppression */                           foreach($v as $k => $val)
unset($u[$i]);                                echo "$k: $val\n";

/* autres parcours */                       foreach($t as ...)
foreach($u as $element)                       echo "$k:$val\n";
  echo $element
/* $element modifiable avec php5 */
 

count($t); // retourne le nombre d'éléments du tableau $tab
is_array($t); // retourne TRUE si la variable $tab est un tableau
array_push($t, 'e1'); $t[] = 'e2';   // ajoute un élément au tableau
array_splice ($t, 0, count($t)); // efface le tableau
array_shift($t); // retourne le premier élément du tableaux et le retire
array_merge ($tab1, $tab2); // Fusionne les deux tableaux
array_reverse($tab);  // inverse l'ordre des éléments du tableau
$tab = array_fill(0, 100, "toto"); // Remplit le tableau
unset($tab[2]);// supprime l'element du tableau, ainsi que son indice
$tab = array_values($tab); // Réindice le tableau
print_r($t); // affiche le contenu du tableau de façon lisible
 

Filtrage d'un tableau


function odd($var)  {                       function even($var)  {                    
    // retourne vrai si impaire                 // retourne vrai si paire
    return($var & 1);                           return(!($var & 1));                  
}                                           }

$array1 = array('a'=>1, 'b'=>2, 'c'=>3, 'd'=>4, 'e'=>5);
$array2 = array(6, 7, 8, 9, 10, 11, 12);

echo 'parcours recursif du tableau des Impair :'.PHP_EOL;
print_r(array_filter($array1, 'odd'));
echo 'parcours recursif du tableau des Pair :'.PHP_EOL;
print_r(array_filter($array2, 'even'));
$result = array_filter($array,
  create_function('$a','return preg_match('#\S#', $a);'));
 

Fonctions pour les tableaux associatifs


// extraire les clés d'un tableau associatif
$tab = array("id" => "1234", "firsname" => "Giles");
$clefs = array_keys($tab, "Jean");
/* $clefs vaut : array("id", "firsname"); */

// extraire les valeurs d'un tableau associatif
$tab = array("id" => "1234", "firsname" => "Giles");
$valeurs = array_values($tab);
/* $valeurs vaut : array("1234", "Giles") */

// savoir si une clé existe dans un tableau associatif
$tab = array("nom" => "Martin");
if(array_key_exists("nom", $tab)) {
    echo "Ok";
}
/* afffiche "Ok" */
if(isset($tab["nom"])) {
    echo "Ok";
}

// tester l'existence d'une valeur dans un tableau
$tab = array(2003, "12.5");
if(in_array(2003, $tab, true) && in_array(12.5, $tab, true)) {
    echo "Trouvé !";
} else {
    echo "Echec";
}
/* affiche "Echec" */
 

Transmettre un tableau d'une page à une autre :

Par la méthode GET


echo '<a href="page_de_reception.php?panier='
 . urlencode(serialize($produits)) . '">page_de_reception</a>';

if(get_magic_quotes_gpc()) {
    $produits = unserialize(stripslashes($_GET['panier']));
}
else {
    $produits = unserialize($_GET['panier']);
}
 

Par la méthode POST


<form method="post" action=" page_de_reception.php">
    <input type="hidden" name="panier" value="<?php echo urlencode(serialize($produits)); ?>" />
    <input type="submit" value="Soumettre" />
</form>
 

$produits = unserialize(urldecode($_POST['panier']));
print_r($produits);
 

Par l'utilisation des sessions


session_start();
$_SESSION['panier'] = $produits;

session_start();
print_r($_SESSION['panier']);
 

Dates

Pour calculer les millisecondes écoulées entre deux moments


$curTime = microtime(true);
$timeConsumed = round(microtime(true) - $curTime,3)*1000;
 

Pour avoir en format date le moment actuel avec les millisecondes


list($usec, $sec) = explode(' ', microtime());
$dateTime = date('d/m/y H:i:s',$sec)
 . substr($usec,1,56);
 

1.2. Structure de programmation

Les structures de controle du PHP sont les mêmes que celles du C.

Inclusion d'un script: include ('mod.php'); // inclusion d'un fichier tel quel pour agréger le code: require_once('mes_fonctions.php'); //inclut une fois

déclaration de fonction/procédure passage par référence:


function nom($param1, $param2) {        fonction nom($param1, &$param2)
  if($param1...)                        // de base dans PHP5
    return ...;       }
 

pour avoir accès aux variables du script dans une fonction, il faut les déclarés dans la fonction en global. Pour inclure des paramétres de configurations il est aussi possible de lire un fichier INI (attention le fichier peut être visible):


[CONFIG]                 $ini_array = @parse_ini_file('../main/menu.txt', TRUE);
DOC_DIR=../docs          if (isset($ini_array['CONFIG']['DOC_DIR'])) {
FORUM_DIR=../phpbb         $doc_dir = $ini_array['CONFIG']['DOC_DIR'];
 

1.3. Traduction des notions de classes et objets

En PHP5, le modèle objet est tout à fait conforme aux grands langages classiques de la POO. Voici un bref rappel:

Une classe est une structure évoluée, qui permet de regrouper non seulement des données, mais aussi des fonctions (méthodes). L'accé aux champs, et aux méthodes se fait avec l'operateur "->". Un objet est une representation dynamique de la classe. Tous les objets d'une même classe auront les mêmes possibilités.

Avant PHP5, les constructeurs étaient des fonctions portant le même nom que la classe dans laquelle ils se trouvaient. Désormais, PHP5 implémente des méthodes spécialement conçues pour les constructeurs et les destructeurs.


class dvpClass {
  function __construct() {             // A l'instanciation de la classe, le
    echo 'Constructeur déclenché<br>'; // constructeur est déclenché.
  }
  function dvp_exemple(){
    echo 'Exemple Objet<br>';
  }
  function __destruct() {              // Le destructeur sera déclenché dès lors
    echo 'Destructeur déclenché';      // que plus  aucune référence à l'objet à
  }                                    // l'objet instancié  n'est  trouvée dans
}                                      // le script (à partir de PHP5)
$obj = new dvpClass();
$obj->dvp_exemple();                   // déclenchement du destructeur.
 

d'autres fonctions: __call __get __set __autoload

L'héritage permet de définir une nouvelle classe à partir d'une classe de base. On parle alors de sous classe, ou de classe dérivée. Cela permet de hiérarchiser et de créer des modèles entre les classes.

Lors de l'héritage de classe, le constructeur et destructeur de la classe mère ne sont pas déclenchés. si besoin, il faut les déclencher explicitement.


class dvpClassFille extends dvpClassParent{    class dvpClassParent{
  function __construct() {                       function __construct(){
      parent::__construct();                       echo 'Constructeur père<br>';
      echo 'Constructeur fille<br>';    }
  }                                              function __destruct(){
  function dvp_exemple(){                          echo 'Destructeur père<br>';
    echo 'Exemple Objet<br>';                    }
  }                                            }
  function __destruct() {
    echo 'Destructeur fille<br>';              // Affichage généré par le script
    parent::__destruct();                      // Constructeur père
  }                                            // Constructeur fille
}                                              // Exemple Objet
$obj = new dvpClassFille();                    // Destructeur fille
$obj->dvp_exemple();                           // Desctructeur père
 

Les accés aux membres de la classe de base, par la classe dérivée, dépand du statut des membres (méthodes et propriétés) dans la classe de base:


     ______________    ________________________    _____________________
     Statut dans la    Accés aux membres de la     Accés aux membres de
     classe de base    classe de base par un       la classe de base par
                       utilisateur de la classe    une classe derivée
     ______________    ________________________    _____________________
     private           non                         non
     protected         non                         oui
     public            oui                         oui
  • interface: Permet de définir des interfaces
  • implements: Permet d'implémenter une interface préalablement définie
  • abstract: Classe ne pouvant être instanciée. Méthodes non implementés mais à redéfinir dans la sous classe
  • Le principe de surcharge n'est pas implémenté
  • Le polymorphisme est implémenté
  • final: Empêche les classes filles de reimplémenter une méthode mère
  • static: Défini des propriétés/méthodes accessibles sans instanciation
  • La "clonisation" des objets Permet de copier un objet de la manière prévue par le développeur, par la méthode __clone()

abstract class A {                     class B extends A {
  abstract public function p(){};        public function p() { ... }
  protected function       q() {};     }
}

class C { public static $propriete = 1; }
echo C::$propriete;//autorisé, affiche 1

<?php                             // en definissant la methode __clone
class dvpClass{                   // class dvpClass{
  public $propriete;              //   public $propriete;
                                  //
  function __construct($val){     //   function __construct($val){
    $this->propriete=$val;        //     $this->propriete=$val;
  }                               //   }
}                                 //   function __clone(){
$obj=new dvpClass(1);             //     $this->propriete=2;
echo $obj->propriete;             //   }
$clone=clone $obj;                // }
echo $clone->propriete;           // le résultat aurai été:12 au lieu de 11
?>
 

1.4. passage de paramètres par réference

Dans le passage par valeur, il s'agit d'une recopie de la variable, mais dans le passage par référence c'est la même variable parente qui est utilisée. Elle est realisée par le mot "&" lors de la déclaration de la fonction. Il est possible d'acceder aux variables parentes par global:


$type='vide';
function EtudeParametre( &$a) {
  global $type;
  $a=$type;
}
 

1.5. passage d'une fonction en paramètre


// An example callback function
function my_callback_function() {
    echo 'hello world!';
}

// An example callback method
class MyClass {
  static function myCallbackMethod() {
    echo 'Hello World!';
  }
}                                  

// Type 1: Simple callback
call_user_func('my_callback_function');

// Type 2: Static class method call
call_user_func(array('MyClass', 'myCallbackMethod'));

// Type 3: Object method call
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

// Type 4: Static class method call (As of PHP 5.2.3)
call_user_func('MyClass::myCallbackMethod');

// Type 5: Relative static class method call (As of PHP 5.3.0)
class A {
    public static function who() {
        echo "A\n";
    }
}

class B extends A {
    public static function who() {
        echo "B\n";
    }
}

call_user_func(array('B', 'parent::who')); // A
 

1.6. Exceptions

Les célèbres "try" et "catch" sont enfin implémentés en PHP5. Voici un exemple:


$Obj = new dvpExempleException();    class dvpExempleException {
                                       public function genererException($pbme) {
try {                                    if(!is_int($pbme)) {
  $Obj->genererException('chaîne');        throw new Exception ("L'argument "
}                                            ."-$pbme- n'est pas numérique");
catch (Exception $exception) {           }
  echo $exception->getMessage().','    }
      .$exception->getLine().','     }
      .$exception->getFile();
}
 

Les méthodes getMessage(), getLine() et getFile() sont des méthodes appartenant à la classe Exception. Elles affichent respectivement le message d'erreur, le numéro de ligne où l'exception est générée (throw) et enfin le nom du script où l'exception s'est produite. La classe Exception étant assez basique, vous pouvez bien sûr l'étendre avec une de vos propres classes (maclasse extends Exception…) bien sûr l'étendre avec une de vos propres classes (maclasse extends Exception…)

1.7. SimpleXML

L'introduction de SimpleXML avec PHP5 est certainement une belle avancée dans le domaine d'interaction entre PHP et XML. Là où l'utilisation des objets existant était parfois complexe, SimpleXML, simplifie l'interprétation des fichiers XML.


<?xml version="1.0"?>                 <?php
<nouvelles>                           $nouvelles = simplexml_load_file(
  <nouvelle>                            'nouvelles.xml');
    <contenu>tempête</contenu>        foreach($nouvelles->nouvelle as $nouvelle)
    <date>28/12/2008</date>           {
  </nouvelle>                             echo 'Contenu : ' ,utf8_decode(
  <nouvelle>                                $nouvelle->contenu).'<br>';
    <contenu>soldes</contenu>             echo 'Date : ' ,$nouvelle->date
    <date>10/01/2009</date>                 .'<br>';
  </nouvelle>                         }
</nouvelles>                          ?>
 

Il est possible de transférer à SimpleXML un objet DOM préalablement instancié:


$xml = new domDocument ;
$xml->load('nouvelles.xml') ;
$simpleXml = simplexml_import_dom($xml);
 

La méthode xpath permet de pointer directement un nœud spécifique.


$nouvelles = simplexml_load_file('nouvelles.xml');
$xpath = '/nouvelles/nouvelle/contenu';
$nouvelle = $nouvelles->xpath($xpath) ;
foreach( $nouvelle as $news ) { echo utf8_decode($news);}
 

Voici le code php avec SimpleXML nécessaire pour parser un fichier RSS


<?xml version="1.0" encoding="UTF-8"?>     <html>
<rss version="0.91">                       <body>
 <channel>                                 <?
  <item>                                   $xml=simplexml_load_file('ex.rss');
   <title>28° cet apres midi</title>       foreach($xml->channel->item as $item)
   <link>http://www.meteo.fr/</link>       {
   <desc>meteo du jour</desc>                echo '<h1><a href='
  </item>                                      .utf8_decode($item->link).'>'
  <item>                                       .utf8_decode($item->title)
   <tilte>5m de neige en montagne</tilte>      .'</a></h1>'
   <link>http://www.skifrance.fr/</link>       .utf8_decode($item->desc);
   <desc>Hauteur des neiges</desc>         }
  </item>                                  ?>
 </channel>                                </body>
</rss>                                     </html>
 

1.8. Opérations avancées sur les chaines de caractères

Encodage du texte


$input = file_get_contents($input);
$currentEncoding = mb_detect_encoding($input, ['UTF-8'], true);
if ($currentEncoding == 'UTF-8') {
  $input = iconv($currentEncoding.'//TRANSLIT', 'ISO-8859-15//TRANSLIT', $input);
  //file_put_contents($input.'2',$sTmp);
}
 

Expression régulières

Vous pouvez tester vos expression régulières en ligne sur le site suivant :
https://regex101.com/

Pour découper le contenu d'un fichier texte DOS, UNIX, ou MAC selon les lignes, avec les expressions régulières :


$arContent = preg_split('/\r\n|\r|\n/', $input);
 

Pour remplacer dans un texte, selon un modèle d'expression, avec les expressions régulières :


$patterns = array(
  '/\!\[(.*?)\]\((.*?).(png|jpg|gif)\)/i',   // ![label_image](nom_image.jpg)
  '!\[([\s\S]*?)\]\(./(.+).(.+)\)!',         // [site](./page.html)
  '!\[([\s\S]*?)\]\(([\s\S]*?)\)!',          // [site](www.site.com)
  '#(^|\s)([a-z]+://([^\s\w/]?[\w/])*)#is',  // http://
  '/\(\((\/.*?).(png|jpg|gif)\|p(.*?)\)\)/i',// ((nom_image.jpg|palign)) page
  '/\(\((\/.*?).(png|jpg|gif)\|(.*?)\)\)/i', // ((nom_image.jpg|align))  text
  '/\(\((.*?).(png|jpg|gif)\|p(.*?)\)\)/i',  // ((nom_image.jpg|palign)) page
  '/\(\((.*?).(png|jpg|gif)\|(.*?)\)\)/i',   // ((nom_image.jpg|align))  text
  '/##(.*?[^\#])##/',                        // ##text##   gras
  '/\*\*(.*?[^\*])\*\*/',                    // **text**   gras
  '/### (.*?)/isU',                          // ### titre3
  '/@@(.*?[^\#])@@/',                        // @@text@@   strong
  '/{{(.*?[^\#])}}/',                        // {{text}}   span
  '/__(.*?[^\_])__/',                        // __text__   souligné
  '/\'\'(.*?)\'\'/',                         // ''text''   italique
  //"/    \* (.*?[\r\n|\n|\r$])/",           // liste
  //'!\[url=(.*?)\|(.*?)\](.+)\[/url\]!isU',   // [url=www.st.com|rel]site[/url]
  //'!\[url=([\s\S]*?)\](.+)\[/url\]!isU',     // [url=www.site.com]site[/url]
  '/\r\n|\n|\r/');                           // retours chariots

$replacements = array(
  '<img src=\'../docs/\\2.\\3\' alt=\'\\1\' align=\'center\' />',
  '[$1](./$2$3)',
  '<a href="$2" title="$1">$1</a>',
  '\\1<a href="\\2">\\2</a><br />',
  '<div align=\'\\3\'><img src=\''.$root_dir.'\\1.\\2\' /></div>',
  '<img src=\''.$root_dir.'\\1.\\2\' alt=\'\\1\' align=\'\\3\' />',
  '<div align=\'\\3\'><img src=\'\\1.\\2\' /></div>',
  '<img src=\'\\1.\\2\' alt=\'\\1\' align=\'\\3\' />',
  '<b>\\1</b>',
  '<b>\\1</b>',
  '<h3>\\1</h3>',
  '<strong>\\1</strong>',
  '<span>\\1</span>',
  '<u>\\1</u>',
  '<i>\\1</i>',
  //"    <li>\\1</li>",
  //'<a href="$1" rel="$2" title="$3">$3</a>',
  //'<a href="$1" title="$2" target="_blank">$2</a>',
  '');

$sTmp = preg_replace($patterns,$replacements, $sLn1);
 

1.9. base de donnees avec MySQL

Le nombre de connexions simultanées aux bases de données n'est pas illimité. Une fois qu'un scripte php est terminé, il ferme les connexions en court. Mais il vaut mieux fermer la connection manuellement, le plus tot possible.

Pour optimiser les scripts il faut respecter le schéma suivant: 1) Ouverture de la connexion 2) Execution requete 3) Fermeture connexion 4) Exploitation des resultats

Beaucoup plus de visiteurs pouront visiter le site en même temps car la connexion est temporaire. Une requete SQL normale prend environ 0.1 seconde. Donc il est possible de faire 10 requêtes sql pendant une seconde. Par exemple pour trois connexions simultanées (ovh) ont peut atteindre 30 requêtes, au delà "mysql_connect" retourne une erreur. A partir de 4 pour les sites mal programmés ou utilisant beaucoup des ressources

il est possible avec phpbb de désactiver les connections mysql persistentes : il suffit de mettre $persistency = false dans /db/mysql.php comme ceci


function sql_db($sqlserver,$sqluser,$sqlpassword,$database,$persistency=false)

/* Fonction de connection à la base*/  /* Execution d'une requette SQL */

define('HOST', 'localhost');           $req='INSERT INTO client(id,nom,prenom)'
define('USER', 'root');                    .' VALUES (\'DURAND\',\'Pascal\')';
define('PASS', 'sDfrTTghy');           mysql_query($req) or die(mysql_error());
define('BASE', 'mabasemysql');
define('LOCALHOST', 'localhost');
define('LOCALUSER', 'root');
define('LOCALPASS', '');               /* Recherche un enregistremment */

function dbconnect()  {                function extract_fields($table,$fields,
  $host = LOCALHOST;                     $condition)
  if(!@mysql_connect(HOST,USER,PASS))  {
  {                                      $req ='SELECT * FROM '.$table
    if(!@mysql_connect(LOCALHOST,              .' WHERE '.$condition;
        LOCALUSER, LOCALPASS))           $arr = explode (',', $fields, 64 );
      die('echec de connexion');         foreach($arr as $i => $name) {
  }                                        global $$name;
  else                                     $$name = '';
    $host = HOST;                        }
  if(@mysql_select_db(BASE))             if($result = @mysql_query($req)) {
    return;                                if($ligne = @mysql_fetch_array(
                                              $result))  {
  if ($host == LOCALHOST) {                  reset($arr);
    if(!@mysql_create_db (BASE))             foreach($arr as $i => $name) {
      die ('Erreur de création: '.             global $$name;
        mysql_error());                        $$name = $ligne[$name];
      @mysql_select_db(BASE);                }  
    return;                                  return $ligne;
  }                                        }  
  else die('Echec de connexion');        }
}                                      }
 

mettre les valeurs à NOT NULL si on sait qu'elle vont l'être.. pas besoin de lire le bit pour savoir avant d'aller piocher la valeur.

utiliser char à la place de varchar. Char est moins gourmand en CPU car il n'a pas besoin de calculer la taille du champ pour aller au suivant. On fait donc le choix que le coût CPU est plus important que le coût mémoire. Car avec varchar on économise un petit peu de mémoire. Si un champ d'une table est variable, toute la table l'est !! Un champ text est un champ variable !

mettre des index sur les champs utilisés fréquemment pour des recherches. C'est très bien en lecture, mais éviter de mettre des index sur des champs qui doivent être écrit souvent. C'est très lent.

éviter select * être plus précis.

utiliser limit 1 si l'on est certain d'avoir besoin que d'un enregistrement. Ainsi Mysql stop la recherche et ne va pas tenter de trier les données.. Genre le break.

utiliser des nombres plutôt que des string pour faire les jointures ! Comparer des nombres en gros 2 fois plus rapide que de comparer une chaîne de 3 caractères ! après c'est encore pire.

OPTIMIZE TABLE table défragmenter de temps en temps les tables.

1.10. base de donnees avec SQLite

SQLite est le changement majeur entre PHP5 et PHP4. SQLite est un SGBD embarqué, donc compilé par défaut. Contrairement à MYSQL, il ne nécessite pas de processus indépendant comme MYSQL Server. SQLite est très léger et très rapide, selon le site officiel de SQLite, il serait 2 à 3 fois plus rapide que Mysql, et parfois 10 fois plus rapide que Postgress et probablement aussi plus rapide que beaucoup de SGBD. Ceci est assez normal puisqu'il n'a pas d'architecture client-serveur, l'interface et le moteur étant en fait contenu dans le même package.

L'architecture de SQLite est assez simpliste puisque toute base de donnée réside dans un et un seul fichier. SQLite, contrairement aux grands SGBD, ne permet pas d'insertions concurrentes. A chaque fois qu'un processus effectue un ordre DML et DDL (INSERT,UPDATE,DELETE,CREATE…), la base est entièrement verrouillée. Des accès concurrents et presque illimités sont par contre permis en lecture seule (SELECT). Dans un environnement où un nombre réduit de processus est chargé d'écrire et tous les autres de lire, SQLite est une excellente solution (par ex pour la gestion de contenu et de menus dynamique, ce qui diminuerai le nombre de connexions à MySql). SQLite implémente la norme SQL 92.

SQLite est doté d'atouts intéressants, voici une liste non-exhaustive de ceux-ci * Possibilité de gérer des transactions * Création de vues * La gestion de contraintes d'intégrité dans un futur proche * La gestion des contraintes NOT NULL et UNIQUE * Gestion des triggers * Gestion des exceptions * Possibilité d'utiliser les fonctions PHP internes, dans les requêtes * Possibilité d'utiliser ses propres fonctions codées en PHP dans les requêtes * Possède beaucoup de fonctions internes * supporte les requêtes imbriquées

L'instanciation de l'objet prend en paramètre le nom de la db. L'objet va alors tenter de se connecter à cette db ou de la créer dans le répertoire courant.


<?php
$db = new SQLiteDatabase('db.sqlite');
$requete  = "
CREATE TABLE ADRESSES_CLIENTS ( ID_ADRESSE INTEGER PRIMARY KEY,
 ID_CLIENT INTEGER , ADRESSE VARCHAR(250) );
CREATE TABLE CLIENTS ( ID_CLIENT INTEGER, NOM_CLIENT VARCHAR(60),
 PRENOM_CLIENT VARCHAR(60) );
//création d'une vue faisant une jointure entre clients et adresses_clients
CREATE VIEW CLIENTSADR AS SELECT NOM_CLIENT,PRENOM_CLIENT,ADRESSE
 FROM CLIENTS INNER JOIN ADRESSES_CLIENTS
 ON ADRESSES_CLIENTS.ID_CLIENT=CLIENTS.ID_CLIENT;
//insertion de deux enregistrements
INSERT INTO CLIENTS VALUES ('1', 'Eyskens', 'Stéphane');
INSERT INTO ADRESSES_CLIENTS VALUES ('1', '1', 'démo adresse');
"
;
$db->query($requete);
$result=$db->query('select NOM_CLIENT FROM CLIENTS');
while($result->valid()){ //On parcours le recordset
 $row=$result->current();
 echo $row['NOM_CLIENT'];
 $result->next();
}
unset($db);
?>
 

Le fait d'écrire dans la base hors d'une transaction est lent car pour écrire dans une base SQLite ce qui se passe : écritrure dans le journal , vérification des index attente des autres utilisateur avant écriture dans le fichier terminal (regardez quand vous faites des écritures il y a un fichier nomBase .jnl qui se crée qui contient ce que vous écrivez et qui sera remis dans le fichier)

du coup si on fait une transaction l'écriture est faite en une seule fois, car juste un bloc ou x blocs fichiers sont écris et pour avoir fait des tests : 10 000 enreg ecrits hors transaction = 3 a 5 minutes 10 000 enreg ecrits dans une transaction = 2 a 3 secondes !!!

Donc il faut déclencher une transaction avant d'écrire et la fermer une fois écrite. Une base SQLite est une base de données relationnelle et comme dans toutes base l'éciture dans une transaction permet de verifier, de gérer au mieux les lock et surtout de revenir à une base avant écriture.


$liste_requetes=array();
array_push($liste_requetes,$requete);

if (count($liste_requetes) > 0)
{
  $db = new SQLiteDatabase('bourse.sqlite');
  $db->query('BEGIN TRANSACTION');
  for ($i=0; $i< count($liste_requetes); $i++)
    $db->query($liste_requetes[$i]);
  $db->query('END TRANSACTION');
  unset($db);
}
 

Il faut privilégier les écritures en bloc, ainsi que les lectures en bloc quitte à utiliser de gros tampons mémoires triés. Supprimer les doublons en bloc;

UPDATE table SET Value= WHERE id IN ('','','',) INSERT INTO table SELECT * FROM table2 DELETE FROM table WHERE rowid IN (SELECT rowid FROM $table t2 GROUP BY Value HAVING count(*) > 1)";

Créer des bases temporaires de données, les détruire et les créer via le système de fichier, dossier par dossier (changer de dossier prend beaucoup de temps). Partitionner la base, stocker les données utiles pour minimiser les appels, en base ou en local. Voici une alternative à la commande copy qui est trop lente:


stream_copy('base_vide_ref.sqlite','base.sqlite');
function stream_copy($src, $dest)  {
  $fsrc = fopen($src,'r');
  $fdest = fopen($dest,'w+');
  $len = 0;
  while (!feof($fsrc)) $len += fwrite($fdest,fread($fsrc,8192));
  fclose($fsrc);
  fclose($fdest);
  return $len;
}
 

Il est possible d'attacher plusieurs bases entre elles, ça peut être très utile. Attention à attacher uniquement de petites base, car cela recopie la base principale dans la base attachée et augmente sa taille. A éviter au maximun.


$myroot = $_SERVER["DOCUMENT_ROOT"];
$db->query("ATTACH DATABASE '".$myroot.'/rep/base.sqlite'."' As 'Y'");
$db->query('INSERT INTO Y.table SELECT * FROM table');
$db->query("DETACH DATABASE 'Y'");
 

SQLite n'implémente qu'un seul type qui est "INTEGER PRIMARY KEY". Tous les autres types étant des strings. SQLiteManager permet de gérer les bases SQLite.

L'utilisation d'une fonction personnelle, se fait en l'enregistrant dans SQLite. * createFunction(nom_fonction,nom_SQLite,nb_parametres) La syntaxe d'utilisation d'une fonction php dans une requête SQLite est: * php('nom de la fonction',paramètre)


$db = new SQLiteDatabase('db.sqlite');      function personne($chaine){
$db->createFunction('transforme_chaine',     if(empty($chaine)){return NULL;}
  'transforme_chaine',1);```             $ch=NULL;
$result=$db->query(
  'select personne(NOM_CLIENT) as NOM,'      for($i=0;$i<strlen($chaine);$i++){
 .'personne(PRENOM_CLIENT) as PRENOM '        if($i==0)
 .'FROM CLIENTS');                              $ch.=strtoupper($chaine[$i]);
while($result->valid()){                      else $ch.=strtolower($chaine[$i]);
 $row=$result->current();                    }
 echo 'Nom:'.$row['NOM']                     return $ch;
    .'Prénom:'.$row['PRENOM'];              }
 $result->next();
}
unset($db);

$db = new SQLiteDatabase('db.sqlite');
$result=$db->query("select php('strtoupper',NOM_CLIENT) as NOM,"
  ."php('strtolower',PRENOM_CLIENT) as PRENOM FROM CLIENTS");
unset($db);
 

Voici un exemple du mode procédural, qui est surtout utile lors des migrations.


$db = sqlite_open('test.sqlite');
$result=sqlite_query($db,'SELECT COL1 FROM MODE_PROCEDURAL');
while($row=sqlite_fetch_object($result)){
 echo $row->COL1;
}
unset($db);
 

SQLite est utilisé par Firefox. Il s'agit des fichiers .sqlite contenus dans le profil Firefox (répertoire utilisateur). L'inconvénient est que ces bases SQLite grossissent. Pour les optimiser voici un batch pour Windows: @FOR %%G IN (*.sqlite) DO ( sqlite3 %%G "VACUUM" )
http://www.sqlite.org/sqlite-3_5_9.zip

La version 3 apporte de meilleures performances ainsi que son lot utile comme :

  • Auto increment (clé primaires à base d'entiers générés automatiquement)
  • Stockage plus efficace (SQLite2 stocke tous les types sous forme de chaine de caractère : entiers, chaines, BLOB... ce qui occupe de l'espace disque)
  • Support des clés étrangères

1.11. Optimisations


http://www.vulgarisation-informatique.com/optimiser-php.php

préférer foreach($tb as $i=>$v) 40% plus rapide que while(list($i,$v)=each($tb)) boucle For avec calcul de la taille hors de la boucle
Résultat : 20000 temps d'exécution : 0.017132 boucle For avec calcul de la taille dans la boucle
Résultat : 20000 temps d'exécution : 0.022836 boucle While avec instruction each
Résultat : 20000 temps d'exécution : 0.035938 boucle Foreach
Résultat : 20000 temps d'exécution : 0.020736 boucle While classique, calcul de la longueur hors boucle
Résultat : 20000 temps d'exécution : 0.016767

préférer ++$i qui est 10% plus rapide que $i++

Les doubles quotes pénalisent les performances, car même s’il n’y a pas de variable à l’intérieur de la chaîne, PHP va tout de même analyser son contenu et c’est ce processus qui pénalise les performances. Pour les chaînes avec des simples quotes, PHP affiche directement le contenu de celle-ci. Nous constatons la même chose avec printf. (6.48s / 7.62s) préférer echo 'toto',fct() à echo 'toto'.fct() ; légèrement plus rapide.

Mettre en cache les variables dans un tableau. Sur une boucle de 10 millions d'itérations on gagne 15% de temps CPU. $tableau['variable'] oblige php à rechercher la valeur dans le tableau et cette recherche bouffe du temps. Mais c'est tout de même peu.

compression ob_gzhandler ... gain de 33% de donnée à transferrer.


<?php
ob_start('ob_gzhandler');
code php
ob_end_flush();
?>
 

éviter in_array(), à remplacer par un isset() sur les clés d'un tableau. Pour mettre les valeurs d'un tableau dans des clés utiliser array_ fill_ keys. Les clés d'un tableau sont des tables de hachage donc très rapide.

Optimiser l'exécution du code :

  • supprimer les include_once et require_once de votre code
  • déclarer vos méthodes en static quand vous le pouvez
  • utiliser des chemins absolus lors de vos inclusions
  • éviter les expressions régulières
  • bannissez l’utilisation de @ (masquer les erreurs)
  • préférer ' à " (echo 'Je suis une chaine' . PHP_EOL;)
  • utilisez echo() plutôt que print()
  • traquer et corriger les erreurs PHP (notice, deprecated, warning, etc.)
  • n’utilisez pas de fonction dans des boucles for
  • évitez les boucles imbriquées
  • évitez les méthodes magiques _get(), __set(), __call(), __autoload()
  • évitez les accesseurs inutiles, $rover->name = ''; et non $rover->getName();
  • tenez votre version de PHP à jour
  • utilisez des gestionnaires de cache : memcached, APC, etc.
  • évitez d’utiliser des variables inutiles
  • décharger la mémoire en utilisant unset()
  • utilisez strtr() plutôt que str_replace() ou preg_replace()
  • utilisez le switch/case() plutôt que des if() multiples
  • utilisez les ‘ lors des accès tableaux
  • évitez les variables globales
  • préférer les pages HTML statiques aux scripts PHP
  • vérifiez si les variables sont disponibles via isset() (si besoin)
  • remplacez strlen($var) < 2 par $var{2}
  • ++$i et plus rapide que $i++
  • n’abusez pas de la POO, le procédural est plus rapide
  • utilisez le design pattern singleton
  • utilisez du cache

1.12. Compression Web


http://www.alsacreations.com/article/lire/914-compression-pages-html-css-gzip-deflate.html

De nos jours, l'accent est souvent mis sur la performance des sites et les économies de bande passante notamment sur mobile. Les temps d'accès et de téléchargement se mesurent (très précisément avec de nombreux outils) en millisecondes.

  • Le serveur compresse les données (code HTML, CSS, JavaScript...)
  • Les fichiers transitent par le réseau via HTTP
  • Le navigateur décompresse à la volée les données avant de les interpréter

Ce qui représentait une charge supplémentaire pour les serveurs web à l'époque où leur puissance était moindre, peut désormais devenir négligeable en regard des améliorations apportées, notamment pour les navigateurs mobiles. Si la compression impose une charge trop importante à votre serveur, il est possible de pré-compresser les contenus, les placer en cache et les délivrer directement.

Ces techniques qui sont prévues depuis HTTP/1.1 (1999) peuvent tout à fait être mises en œuvre pour les documents HTML mais aussi CSS, XML ou JavaScript. Il est inutile de s'en servir pour les fichiers binaires (images, vidéos, PDF...). Elles ne vous dispensent pas de réduire initialement la taille des fichiers HTML ou CSS . On peut considérer que la totalité des navigateurs

supportent la décompression des pages avec HTTP/1.1 :

  • Microsoft Internet Explorer depuis 4.0*
  • Opera depuis 5.12
  • Firefox toutes versions
  • Google Chrome toutes versions
  • Safari toutes versions
  • Netscape depuis 4.06
  • Tous les navigateurs mobiles

De plus, il incombe aux navigateurs d'envoyer un en-tête HTTP indiquant les types de pages compressées supportées . Si cet en-tête ne figure pas dans ceux reçus par le serveur, il lui suffit de ne pas activer la compression.

GET / HTTP/1.1 Host: www.alsacreations.com Accept-Encoding: gzip User-Agent: Firefox/3.6

Le serveur répond alors de la même manière, grâce à Content-Encoding, et en faisant suivre par le contenu compressé de la page.

HTTP/1.1 200 OK Server: Apache Content-Type: text/html Content-Encoding: gzip Content-Length: 13337

...

Deux formats coexistent :

  • Deflate, algorithme qui couple LZ77 et le codage de Huffman (zlib)
  • Gzip, évolution de Deflate, plus performant, mieux supporté, plus répandu

Mise en place au niveau des serveurs web

Apache est équipé de modules de compression :

  • dans les anciennes versions 1.3 : mod_gzip ou mod_deflate
  • depuis la version 2.0 : mod_deflate qui utilise zlib et remplace mod_gzip

Microsoft IIS supporte la compression depuis la v4, mais celle-ci est victime de bugs. Dans la v5, les efforts de Microsoft n'ont pas porté leurs fruits puisque celle-ci est toujours instable. C'est enfin dans la version 6 que la compression HTTP a été finalisée. Cependant elle nécessite quelques manipulations; voir doc Microsoft : Using HTTP Compression for Faster Downloads (IIS 6.0) et tutoriel en français pour activer la compression GZip dans IIS6.

Les autres serveurs restent marginaux. Lighttpd est équipé du module bien nommé mod_compress.

Solution alternative en PHP

La fonction ob_gzhandler et l'ensemble des fonctions de type ob_* disponibles depuis PHP4 permettent la gestion du tampon de sortie, c'est à dire des données qui seront envoyées au navigateur. Il est alors possible de générer le contenu complet de la page et de le compresser avec Gzip avant envoi. On active le tampon en début de script avec ob_start, et on le vide à la fin avec ob_end_flush.

La fonction ob_gzhandler a le mérite de vérifier les types de compressions supportés par le navigateur (gzip, deflate ou aucun) avant de retourner le contenu du tampon de manière appropriée. Si le navigateur ne supporte pas les pages compressées, cette fonction retournera false.

La plupart des hébergeur intégrent la compression; pour vérifier aller sur :
http://www.whatsmyip.org/http-compression-test

1.13. Caches code PHP

Comme nous venons de le voir à l’instant, le PHP est un langage compilé qui compile un script avant chacune de ses exécutions. Voici beaucoup de temps perdu, sachant que la plupart des scripts PHP ne changent pas entre deux exécutions. On pourrait alors imaginer de faire une compilation une fois, et de la garder en mémoire.C’est exactement ce que font les caches code PHP dont voici une liste non exhaustive (dans le désordre) :

  • APC ou Alternative PHP Cache qui devrait être intégré par défaut dans PHP 6 ;
  • eAccelerator qui est dérivé de Turck MMcache qui n’est plus maintenu ;
  • Zend Platform qui est un ensemble liant compilateur spécifique, encodeur de code source et outils additionnels ;
  • The ionCube PHP Accelerator est un cache code, des outils permettent aussi d’ encoder les scripts PHP.

Le principe de fonctionnement d’un cache code PHP est le suivant :

le serveur web voit d’après le type MIME que c’est au PHP de jouer et lui passe la main (via le module intégré au serveur, ou bien via une interface de type FastCGI, CGI, etc.) ; le PHP vérifie s’il a déjà une version compilée du script PHP dans son cache :

  • si dans le cache et cache à jour, saute à l’étape 4 ;
  • sinon, charge le script depuis le système de fichiers ; le PHP compile le script chargé ; le PHP exécute le script compilé ; le PHP rend la main.

Gain de performances

Grâce au cache code, le PHP peut faire l’économie de l’étape de compilation du script entre deux exécutions d’un même script. Selon la taille du script et la machine sur laquelle il tourne, cela fait généralement économiser entre 50 et 250 ms de temps d’exécution de script. L’expérience montre que cela permet de doubler la vitesse d’excution d’un script PHP.

En outre, les caches code PHP mettent à disposition des scripts des fonctions leur permettant d’utiliser la mémoire cache persistante entre deux exécutions de script pour y stocker des données. Un script peut donc y stocker des valeurs qui changent peu entre deux exécutions, mais qui sont longues à calculer. Par exemple, dans le cas d’un forum, la quantité de messages publiés change rarement et n’a pas besoin d’être mise à jour en temps réel. Or, cela implique parfois des calculs lourds au niveau de la base de données. Stocker cette valeur dans une mémoire persistante pour la réutiliser aux prochains affichages permet ainsi de faire gagner un temps précieux. L’expérience montre que l’on peut là encore doubler les performances d’un script en exploitant la mémoire persistante du cache code PHP pour y stocker des données.


http://unearaigneeauplafond.fr/php-langage-interprete-compile/

1.14. Utilisation de PHP avec Ajax

AJAX (Asynchronous JavaScript and XML) permet de mettre à jour certaines parties d'une page sur base d'évènements déclenchés par l'utilisateur sans recharger la page. L'objet XMLHttpRequest permet d'échanger des informations sous différents formats (dont XML, HTML ou texte).

Fichier ajax.js


function ajaxXmlHttp() {
  var xmlhttp = false;
  /* Compilation conditionnelle d'IE */
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
        xmlhttp = false;
      }
    }
  @else
    xmlhttp = false;
    @end @*/


  /* on essaie de créer l'objet si ce n'est pas déjà fait */
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try{
      xmlhttp = new XMLHttpRequest();
    } catch (e) {
      xmlhttp = false;
    }
  }
  return xmlhttp ;
}
 

Pour déclarer ce qui se produit lorsque la réponse est reçue: httpRequest.onreadystatechange = function() { // traitement de la réponse };

Pour lancer effectivement la requête serveur, il faut appeler les méthodes: httpRequest.open('GET', 'http://www.example.org/some.file', true); httpRequest.send();

Pour des raisons de sécurité, il n'est pas possible d'appeler des pages sur un autre domaine. Les données doivent être sous la forme d'une chaîne de requête : nom=valeur&autrenom=autrevaleur&ainsi=desuite

Pour envoyer des données avec la méthode POST, il faut changer le type MIME: httpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded')

Quand la réponse est reçu, la fonction déclarée doit vérifier l'état de la requête. Si cet état a une valeur de 4, cela signifie que la réponse du serveur a été reçue dans son intégralité et qu'elle peut maintenant être traitée. La 2nd vérification concerne le code d'état de la réponse HTTP du serveur (200=OK).

Pour accéder à ces données la fonction dispose de deux méthodes: * httpRequest.responseText — chaîne de texte * httpRequest.responseXML — objet XMLDocument qui se traite avec des fonctions DOM de JavaScript.

Fichier combos.htm


<html>
  <head>
    <title>Ville par cp </title>
    <script type="text/javascript" src="ajax.js"></script>
    <script type="text/javascript">
    <!--
   /* Appel Ajax */

   function maj(index,param)
   {
     //recuperation de l'objet
     var x = new Array("region","departement","arrondissement", "");
     var nom;
     var xmlhttp=ajaxXmlHttp();

     nom = x[index];
     nomsuiv = x[index+1];

     xmlhttp.open("GET","combos.php?nom="+escape(nom)+"&param="+escape(param),
       true);
     //traitement le la reponse du serveur
     xmlhttp.onreadystatechange=function(){
     try {
       if((xmlhttp.readyState==4)&&(xmlhttp.status==200))
       { // reponse terminée et statut OK
         var elt= document.getElementById(nom);
         var obj=eval("("+xmlhttp.responseText+")");
         index = index+1;
         if (nomsuiv == "")
           var sortie="<select>";
         else
           var sortie="<select ONCHANGE='maj(" + index + ",
             this.options[this.selectedIndex].value);'>";
         for(var i=0; i< obj.resultats.length;i++) {
           sortie=sortie+obj.resultats[i];
         }
         sortie = sortie + "</select>";
         elt.innerHTML=sortie;
         document.getElementById("wait").style.visibility="hidden";
       }
     }
     catch( e ) {
       alert("Une exception s'est produite : " + e.description);
     }
     }
     document.getElementById("wait").style.visibility="visible";
     xmlhttp.send(null);
   }
   -->
    </script>
  </head>
  <body>
    <img  id="wait" src="wait.gif" style="visibility:hidden"/>
    <dl>
      <dt><label for="">Region</label>
      <dd id='region'></dd>
      <dt><label for="">Departement</label>
      <dd id="departement"></dd>
      <dt><label for="">Arrondissement</label>
      <dd id="arrondissement"></dd>
    </dl>
    <script>maj(0, '');</script>
  </body>
</html>
 

Si vous envoyez une requête vers un bout de code dynamique qui renvoie du XML, plutôt que vers un fichier XML statique, vous devez définir certains en-têtes de réponse pour que votre page fonctionne; Content-Type: application/xml '' voir la fiche HTML ''

Fichier combos.php


<?php
if(isset($_GET['nom'])) $nom=$_GET['nom']; else $nom='';
if(isset($_GET['param'])) $param=$_GET['param']; else $param='';
$done=0;

mysql_connect("127.0.0.1",'root','');
mysql_select_db('geocity');

echo '{ "resultats" : [';

if(($nom == 'region') && ($param == ''))
{
  $result = mysql_query("SELECT DISTINCT ncc, id FROM regions ");
  if($result) {
    $sep='';
      while($row=mysql_fetch_array($result))
      {
        echo "$sep\""."<OPTION VALUE=".$row['id'].">"
          .str_replace('"','\"',$row['ncc']).'</OPTION>"';
        $sep=',';
      }
      mysql_free_result($result);
      $done = 1;
  }
}

if(($nom == 'departement') && ($param <> ''))
{
  $result = mysql_query("SELECT DISTINCT ncc, id "
                       ."FROM departements WHERE id_regions = ".$param);
  if($result) {
    $sep='';
    while($row=mysql_fetch_array($result))
    {
      echo"$sep\""."<OPTION VALUE=".$row['id'].">"
        .str_replace('"','\"',$row['ncc']).'</OPTION>"';
      $sep=',';
    }
    mysql_free_result($result);
    $done = 1;
  }
}

if(($nom == 'arrondissement') && ($param <> ''))
{
  $result = mysql_query("SELECT DISTINCT ncc, id FROM arrondissements "
                       ."WHERE id_departements = ".$param);
  if($result) {
    $sep='';
    while($row=mysql_fetch_array($result))
    {
      echo"$sep\""."<OPTION VALUE=".$row['id'].">"
        .str_replace('"','\"',$row['ncc']).'</OPTION>"';
      $sep=',';
    }
    mysql_free_result($result);
    $done = 1;
  }
}

if ($done == 0) echo "null";

echo "] }";
?>
 

CHAPITRE 2 - Architecture web

2.1. Nom de domaine et Hébergement

Le meilleur moyen pour avoir un domaine gratuit, professionnel et sans pubs, est d'utiliser un hébergeur qui sois gratuit et sans pub qui ait un serveur DNS, car grace aux DNS l'hébergeur pourra rediriger votre url.

La meilleur redirection DNS gratuite qui existe est celle proposée par: "dot.tk" Par exemple on va réserver un nom de domain en . tk (ex:www.domaine.tk) aux serveurs DNS de notre hébergeur, dans cet exemple l'hébergeur site web sera: "freewebhostingarea.com"qui utilise les serveur DNS ns1.eu5.org et ns2.eu5.org

1er étape : réserver le nom de domaine. Inscrivez vous sur ce site : dot.tk Après vous avoir inscrit gratuitement, réservez votre nom de domaine en cliquant sur "Ajoutez un nouveau domaine GRATUIT". choisissez l'option "Utiliser DNS pour ce domaine" . dans la 1ere ligne vous écrirez : ns1.eu5.org et dans la 2em : ns2.eu5.org Attention ce nom de domaine est gratuit qu'un an, après il devient payant, et le service est interompu sans préavis. Il vaut mieux achetter son nom de domaine. Par exemple sur ovh, il est possible de paramétrer soi même le DNS facilement: depuis les options avancées du DNS, supprimer toutes les entrées, et mettre celles de freewebhosting. Autrement si vous demandez au support ovh, il vous factureront 6€ pour faire ces 3 clics à votre place.

2em étape : s'incrire sur l'hébergeur "freewebhostingarea.com" "freewebhostingarea" est un hébergeur gratuit et sans pubs, 15000 mb d'espace, php5, MySQL 5 ... et le plus importent est qu'il utilise le DNS ! Sous "Free domain hosting (for already registered domain)" écrivez le domaine que vous avez réserver sur "dot.tk" . Terminez l'inscription

En autre hébergeurs gratuits et sans pub on a http://www.000webhost.com/

2.1. Spécifier l'interpréteur de scripts

Comment executer les fichiers ".php" par l'interpretteur des fichiers ".php5"

Il faut créer un fichier .htaccess à la racine de votre site avec cette ligne : AddHandler application/x-httpd-php5 .php

Il faut que ce handler soit déjà déclaré dans le httpd.conf, du serveur apache.

AddHandler application/x-httpd-php5 .php5 Action application/x-httpd-php5 /usr/bin/php

application/x-httpd-php5 doivent être identiques. Si ce n'est pas le cas, alors il faut soit modifier le httpd.conf, soit le .htaccess .


http://www.prestashop.com/forums/viewthread/446/


     hebergeur      forcer en php5/register_globals
     _________________________________________________________
     ovh            SetEnv PHP_VER 5
                    SetEnv REGISTER_GLOBALS 0
     1&1            AddType x-mapp-php5 .php
     free           php 1
     Lycos          AddHandler application/x-httpd-php5 .php
     _________________________________________________________

2.2. Protection d'un répertoire par .htaccess

.htaccess


AuthName ":: ACCES LIMITE ::"
AuthType Basic
AuthUserFile /var/www/site/private/password.txt
Require valid-user

/private/password.txt


dixi:KQU1hPy881rFM
dixi:UbUDU1UyvAV7s
client:$1$ZW4zj1iB$aJ3ORgNm3OrnpXGgHRtZW.

/private/.htaccess


Deny from all

2.3. urlrewriting

L'hébergeur doit permettre l'url rewriting. Pour le savoir executer un phpinfo; le module mod_rewrite doit être présent dans apache2handler/Loaded Modules . le fichier de configuration d'Apache (httpd.conf) doit contenir ces lignes :

LoadModule rewrite_module libexec/mod_rewrite.so AddModule mod_rewrite.c

Pour distinguer les diférents paramètres, vous devez choisir un séparateur. caractère conseillés: - , . / | caractères déconseillés: _ # & @ ? $ + accents

article.php?id=12&rubrique=5 -> article-12-5.html article.php?id=12&page=2&rubrique=5 -> article-12-2-5.html

mapage.php?var1=valeur1&var2=valeur2&...&varN=valeurN -> mapage-var1-valeur1-var2-valeur2-....-varN-valeurN.html

Le code à insérer dans le .htaccess utiles les expressions régulières :

RewriteEngine on RewriteRule (.)(-.+)-([^-]+)-([^-&])([^-]).html $1$2&$3=$4$5.html [N] RewriteRule (.)-([^-]+)-([^-])(.).html $1.php?$2=$3$4 [L] RewriteRule ^(.*).html $1.php [L]

Voici le contenu du fichier .htaccess


# Le serveur doit suivre les liens symboliques :
Options +FollowSymlinks

# Activation du module de réécriture d'URL :
RewriteEngine on

# Règles de réécriture d'URL :

# Article sans numéro de page :
RewriteRule ^article-([A-z]+)-([A-z]+)\.html$
  article.php?lng=$1&page=$2 [L]

# Article avec numéro de page :
RewriteRule ^article-([A-z]+)-([0-9]+)-([A-z]+).html$
  article.php?lng=$1&page=$2&typ=$3 [L]

voir la partie des expressions régulières [L] Indique au module qu'il doit s'arrêter si le shéma correspond sans appliquer les règles suivantes.


http://www.webrankinfo.com/dossiers/referencement-et-php/sommaire

2.4. sitemap

Avant le fichier "robots.txt" (à la racine du site), ne servait qu'à restreindre l'accés de certains répertoires aux bots (programmes d'indexation des moteurs de recherche). Maintenant, ce fichier sert aussi à demander aux bots d'aller lire le (ou les) fichier(s) sitemap présents sur le site.

robots.txt

User-agent: * Sitemap: http://www.monsite.com/sitemap.xml

sitemap.xml


<?xml version="1.0" encoding="UTF-8"?>
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url>
        <loc>http://www.monsite.com/index.php</loc>
      </url>
      ...
    </urlset>
 

2.4 Creation d'un webservice PHP

En PHP, on peut faire des webservices, que ce soit en tant que client ou en tant que serveur. Il faut avoir le module php_soap installé et activé. On commence par créer un objet SoapServer qui prend en arguments un fichier WSDL (null ici) et une liste de paramètres. Si le fichier WSDL n’est pas renseigné comme ici, il faut obligatoirement spécifier le paramètre URI ensuite.

Ensuite, on va indiquer à notre serveur, la classe qui gère les requêtes SOAP par la méthode setClass(). La méthode handle() fait le nécessaire pour gérer une requête SOAP. L’URI qui représente l’espace de nom, est différente de la Location du service qui est l’URL à interroger.


http://www.willdurand.fr/decouverte-des-webservices-en-php/


// Webservice                          // Client                            
class Donne {                          try  {                              
  function donne($i) {                   $clientSOAP = new SoapClient(null,
    return $i;                              array (                        
  }                                           'uri' => 'http://...php',    
  function hello() {                          'location' => 'http://...php',
    return "hello world";                     'trace' => 1,                
  }                                           'exceptions' => 0            
}                                         ));                              
                                         $ret = $clientSOAP->__call(        
try  {                                                   'hello', array());
  $server = new SoapServer(null,         echo $ret."<br />";                
   array('uri' => 'http://...php'));     $ret = $clientSOAP->__call(        
  $server->setClass("Donne");                       'donne', array('i'=>5));
  $server->handle();                     echo $ret;                        
}                                      }                                    
catch(Exception $e)  {                 catch(SoapFault $f)  {              
  echo "Exception: " . $e;               echo $f;                          
}                                      }                                    
 

On travaille toujours en mode non WSDL, il faut passer obligatoirement deux paramètres qui sont URI et Location. Trace et Exception sont utiles lorsqu’un problème survient.

Pour appeler une méthode, on utilise la méthode __call(). Pour passer les paramètres à une fonction, il suffit de passer un tableau associatif.

Le webService retourne une réponse au format XML, par exemple sur le site
http://www.xmethods.net/
qui présente des services web, pour le service whois: Seul le début nous intéresse. Par exemple, on voit que ce service propose deux fonctionnalités : HelloWorld et Whois.

Il faudra donc une classe PHP représentant cet objet. Ensuite on va utiliser un SoapClient en mode WSDL. Le script qui suit affiche la liste des fonctionnalités du service grâce à la fonction __getFunctions(), puis invoque successivement les deux méthodes du service.


<?php
  class Whois
  {
    private $servername;
    private $port;
    private $domain;
 
    function __construct($s, $p, $d)
    {
      $this->servername = $s;
      $this->port = $p;
      $this->domain = $d;
    }
  }
 
  try
  {
    $client = new SoapClient('http://www.ecubicle.net/whois_service.asmx?WSDL');
 
    var_dump($client->__getFunctions());
    echo '<hr /><br />';
 
    echo '<b>Invocation de HelloWorld() :</b>';
    echo '<br />';
 
    $ret = $client->__soapCall('HelloWorld', array());
   
    print_r($ret);
    echo '<br />';
    echo $ret->HelloWorldResult;
   
    echo '<br /><br />
    <b>Invocation de Whois() :</b>'
;
    echo '<br />';
    $ret = $client->__soapCall(
      'Whois', array('Whois'=>new Whois('whois.verisign-grs.com',43,'google.fr')));
   
    echo $ret->WhoisResult;
  }
  catch(Exception $e)
  {
    echo '<br /><hr />';
    echo "<b>Exception:</b> " . $e;
  }
?>
 

2.5. Serveur Apache sous Linux

/etc/php4/apache/php.ini rajouter ou decommenter la ligne extension=mysql.so Register_globals=OFF error_reporting=E_ALL

Attention aux valeurs de

  • memory_limit 16-32
  • max_execution_time 60s sinon il peut y avoir des erreurs avec certains scripts comme ipb... joomla qui nécessite une plus haute valeur à l'installation (facultatif).

/etc/apache/httpd.conf ou modules.conf /usr/local/apache2/conf/httpd.conf rajouter ou decommenter les lignes LoadModule php4_module /usr/lib/apache/1.3/libphp4.so LoadModule php5_module modules/libphp5.so LoadModule vhost_alias_module /usr/lib/apache/1.3/mod_vhost_alias.so

eventuellement rajoutter AddModule mod_php4.c

decommenter les lignes AddType application/x-httpd-php .php .php5 .php4 .php3 .phtml .phps

User et Group representent l'utilisateur et le groupe avec qui, le serveur apache se lance: mettre un utilisateur et un groupe sans privileges!

Arret et demarrage d'apache: /usr/local/apache2/bin/apachectl start ou stop

lancer mysql: mysql_install_db mysqladmin -u root password 'mdp'

Il est recommendé de créer un superutilisateur: mysql -u root -p mysql>INSERT INTO user VALUES('localhost','phil',PASSWORD('mdp'),'Y','Y','Y', ... 14 'Y'); mysql>FLUSH PRVILEGES;

>SET PASSWORD FOR root@localhost=PASSWORD('new_mdp') WHERE user='root'; >FLUSH PRIVILEGES

Dans tous les cas conserver localhost

Un utilisateur anonyme est crée. Il a accé à test et à toutes les bases commencant par test_ en localhost

pour supprimer toutes les tables de droit supprimer v>3.22.10 .frm .MYI .MYD dans le dossier des tables mysql

/var/lib/mysql>chown mysql *

mysqladmin -u root -h my_host password 'newmdp' utilisateur mysql 16 carac max www.mysql.com/doc/fr

GRANT USAGE ON . TO ravage@localhost IDENTIFIED By 'rabla' WITH GRANT OPTION;

2.6. Serveur IIS sous Windows

IIS (Internet Information Services) est un serveur web pour Windows. Il s'installe parmis les composants windows dans "ajout/Suppression des programmes" Le dossier racine du serveur est "C:\Inetpub", et le site web par défaut dans "C:\Inetpub\wwwroot". L'interpreteur de pages web actives par défaut est l'ASP.

Pour mettre en ligne un site en ASP ou en HTML:

  • placer le site dans le dossier Inetpub
  • Aller dans Outils d'Administration, ouvrir le panneau de gestion des services IIS6 (ou executer "inetmgr").
  • Faire un clic droit sur Site Web Par Defaut, Nouveau, "Répertoire virtuel...".
  • Choisir un Alias puis sélectionner le dossier. Le dossier sera accèssible depuis le net à l'adresse http://localhost/alias

Arrêt et redémarrage du serveur: Exécuter "services.msc", cliquer sur «Administration IIS», puis cliquer à gauche sur l’action souhaitée pour ce service : « Arrêter », « Mettre en pause », « Redémarrer »

2.7. Serveur Apache sous Windows

Installation

Installer mySql sans changer le mot de passe. "http://dev.mysql.com/downloads/". MySql est un service qui peut être arrété par "services.msc". Télécharger depuis "http://www.php.net/downloads.php" le pack PHP pour Windows. Décompressez l'archive zip du pack, ex: "C:\Inetpub\php". Faire de même pour le module phpMyAdmin ex: "C:\Inetpub\phpmyadmin". Et modifier ou créez les fichiers de configuration:

C:\Inetpub\php\php.ini-dist C:\Inetpub\phpmyadmin\config.inc.php


; Directory in which the load...   <?php
extension_dir="C:\Inetpub\PHP\ext" /* Servers configuration */
                                   $i = 0;
; **You CAN safely ...
cgi.force_redirect = 0             /* Server (config:mumuri) [1] */
                                   $i++;
extension=php_mysql.dll    
extension=php_mysqli.dll           $cfg['Servers'][$i]['host'] = 'localhost';
extension=php_pdo.dll              $cfg['Servers'][$i]['extension'] = 'mysql';
extension=php_pdo_sqlite.dll       $cfg['Servers'][$i]['connect_type'] = 'tcp';
extension=php_sqlite.dll           $cfg['Servers'][$i]['compress'] = false;
                                   $cfg['Servers'][$i]['auth_type'] = 'config';
[mail function]                    $cfg['Servers'][$i]['user'] = 'root';
; For Win32 only.                  $cfg['Servers'][$i]['password'] = '';
SMTP = srvlionet                   //$cfg['Servers'][$i]['only_db']="<nonbase>";
smtp_port = 25                     /* End of servers configuration */
                                   ?>
 

Enregistrez le fichier "php.ini-dist" dans le dossier Windows, sous"php.ini".

modification et création des paramètres utilisateurs de MySql:


shell> mysql -u root
SET PASSWORD FOR ''@'localhost' = PASSWORD('nouveau_mot');
SET PASSWORD FOR ''@'%' = PASSWORD('nouveau_mot');

CREATE USER 'adagio'@'localhost' IDENTIFIED BY 'AdaVers';
GRANT SELECT,INSERT,UPDATE,DELETE ON adagio.* TO 'adagio'@'localhost';

CREATE USER 'interne'@'localhost' IDENTIFIED BY 'epsa';
GRANT SELECT,INSERT,UPDATE,DELETE ON interne.* TO 'interne'@'localhost';
 

configuration

Nous allons maintenant ajouter la prise en charge des fichiers PHP par le module CGI PHP. Aller dans Outils d'Administration et ouvrir le panneau de gestion des services IIS6 (ou executer "inetmgr"). Faire un clic droit sur "Sites Web" puis "Propriétés". Aller dans "Répertoire de base" et enfin "Configuration" pour ajouter une extension. Cliquez sur "Ajouter" et complétez comme suit: "C:\Inetpub\php\php5isapi.dll" Choisissez bien dans la liste le module CGI

Pour finir avec cette partie, vous pouvez également spécifier comme page par défaut le fichier index.php, onglet "Document" puis "Ajouter" : index.php

Il reste à ajouter l'extension au service IIS pour autoriser son exécution. Dans le "Gestionnaire des services Internet" vous trouverez un intitulé "Extension du service Web". Cliquez dessus pour avoir le listing des composants installés et autorisés. Cliquez sur le lien avec la flèche "Ajouter une nouvelle extension..." puis complétez avec un nom de composant et en spécifiant comme exécutable notre module CGI comme précédemment : Fichiers PHP / C:\Inetpub\php\php5isapi.dll Il est maintenant possible d'autoriser ou interdire l'exécution de pages PHP.

CHAPITRE 3 - Framework Symfony (SF)

3.1. Introduction

Les avantage du Framework

L'avantage premier est le gain en productivité. Un framework va vous aider à réaliser un « bon code » de par sa propre architecture, et à bien organiser votre code. Et un code bien organisé est un code facilement maintenable et évolutif! De plus, un framework offre des briques prêtes à être utilisées, ce qui vous permet d'utiliser des briques puissantes et éprouvées. En effet, ces briques sont développées par des équipes de développeurs chevronnés, elles sont donc très flexibles et très robustes. Vous économisez ainsi des heures de développement !

Ensuite, un framework améliore la façon dont vous travaillez. En effet, dans le cas d'un site Internet, vous travaillez souvent avec d'autres développeurs PHP et un designer. Un framework vous aide doublement dans ce travail en équipe. D'une part, un framework utilise presque toujours l'architecture MVC (façon d'organiser son code qui sépare le code PHP du code HTML). Ainsi, votre designer peut travailler sur des fichiers différents des vôtres. D'autre part, un framework a une structure et des conventions de code connues. Ainsi, vous pouvez facilement recruter un autre développeur : s'il connaît déjà le framework en question, il s'intégrera très rapidement au projet.

Enfin, le dernier avantage est la communauté soutenant chaque framework. C'est elle qui fournit les tutoriaux ou les cours (comme celui que vous lisez !), de l'aide sur les forums, et bien sûr les mises à jour du framework.

Les inconvéniants

Pour maîtriser un framework, il faut un temps d'apprentissage non négligeable. Chaque brique qui compose un framework a sa complexité propre qu'il vous faudra appréhender.

Pour les frameworks les plus récents, tels que Symfony, il faut également être au courant des dernières nouveautés de PHP. (POO et namespaces Victor Thuillier) De plus, connaître les bonnes pratiques telles que l'architecture MVC.

Symfony est un framework PHP, ainsi que Zend Framework, CodeIgniter, CakePHP,... Le choix d'un framework doit être adapté au projet. Et Symfony est l'un des plus flexibles et des plus puissants.

__ Symfony 4__

SF contient tout ce dont vous avez besoin pour mener à bien votre projet :

  • un moteur de gabarit ;
  • un ORM (Object-Relational Mapping ou mapping objet-relationnel);
  • un client de test ;

En réalisant un site web complet, vous apprendrez à :

  • intégrer des vues avec le moteur de gabarits Twig,
  • manipuler une base de données à l'aide de l'ORM Doctrine et,
  • créer des formulaires parfaitement intégrés et validés.
  • sécuriser le site web et créer un espace d'administration,
  • mesurer la qualité de votre code et le respect des standards de la communauté.
  • mettre votre application en production sur un serveur ou dans le Cloud : avec Platform.sh, un des acteurs principaux du marché.

Réf: Symfony2
https://openclassrooms.com/courses/developpez-votre-site-web-avec-le-framework-symfony2/symfony2-un-framework-php
Réf: Symfony4
https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-4

Réf: ORM
https://www.base-de-donnees.com/orm/

3.2. Développez votre première application Symfony

Requêtes et réponses en Symfony

Le framework Symfony, et notamment son composant HttpFoundation, apporte une couche d'abstraction pour la requête et la réponse.

La classe Request permet de centraliser l'accès à toutes les super variables de PHP en une seule classe utilitaire.


<?php
use Symfony\Component\HttpFoundation\Request;

// Récupération des valeurs accessibles dans les super variables
$request = Request::createFromGlobals();

// Récupérer l'url
$request->getPathInfo();

// récupérer des attributs en GET ou POST
$request->query->get('name');
$request->request->get('name', 'nom par défaut');

$request->getMethod();    // e.g. GET, POST, PUT, DELETE ou HEAD
 

La classe Response permet de retourner une réponse à l'utilisateur valide en termes de langage HTTP.


<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();
$name = $request->get('name');
$response = new Response();

$response->setContent(
    '<html><body>Hello'
    . $name
    .'</body></html>'
);
$response->setStatusCode(Response::HTTP_OK);
$response->headers->set('Content-Type', 'text/html');

// Retourne une réponse HTTP valide
$response->send();
 

Liez une URL à une action

Le composant HttpKernel permet de récupérer la requête de l'utilisateur et de renvoyer une réponse.

Un contrôleur Symfony peut être une simple fonction d'une classe PHP et il est possible de configurer le routing à l'aide d'annotations PHP même si d'autres formats de déclaration sont possibles. Le framework Symfony fournit aussi un contrôleur frontal en charge de recevoir toutes les requêtes de l'utilisateur et de trouver la bonne action (fonction) du contrôleur à exécuter.

Réalisez une application configurable et extensible

Vous allez découvrir le composant Dependency Injection de Symfony, et notamment comment construire nos objets et les récupérer à l'aide du container de services

Le composant Dependency Injection est fourni avec un container de services.

Un service est un objet qui est utilisé dans votre projet, et auquel vous avez besoin d'accéder. Ce service est enregistré dans un container, ainsi que les étapes nécessaires à sa construction : dépendances, méthodes et arguments à appeler. Exemple de création d'un service:


<?php
// src/Services/ComplexObject.php
namespace App\Services;
class ComplexObject
{
    private $foo;
    private $other;
    public function __construct(Foo $foo, Other $other)
    {
        $this->foo = $foo;
        $this->other = $other;
    }
    public function doSomething() { } // ...
}
 

Pour vérifier qu'un service est disponible, allez dans la console de Symfony et taper la commande debug:container App\Services\ComplexObject


  Information for Service "App\Services\ComplexObject"
  ====================================================
  
   ---------------- ----------------------------
    Option           Value
   ---------------- ----------------------------
    Service ID       App\Services\ComplexObject
    Class            App\Services\ComplexObject
    Tags             -
    Public           no
    Synthetic        no
    Lazy             no
    Shared           yes
    Abstract         no
    Autowired        yes
    Autoconfigured   yes
   ---------------- ----------------------------

Le service est immédiatement disponible dans le container ! on peut l'injecter sans crainte dans nos classes !


<?php
// src/Controller/HelloController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class HelloController extends AbstractController  {
    /** Page d'accueil
     * @Route("/", name="accueil")
     */

    public function home(ComplexObject $complexObject)
    {
        // $complexObject->doSomething();
    }
}
 

L'autowiring de services (autochargement des classes) est activée par défaut dans tout projet Symfony 4. Dans le fichier services.yaml, vous retrouverez la déclaration suivante :

config/services.yaml


services:
  _defaults:
    # Ajoute automatiquement les dépendances à vos objets
    autowire: true

Dans votre projet, le framework va parcourir l'ensemble des ressources (ou chemins) définies :

Réf: Symfony4
https://openclassrooms.com/fr/courses/5489656-construisez-un-site-web-a-l-aide-du-framework-symfony-4

111 millisecondes