Frameworks Web en PHP

Prérequis

Quelques technologies nécessaires :


Hypertext Transfer Protocol (HTTP)

HTTP est un protocole applicatif pour les systèmes distribués. Il est générique et sans état.

Structure d’un message générique

 generic-message = start-line
                 *(message-header CRLF)
                 CRLF
                 [ message-body ]
 start-line      = Request-Line | Status-Line

En-têtes et entités HTTP

 message-header = field-name : [ field-value ]
 field-name     = token
 field-value    = *( field-content | LWS )
 field-content  = <the OCTETs making up the field-value
                  and consisting of either *TEXT or combinations
                  of token, separators, and quoted-string>

Exemple d’en-têtes de requête

Host: tools.ietf.org
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: UTF-8,*;q=0.5
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17

Requêtes HTTP

Les requêtes sont envoyées du client au serveur.

 Request = Request-Line
           *(( general-header
             | request-header
             | entity-header ) CRLF)
           CRLF
           [ message-body ]

Ligne de requête

 Request-Line = Method SP Request-URI SP HTTP-Version CRLF

Exemple

 GET /project/65142b1a71134a60df97ad24 HTTP/2

Méthodes HTTP


Réponses HTTP

 Response    = Status-Line
               *(( general-header
                | response-header
                | entity-header ) CRLF)
               CRLF
               [ message-body ]

Exemple

HTTP/1.1 200 OK

HTTP/2 ne définit pas de Reason-Phrase :

HTTP/2 200

Codes de statut


Representational State Transfer (REST)

REST est un style d’architecture logicielle pour les systèmes distribués sur HTTP.

API RESTful et Méthodes HTTP

Ressource GET PUT POST DELETE
Collection URI Liste Remplace Crée Supprime
Élément URI Récupère Remplace Non utilisé Supprime

Sécurité

Trop de vulnérabilités existent… Mais les développeurs sont responsables de leur code !

Attaques courantes

Mesures de protection

Réduisez les vulnérabilités… Utilisez des frameworks !


MVC (Model-View-Controller)

Le modèle MVC permet de :

Modèle

Vue

Contrôleur


MVC en PHP

Un simple script PHP (mal conçu)

Affiche des actualités et permet de commenter.

<?php
$pdo = new \PDO("mysql:host=127.0.0.1;port=3306;dbname=database", 'user', 'password');
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $news_id = $_POST['news_id'];
    $stmt = $pdo->query("INSERT INTO commentaires SET news_id='$news_id',
      auteur='" . $_POST['auteur'] . "', texte='" . $_POST['texte'] . "', date=NOW()");
    header("location: " . $_SERVER['SCRIPT_NAME'] . "?news_id=$news_id");
    exit;
} else {
    $news_id = $_GET['news_id'];
}
?>
<html><head><title>Les news</title></head>
<body>
    <div id="news">
        <?php
        $news_req = $pdo->query("SELECT * FROM news WHERE id='$news_id'");
        $news = $news_req->fetch();
        ?>
        <h1>À la une : <?php echo $news['titre'] ?></h1> 
        <h4>postée le <?php echo $news['date'] ?></h4>
        <p><?php echo $news['texte_nouvelle'] ?> </p>
        <?php
        $comment_req = $pdo->query("SELECT * FROM commentaires
      WHERE news_id='$news_id'");

        $nbre_comment = $comment_req->rowCount();

        ?>
        <h3><?php echo $nbre_comment ?> commentaires relatifs à cette news</h3>
        <ul>
        <?php while ($comment = $comment_req->fetch()) { ?>
            <li><b><?php echo $comment['auteur'] ?></b>
                a écrit le <?php echo $comment['date'] ?>
            <p><?php echo $comment['texte'] ?></p>
        <?php } ?>
        </ul>

        <form method="POST" action="<?php echo $_SERVER['SCRIPT_NAME'] ?>" name="ajoutcomment">
            <input type="hidden" name="news_id" value="<?php echo $news_id ?>">
            <label>Votre nom : </label><input type="text" name="auteur"><br />
            <label>Votre commentaire : </label> <textarea name="texte" rows="5" cols="20" >

      </textarea><br />
            <input type="submit" name="submit" value="Envoyer">
        </form>
    </div>
</body></html>

Problèmes du code

Version MVC : Une meilleure approche

Modèle

// simpleModel.php
function dbconnect() {
  static $connect = null;
  if ($connect === null) {
    try {
      $connect = new PDO("mysql:dbname=" . getenv('DB_NAME') . ";host=" . getenv('DB_HOST'), getenv('DB_USER'), getenv('DB_PASSWORD') );
      $connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) { echo 'Connection failed :( : ' . $e->getMessage(); exit;}
  }
  return $connect;
}

function get_news($id) {
  try{
    $sql = "SELECT * FROM news WHERE id= :id";
    $sth = dbconnect()->prepare($sql);
    $sth->execute(array(':id' => $id));
    if($sth->errorCode() == 0) {
      return  $sth->fetch();
    }
    else {
      return array();
    }
  }catch (PDOException $e) { echo 'Select comments failed: ' . $e->getMessage(); exit;}
}

function get_comments($news_id) {
  try {
    $sql = "SELECT * FROM commentaires WHERE news_id= :news_id";
    $sth = dbconnect()->prepare($sql);
    $sth->execute(array(':news_id' => $news_id));
    if($sth->errorCode() == 0) {
      return  $sth->fetchAll();
    }
    else {
      return array();
    }
  }catch (PDOException $e) { echo 'Select comments failed: ' . $e->getMessage(); exit;}
}

function insert_comment($comment) {
  $connect = dbconnect();
  try{
    $sql =  "INSERT INTO commentaires SET news_id= :news_id , " .
    "auteur= :auteur , " .
    "texte= :texte , " .
    "date=NOW()";
    $sth = $connect->prepare($sql);
    $sth->execute(array(':news_id' => (int)$comment['news_id'],
      ':auteur' => $connect->quote($comment['auteur']),
      ':texte' => $connect->quote($comment['texte']),
      )
    );
  } catch(PDOException $e) { echo 'Insert failed: ' . $e->getMessage(); exit;}
}

Vue

<!-- simpleView.php -->
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Les news</title>
</head>
<body>
  <h1>Les News</h1>
  <div id="news">
    <?php if ($news): ?>
      <h2><?= htmlspecialchars($news['titre']) ?> postée le <?= htmlspecialchars($news['date']) ?></h2>
      <p><?= nl2br(htmlspecialchars($news['texte_nouvelle'])) ?></p>
      <h3><?= $nbre_comment ?> commentaire(s) relatif(s) à cette nouvelle</h3>
      <dl>
      <?php foreach ($comments as $comment): ?>
        <dt><?= htmlspecialchars($comment['auteur']) ?>, le <?= htmlspecialchars($comment['date']) ?>:</dt>
        <dd><?= nl2br(htmlspecialchars($comment['texte'])) ?></dd>
      <?php endforeach; ?>
      </dl>
    <?php else: ?>
      <p>Cette news n'existe pas.</p>
    <?php endif; ?>
    
    <h3>Un commentaire ?</h3>
    <form method="POST" action="<?= htmlspecialchars($_SERVER['SCRIPT_NAME']) ?>" name="ajoutcomment">
      <input type="hidden" name="news_id" value="<?= $news_id ?>">
      <input type="text" name="auteur" placeholder="Votre nom" required><br>
      <textarea name="texte" placeholder="Saisissez votre commentaire" required></textarea><br>
      <input type="submit" name="submit" value="Envoyer">
    </form>
  </div>
</body>
</html>

Contrôleur

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    insert_comment($_POST);
    header("Location: ?news_id=" . $_POST['news_id']);
    exit;
}
$news = get_news($_GET['news_id']);
$comments = get_comments($_GET['news_id']);
$nbre_comment = sizeof($comments);
require ('simpleView.php');

Frameworks PHP MVC

Quelques frameworks populaires :