dimanche, 5 juin 2016

Laravel : utilisation (cas d'une page statique)

Vues

1. Le gabarit (vue générique / parent)

Avec Blade – le moteur de templates de Laravel –, il convient de créer un gabarit sous resources > views. Nommons le default.blade.php, et déposons-y ce contenu :


<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Page de test</title>
</head>
<body>

<h1>Mon site test</h1>

@yield('content')

</body>
</html>

Comme nous pouvons le voir, ce fichier HTML n'est pas complètement normé/standard. L'élément @yield('content') est en effet une des premières caractéristiques de Blade. L'élément yield permet d'agréger le contenu 'content' d'une page tierce, qui héritera du gabarit default.blade.php. Créons donc cette page tierce pour y voir plus clair.  

2. La vue (vue spécifique / enfant)

Dans le dossier views, créons un dossier test et créons-y un fichier informations.blade.php comprenant ce contenu :


@extends('default')

@section('content')
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</p>
@endsection

Dans ce fichier, nous pouvons comprendre le code comme suit : hérite du fichier default (sous-entendu default.blade.php), gabarit qui agrègera (@yield) le contenu de la section 'content'.  

Route

Comme vu dans l'article précédent, le fichier routes.php – présent dans le dossier app > Http – indique l'action à accomplir en fonction de l'URL saisie dans le navigateur. Nous allons donc établir la route comme suit :


Route::get('informations', function() {
	return view('test.informations');
});

Dans le présent exemple, Laravel récupère la vue située dans mon dossier resources > views > test > informations pour l'afficher à l'adresse http://localhost/monprojet/public/informations.   ... Mais cette formulation est un raccourci barbare. Préférons-lui :


Route::get('informations', 'TestController@index');

Cette instruction peut être traduite comme suit : pour la route menant à http://localhost/monprojet/public/informations, exécute la méthode index() du contrôleur TestController. Reste donc à créer ledit contrôleur pour que la route génère un résultat...  

Contrôleur

Dans le dossier App > Http > Controllers, créez un contrôleur TestController avec ce contenu :


<?php
namespace App\Http\Controllers;

class TestController extends Controller {

	public function index() {
		return view('test.informations');
	}

}

La méthode index() du contrôleur ici présent – à laquelle il a été fait appel dans la route ci-dessus – retourne la vue informations.blade.php issue du dossier test sous resources > views (on aurait tout aussi bien pu écrire test/informations, Laravel accepte les deux nomenclatures)  

Résultat

En se rendant sur la page : http://localhost/monprojet/public/informations, nous obtenons ce résultat :  

Conclusion

Rien ne justifie le choix d'un framework pour la réalisation d'un site statique, puisqu'il complexifie énormément les choses, comme vous pouvez le voir. Toutefois, dès lors que nous exploiterons des données dynamiquement et communiquerons avec la base de données, les procédures s'en trouveront allégées : moins de code, plus de sécurité ;) . Le prochain article s'attardera sur la création d'une page plus dynamique pour permettre d'exploiter les vues Blade, les routes et les contrôleurs un peu plus loin. Et ce sera toujours sans modèle ni base de données, pour y aller pas à pas. Enregistrer

samedi, 4 juin 2016

Laravel : introduction

laravel.pngNé en 2011, Laravel est le framework PHP à architecture MVCR dont on parle probablement le plus après Symfony depuis quelques années. Je suis partie à la rencontre de cet outil, et pour ne rien perdre des connaissances que j'en ai engrangées, je délivre dans le même temps ce mémo.


Installer Laravel

  • Installer Composer.composer.png
  • Installer Laravel : depuis l’invite de commandes, accéder au dossier www/htdocs de votre wamp/xampp et exécuter la commande suivante :
    composer create-project laravel/laravel {directory} "~5.0.0" --prefer-dist
  • Établir la connexion à la base de données : adapter les paramètres sous le fichier .env à la racine du dossier.

Préambule

Arborescence du framework

  • app (cœur de votre application)
    • Commands
    • Console
    • Events
    • Handlers
    • Commands
    • Events
    • Http
      • Controllers
      • Middleware
      • Requests
    • Providers
    • Services
  • bootstrap (fichiers d’initialisation de Laravel)
  • config (fichiers de configuration)
  • database (fichiers liés à la base de données)
    • migrations
    • seeds
  • public (assets : fichiers images, js, css)
    • package
  • resources (vues et fichiers de langue)
    • lang
    • views
  • storage (données temporaires de l’application : clés de session, caches…)
    • cache
    • logs
    • meta
    • sessions
    • views
    • work
  • tests (fichiers de tests unitaires)
  • vendor (composants de Laravel & dépendances)

Routes

Laravel impose l'utilisation de routes pour faire le pont entre ses vues et ses contrôleurs. S'il s'agit d'une caractéristique plutôt rébarbative au premier abord ((Face à des frameworks comme CodeIgniter, CakePHP ou Nette qui gèrent les routes automatiquement, Laravel force à se concentrer sur une composante de plus.)), on lui reconnaît les qualités de renforcer la sécurité et surtout d'améliorer la vitesse d'affichage, et donc l'expérience utilisateur. Présent dans le dossier app > Http, le fichier routes.php indique l'action à accomplir en fonction de l'URL saisie dans le navigateur. En fonction de l'URL explorée, les routes transmettent des données à la méthode d'un contrôleur, qui se charge d'exécuter une série d'instructions – en passant si nécessaire par le modèle, destiné à l'élaboration de requêtes dans la base de données – pour renvoyer enfin le résultat à la vue.

mcvr-1.png

Artisan

Laravel propose une interface en ligne de commande nommée Artisan. Artisan permet d'automatiser toute une série d'opérations de gestion au sein du framework, telles que la création de contrôleurs, de modèles, de migrations, ou l'affichage des routes existantes établies au sein de l'application créée.

Blade

Blade est le moteur de templates dépendant de Laravel. Il fonctionne sur un système d'héritage qui lui permet d'agréger des vues, et de faciliter par ailleurs l'affichage de variables (code PHP) en échappant la plupart des données qui sont embarquées dans les vues.

Eloquent

Eloquent est un ORM (Object-relational Mapping) implémentant ActiveRecord qui permet de faciliter les requêtes dans la base de données par une syntaxe voulue plus éloquente que du simple SQL. Il supporte nativement plusieurs SGBD : MySQL, PostgreSQL, Sqlite3 et SQLServer. Eloquent est typiquement utilisé dans les modèles, situés dans le dossier app > Http. Depuis Laravel 4, il n'est toutefois plus obligatoire pour gérer les requêtes au sein du framework. Il peut être par ailleurs remplacé par d'autres ORM qui correspondraient mieux aux attentes du développeur.

Conventions de nommage

  • Les tables des bases de données doivent figurer au pluriel.
  • Les colonnes de la base de données doivent normalement figurer en snake_case.
  • Les noms de classes doivent être déclarées UpperCamelCase.
  • Le nom des méthodes et des fonctions est prévu en lowerCamelCase.
  • Les constantes sont toutes déclarées en UPPERCASE_AVEC_UNDERSCORES.
  • Le nom des modèles, rappelant celui des tables doit figurer au singulier.
  • Les contrôleurs n'imposent rien quant au genre (singulier ou pluriel).

Précautions

Contrairement à d'autres frameworks, Laravel propose une upgrade (et non une update !) à chaque sous version, et ce, de manière extrêmement rapide ((Laravel a proposé sa version 5.0 en février 2015, sa version 5.1 en juin 2015 et sa version 5.2 en décembre 2015 !)). En procédant à l'upgrade d'un projet sur lequel vous avez déjà bien avancé, vous risqueriez de ne plus pouvoir exécuter celui-ci comme avant en raison des changements opérés au sein du noyau même de l'outil en passant, par exemple, de la version 5.1 à la version 5.2 du framework. Je vous recommande donc de conserver la version avec laquelle vous avez entamé votre site/application. Toutefois, pas de panique : les différentes versions du framework sont supposées être maintenues assez durablement, et leurs documentations rester disponibles tant que les versions précédentes "vivront".

laravel-releases.png

Dans l'article suivant, nous nous pencherons sur une utilisation basique du framework – sans base de données – pour appréhender les interactions entre les routes, les contrôleurs et les vues Blade. Enregistrer

mardi, 1 décembre 2015

Contrer les robots spammeurs

 

captha.gifDès lors que votre site est référencé sur le web et comporte un formulaire (destiné à envoyer un mail, à commenter un article, à s'inscrire sur un site...), il s'offre telle une proie aux vautours que sont les spambots. Les robots spammeurs prennent en effet d'assaut de nombreux sites en complétant frénétiquement les champs de saisie qui se présentent devant eux. Ici, vous trouverez une liste de solutions en vue de contrer ce phénomène.

  • Ne pas écrire son adresse mail en clair sur un site ! Voici des solutions pour cacher un e-mail.
  • Placer un champ invisible dans le formulaire (display:none ou visibility:hidden en CSS) : les spambots tentent de tous les remplir. Si ce champ est rempli, vous êtes à peu près sûr de ne pas avoir affaire à un humain ((Attention, les lecteurs d'écran des malvoyants peuvent parcourir ce genre de champ. À vous de mettre en garde les utilisateurs pour qu'ils ne le remplissent.)). Toutefois, veillez à ce que le champ ait l'air le plus normal possible pour que les robots ne l'ignorent pas (évitez les name='leaveBlank', 'detectSpam' ou 'honeypot').
  • Vérifier l'email : l'envoi d'un lien pour confirmer la transaction est une option pertinente dans le cadre de l'inscription sur un site. Elle est plus rébarbative s'il s'agit simplement de publier un commentaire sur un blog.
  • Permettre aux utilisateurs de s'inscrire par l'intermédiaire des réseaux sociaux (Oauth) est aussi une solution pour ne pas se confronter aux robots. Mais il serait déplaisant de n'offrir que cette solution aux utilisateurs, car nombre d'entre eux préfèrent une inscription classique.
  • Poser une question telle que "Quatre plus six ?" ou "Quelle est la couleur de l'herbe ?" : il s'agit d'une solution accessible pour vérifier si vous avez affaire à un robot. Toutefois, elle est souvent dissuasive pour les utilisateurs qui n'en saisissent pas l'utilité.
  • Imposer un CAPTCHA visuel (image résistant aux dispositifs OCR) est une possibilité. Mais les CAPTCHAs sont rébarbatifs pour les utilisateurs et surtout non accessibles aux personnes souffrant de troubles visuels sévères ((Les aveugles et malvoyants ne sont capables de prendre connaissance du contenu d'une image que par l'attribut "alt" de l'élément HTML "img". En l'occurrence, les CAPTCHAS ne renseignent pas ce genre d'attribut, sous peine de prêter main forte aux robots spammeurs.)), donc à éviter dans la mesure du possible.
  • Imposer un CAPTCHA audio est une option intéressante, mais pas meilleure que la précédente. Le problème de l'accessibilité se pose en effet non seulement pour les sourds et malentendants, mais aussi pour les utilisateurs dont la carte son serait dysfonctionnelle...
  • Imposer un reCAPTCHA (Google) semble une option partiellement fonctionnelle en termes d'accessibilité. Certains lecteurs d'écran sont en mesure d'y accéder, d'autres non. Dans ce cas-ci, Google analyse si l'utilisateur est un robot ou non sur base des mouvements de la souris et de la manière dont les réponses sont saisies. Toutefois, cet outil est controversé, parce qu'il semble au passage se saisir des données privées de l'utilisateur à des fins publicitaires.
  • Vérifier si l'IP n'appartient pas à une liste noire via des outils tels que Project HoneyPot, Stop forum spam ou Botscout.
  • Bloquer les IP selon le lieu d'origine de "l'utilisateur" : la plupart des robots spammeurs émanent de Chine, Inde, Indonésie, Pakistan, Russie et Ukraine. Si votre site n'est pas destiné à un public international, envisagez de bloquer ce type d'IP d'emblée.
  • Bloquer une liste de mots-clés : si les contenus postés comprennent des termes inappropriés ou que, par exemple, 5 consonnes se suivent dans une chaîne de caractères, bloquez l'IP.
  • Dénombrer le nombre de tentatives d'écriture/d'inscription émanant d'une même adresse IP et prévenir le flood ou les attaques en rejetant l'IP pour une durée établie au bout de X essais.
  • Détecter la rapidité de complétion : les robots remplissent un formulaire en une maigre poignée de secondes après l'ouverture de la page. Des outils jQuery sont en mesure de calculer ce genre de délai, à vous de bloquer les faux-utilisateurs potentiels qui prennent moins de 5 secondes pour compléter et valider un formulaire.
  • Demander aux utilisateurs de fournir leurs motivations pour rejoindre le site et soumettre les réponses à l'appréciation d'un modérateur pour l'activation des comptes. C'est ultra ingrat et fastidieux tant pour les utilisateurs que pour les gestionnaires du site, mais c'est très sûr...
  • [CMS] Utiliser des solutions anti-spams telles qu'Akismet sous Wordpress ou Mollom sous Drupal.

Malgré toutes ces solutions, aucune ne garantit à 100% que vous soyez à l'abri d'attaques qui portent leurs fruits. L'évolution des robots est grandissante, il convient de veiller sans cesse pour adapter la sécurité de son site en conséquence.


Informations complémentaires

Sources

Enregistrer

mardi, 24 novembre 2015

Nette framework : utilisation

Ici, nous voyons les interactions entre une présentation et ses vues, comment fonctionnent les formulaires, ainsi que l'ajout et l'édition de données dans la base de données.

Avant de commencer, admettons que vous ayez connecté votre base de données (cf. article précédent) en prenant soin de privilégier InnoDB comme moteur de stockage, et que vous ayez créé deux tables : posts et comments.

Presenter / Présentation

app/presenters/PostPresenter.php


namespace App\Presenters;

use Nette,
    Nette\Application\UI\Form;

class PostPresenter extends BasePresenter
{
/** @var Nette\Database\Context */
private $database;

public function __construct(Nette\Database\Context $database)
{
    // connexion à la base de données
    $this->database = $database;
}

public function renderDefault() ➊
// génère une vue default.latte
{
   // récupère les données et
   // les envoie dans la vue sous la variable $posts
   $this->template->posts = $this->database->table('posts')
      ->order('created_at DESC')
      ->limit(5);
}

public function renderShow($postId) ➋
// génère une vue show.latte
{
   // récupération du $postId,
   // s'il n'existe pas, afficher une erreur,
   // sinon envoyer le résultat dans la vue
   $post = $this->database->table('posts')->get($postId);
   if (!$post) {
       $this->error('Post not found');
   }

   $this->template->post = $post;
   $this->template->comments = $post->related('comments')
       ->order('created_at');
}

protected function createComponentCommentForm() ➌
// sera récupéré dans la vue sous "CommentForm"
{
    // création d'un formulaire
    $form = new Form;

    $form->addText('name', 'Your name:') // ('name', 'label')
        ->setRequired() // required
        ->setAttribute('class', 'toto')
        ->setAttribute('placeholder', 'Please type your name')
        ->setAttribute('onchange', 'mafonction()');

    $form->addText('email', 'Email:')
        ->setType('email');

    $sex = array(
        'm' => 'male',
        'f' => 'female',
    );
    $form->addRadioList('gender', 'Gender:', $sex);

    $form->addCheckbox('Human', 'Are you a human ?');

    $countries = array(
        'Europe' => array(
            'CZ' => 'Czech republic',
            'SK' => 'Slovakia',
            'GB' => 'United Kingdom',
        ),
        'CA' => 'Canada',
        'US' => 'USA',
        '?'  => 'other',
    );
    $form->addSelect('country', 'Country:', $countries)
        ->setPrompt('Pick a country');

    $form->addTextArea('content', 'Comment:')
       ->setDisabled(); // disabled

    $form->addUpload('thumbnail', 'Thumbnail:')
        ->addRule(Form::IMAGE, 'Thumbnail must be JPEG, PNG or GIF');

    $form->addSubmit('send', 'Publish comment');

    $form->onSuccess[] = array($this, 'commentFormSucceeded'); ➍

    return $form;
}

➍ public function commentFormSucceeded($form, $values) {
$postId = $this->getParameter('postId');

$this->database->table('comments')->insert(array(
     'post_id' => $postId,
     'name' => $values->name,
     'email' => $values->email,
     'content' => $values->content,
));

$this->flashMessage('Thank you for your comment', 'success'); ➎
$this->redirect('this');
// alternative :
// $this->redirect('show', $post->id);
}

public function actionEdit($postId) ➒
// actionEdit et non renderEdit :
// il ne s'agit pas que d'un travail de rendu dans ce cas-ci.
{
    $post = $this->database->table('posts')->get($postId);
    if (!$post) {
        $this->error('Post not found');
    }
    $this['postForm']->setDefaults($post->toArray()); ➏
}

protected function createComponentPostForm() ➏
{
$form = new Form;
$form->addText('title', 'Title:')
     ->setRequired();
$form->addTextArea('content', 'Content:')
     ->setRequired();

$form->addSubmit('send', 'Save and publish');

$form->onSuccess[] = array($this, 'postFormSucceeded'); ➐

return $form;
}

➐ public function postFormSucceeded($form, $values) {
$postId = $this->getParameter('postId');

if ($postId) {
   $post = $this->database->table('posts')->get($postId);
   $post->update($values);
} else {
   $post = $this->database->table('posts')->insert($values);
}

$this->flashMessage('Post was published', 'success'); ➎
$this->redirect('show', $post->id);
}

}

View / Vue

app/templates/Post/default.latte


{block content} ➑
    <h1 n:block="title">Blog</h1>

    {foreach $posts as $post}
    <div class="post">
        <div class="date">{$post->created_at|date:'F j, Y'}</div>

        <h2>{$post->title}</h2>

        <div>{$post->content}</div>
    </div>
    {/foreach}

    <a n:href="Post:create">Write new post</a>

{/block}

➋ app/templates/Post/show.latte


{block content} ➑
<p><a n:href="Homepage:default">← back to posts list</a></p>
<div class="date">{$post->created_at|date:'F j, Y'}</div>
<h1 n:block="title">{$post->title}</h1>
<div class="post">{$post->content}</div>
➒ <a n:href="edit $post->id">Edit this post</a>

<h2>Post new comment</h2>
➌ {control commentForm}

<h2>Comments</h2>
<div class="comments">
    {foreach $comments as $comment}
        <p><b><a href="mailto:{$comment->email}"
         n:tag-if="$comment->email">
         {$comment->name}</a></b> said:</p>
        <div>{$comment->content}</div>
    {/foreach}
</div>

app/templates/Post/edit.latte


{block content} ➑
<h1>Edit post</h1>

➏ {control postForm}

app/templates/@layout.latte (gabarit inclusif)


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>{ifset title}{include title|striptags} | {/ifset}Nette Web</title>
    <!-- embarque/agrège le title spécifié dans la vue -->

    <link rel="shortcut icon" href="{$basePath}/favicon.ico">
</head>

<body>
     ➎ <div n:foreach="$flashes as $flash" n:class="flash, $flash->type">
            {$flash->message}
        </div>
    <!-- affiche les messages d erreur liés
    à la complétion du formulaire (champs requis et autres règles)-->

     ➑ {include content}
        <!-- embarque/agrège le contenu des vues : {block content} -->

    {block scripts}
    <script src="//nette.github.io/resources/js/netteForms.min.js"></script>
    {/block}
</body>
</html>

Formulaires : validation et récupération des données


$form->addPassword('password', 'Password:')
    // if password is not longer than 5 characters ...
    ->addCondition(Form::MAX_LENGTH, 5)
        // ... then it must contain a number
        ->addRule(Form::PATTERN, 'Must contain number', '.*[0-9].*')
        ->addRule(Form::RANGE, 'You must be older 18 years and be under 120.', array(18, 120));

// récupération des valeurs après soumission :
$values = $form->getHttpData($form::DATA_TEXT, 'sel[]');
$values = $form->getHttpData($form::DATA_TEXT | $form::DATA_KEYS, 'sel[]');

Parmi les règles et conditions, voici la liste des fonctions possibles ((Liste non exhaustive.)) :

  • Form::MIN_LENGTH : minimum de caractères ou de fichiers accepté
  • Form::MAX_LENGTH : maximum de caractères ou de fichiers accepté
  • Form::LENGTH : nombre strict de caractères ou de fichiers accepté
  • Form::EMAIL : impose un format email
  • Form::URL : impose un format url
  • Form::INTEGER : impose un nombre entier
  • Form::FLOAT : impose un nombre décimal
  • Form::RANGE : impose une fourchette entre X et Y
  • Form::PATTERN : expression régulière
  • Form::BLANK : le champ doit rester vide
  • Form::MAX_FILE_SIZE : impose le poids d'un fichier
  • Form::MIME_TYPE : vérifie si le type MIME est valide
  • Form::IMAGE : impose un fichier au format .gif, .png ou .jpg
  • Form::FILLED : vérifie si le champ est rempli
  • Form::EQUAL : vérifie que la valeur est égale à celle prescrite
  • Form::NOT_EQUAL : vérifie que la valeur est différente de celle prescrite
  • Form::IS_IN : vérifie si la valeur fait partie d'un tableau
  • Form::VALID : vérifie si le champ est acceptable pour la validation

Sources

lundi, 23 novembre 2015

Nette framework : présentation et installation

nette.pngNette est un framework MVP* qui a le vent en poupe en République tchèque (d’où il vient) et en Slovaquie. Il existe depuis 2009 et Sitepoint le place dans le trio de tête des frameworks PHP en 2015, malgré quelques carences au niveau des performances, comme pour Zend et Laravel :

 

sp-compare.gif

Bien que la Belgique et la France ignorent pour le moment ce framework, je l’ai testé pour comparer son fonctionnement à ceux de Laravel, CodeIgniter et CakePHP.

Nette comporte pléthore de qualités : parmi elles, sa prise en main d’une simplicité déconcertante, sa sécurité manifeste, ses outils de débogage (Tracy), sa documentation complète et accessible (qui commence au b.a.-ba, contrairement à certaines…) et sa communauté anglophone plutôt dynamique.

A l’inverse de certains frameworks, il fonctionne selon une architecture Modèle-Vue-Présentation, version évoluée de l’architecture Modèle-Vue-Contrôleur.

mvp.png

Le MVP garde le même principe que le MVC mais élimine l’interaction entre la vue et le modèle. Le relais est assuré par la présentation qui organise les données à afficher dans la vue. Plus d’informations.

Dans cet article et ceux qui suivront, vous trouverez des mémos d’utilisation du framework, comme je l’ai fait en son temps pour CakePHP.


Installer Nette Framework

  • Installer Composercomposer.png
  • Installer Nette : depuis l’invite de commandes, accéder au dossier www/htdocs de votre wamp/xampp et exécuter la commande suivante :
    composer create-project nette/sandbox [app_name]
  • Mettre à jour Nette : la dernière version stable du framework sera installée en exécutant à partir du dossier générique de l’appli la commande suivante :
    composer update
  • Installer les composants nécessaires au bon fonctionnement du framework :
    composer require latte/latte
  • Établir la connexion à la base de données en INNODB : adapter les paramètres sous app > config > config(.local)*.neon (* Si vous testez l'appli en local ou en production). Attention à l'indentation au sein du fichier .neon !

Prérequis

⚠ Mémo :

nette-structure.png

  • Il y a autant de vues qu’il y a d’actions/méthodes dans le presenter.
  • Il y a autant de dossiers de vue (sous Templates) qu’il y a de presenters.

Standards de programmation

  • L'indentation est importante : elle se fait par tabulations et non par espaces.
  • Les lignes de codes sont limitées à 120 caractères (idéalement, 80 ou moins).
  • Les constantes TRUE, FALSE, NULL sont toujours en capitales.
  • Nette recommande l'utilisation de l'UTF-8 et de l'ASCII en guise d'encodage de caractères.
  • L'utilisation de <?php est la seule manière valable d'amorcer du code en php (oubliez les '<?= ?>').
  • La fermeture ?> doit être omise dans les fichiers qui contiennent du PHP exclusivement.
  • Limitez-vous à une déclaration par ligne.
  • Aucune espace ne doit traîner à la fin des lignes de code.
  • Les noms de fichiers et noms de classes doivent être identiques.
  • La déclaration de variables, fonctions ou constantes globales est fortement déconseillée.
  • @, l'opérateur de contrôle d'erreur (ou de mise en veilleuse) doit être commenté comme suit :
@mkdir($dir); // @ - directory may exist

Conventions de nommage

  • Les classes doivent être déclarées en UpperCamelCase.
  • Les propriétés et méthodes doivent être déclarées en lowerCamelCase.
  • Les opérateurs de comparaison forts (===/!==) sont préférés aux autres (==/!=).
  • Les structures conditionnelles utilisent elseif et non else if.
  • Se limiter à des caractères alphanumériques dans le choix des noms.
  • Les variables doivent être explicites : $i, $n ne sont admises que pour faire office de compteur dans les boucles.
  • La concaténation demande un espace avant et après le "."
  • Les tableaux doivent être déclarés avec la déclaration entre [], avec des espaces après chaque virgule pour augmenter la lisibilité du code : [$un, $deux, $trois]
  • Le nom des interfaces commence toujours par un "I". Exemple : IPresenter.
  • Les mots-clés "extends" et "implements" doivent être déclarés sur la même ligne que le nom de la classe.

Sources

dimanche, 22 novembre 2015

Renforcer la sécurité d’un site ou une appli web

alt=&quot;StickOfCelery (Deviantart) - SQL Wifejection&quot;

Ci-après, les développeurs web et webmestres trouveront une liste sélective et concise ((Pour plus d'informations, consulter les sources au bas de l'article.)) de pratiques et recommandations permettant de renforcer la sécurité des sites et applications web. Le respect de ces principes ne suffit pas (un hackeur vaillant obtient souvent ce qu'il convoite), mais permet à tout le moins de ne pas laisser la porte grand ouverte...

CMS, forums, frameworks et autres outils "prêts à l'emploi"

  • Mise à jour constante de l'outil et de ses plugins / librairies.
  • Éviter de préfixer les tables avec leurs abréviations habituelles (wp_ pour Wordpress, jml_ pour Joomla, etc.).
  • Cacher autant que possible l'outil utilisé, en particulier dans la barre d'adresse.

.htaccess

Attention, le .htaccess est sensible ! Il convient de faire des sauvegardes du fichier au préalable, de tester une modification à la fois, et de veiller au fonctionnement de l'intégralité du système après avoir opéré chaque changement. L'altération du .htaccess mène vite à une "Internal server error" (500).

  • Register_globals à 0 / OFF / False pour empêcher l'accès aux superglobales telles que $_POST, $_GET, etc.
  • Interdiction de lister le contenu des dossiers et d'accéder à des fichiers spécifiques (éviter impérativement de faire ceci dans le fichier robots.txt qui passe plus volontiers en clair !)
  • Utilisation de la dernière version de PHP.

Fichiers et dossiers

  • CHMOD : Attribution de permissions d'accès restrictives aux dossiers (705/755) et fichiers (604/644) présents sur le FTP, dans la mesure du possible. Accès encore plus restrictif aux fichiers principaux tels que l'index du site et le style CSS (404/444).
  • Emploi de noms surprenants ((Cela va un peu à contre-sens des préceptes liés au code "propre" et aux lois du référencement, mais les robots spammeurs seraient paramétrés pour visiter des adresses comprenant certains termes.)) en particulier pour les pages qui comprennent des formulaires : éviter login, admin, contact, etc. (cela vaut également pour les attribut "name" des inputs : éviter name, (e)mail, subject, etc.).

Mots de passe

  • Les bons mots de passe comprennent au minimum 8 caractères, et présentent des lettres, des chiffres ainsi que des caractères spéciaux.
  • Scrupuleusement veiller à utiliser des mots de passe différents pour le FTP, la base de données, l'administration du site, l'authentification, etc.

Identifiants

  • Les CMS proposent souvent "admin" ou "administrateur" en guise d'identifiant. À éviter.
  • Éviter l'ID 1 pour l'administrateur.

Base de données et requêtes SQL

Cryptage

Pour un hashage sûr – de mots de passe en particulier –, préférer password_hash() et crypt() à MD5, SHA1 et SHA256.

  • Crypter le fichier de configuration ((Sécurité supplémentaire par rapport au CHMOD, au .htaccess qui en réduit l'accès et à l'extension .php qui ne permet pas d'afficher le fichier en texte brut.)).
  • Crypter les mots de passe.
  • Crypter les adresses e-mail.

Sessions

Plusieurs techniques permettent de prévenir les détournements de sessions :

  • Lier une adresse IP à une session peut-être une bonne pratique, à condition que les utilisateurs n'utilisent pas un logiciel comme Tor pour préserver leur anonymat :
$ IP = getenv ("REMOTE_ADDR");
  • Invalider l'ID de session après connexion de l'utilisateur (ou même après chaque demande) avec session_regenerate_id ().
  • Attribuer des tokens lors de la complétion des formulaires (ne jamais stocker les tokens dans des cookies !)

Vérification et validation

⚠ Principe fondamental : NE JAMAIS faire confiance aux données saisies par l'utilisateur ((Retenez que les fichiers, valeurs de session, données des cookies et données provenant de services tiers sont aussi des entrées étrangères !)).

  • Vérifier l'origine (émetteur) pour les envois de messages.
  • Vérifier le typage de ce qui est envoyé (is_string, is_int, is_bool, is_array...).
  • Vérifier si le contenu est autorisé (in_array).
  • Pour les comparaisons, recourir à l'identité (===) et non à l'égalité (==).
  • Limiter le nombre de caractères des données envoyées (varchar (x) et validation).
  • Échapper les contenus pour éviter les balises – <script> et <iframe> en particulier –, ainsi que ces signes ((Pour ce faire, abuser des fonctions PHP htmlentities, htmlspecialchars, strip_tags, addslashes et dérivées et/ou utiliser des RegExp. Attention, la fonction mysql_real_escape_string n'est visiblement pas sûre !)) :
< > : ; " ' & $ ! ? ~ ^ | @ # ( ) [ ] { }  _ - / \

php.ini

Moult paramètres peuvent être modifiés de manière à rendre le site plus opaque et plus sécure :

display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
disable_functions

Toutefois, certains hébergements ne permettent pas de modifier ce fichier. Le .htaccess peut y subvenir en tout ou partie.

Surveillance

Les logs permettent de retracer les événements qui ont eu lieu sur le site ou l'application en ligne. Il peut s'avérer nécessaire de les analyser de temps en temps. Il est primordial d'y revenir après un désastre.

Tester la vulnérabilité de vos sites


Sources

mardi, 13 octobre 2015

Coder proprement

code.jpg

Tout script compliqué à lire ou à comprendre peut nécessairement être simplifié, amélioré, refactoré. Voici quelques piliers qui concourent à la qualité du code :

  • Noms significatifs et clairs Choisir des noms ou groupes nominaux pour les classes (ex : Customer), des verbes pour les méthodes (ex : deletePage), des noms de variables en fonction de leur rôle (ex : $ip_visiteur), contextualiser autant que possible pour éviter les déductions (ex : stateAdress plutôt que state tout court, ou state dans une classe Address) ; éviter les abréviations ; un même nom ne doit jamais avoir deux usages.
  • Fonctions courtes ; classes et méthodes aussi Les fonctions ne doivent faire qu'une et une seule chose. Il convient de les écourter au maximum (~5 lignes) ; d'éviter les indentations à plus de 2-3 niveaux et de les faire se succéder comme une suite d'articles dans un journal. Les méthodes (~20 lgn) et les classes (~200 lgn) doivent être également aussi courtes que possible.
  • Commentaires Commenter ce qui mérite d'être clarifié ; expliciter les actions commises par des parties de code (sens général).
  • Lisibilité : indentation du code et espacement des rubriques Pour la lisibilité du code, saisir une instruction par ligne. Les blocs d'instruction ou les fonctions doivent être séparés par des lignes ou des espaces permettant de segmenter le code en rubriques. L'indentation doit être claire et chaque accolade fermante doit être verticalement alignée à l'instruction défi nissant l'accolade ouvrante correspondante.
  • Exceptions et non codes de retour Les codes de retour obligent à créer des structures conditionnelles qui ne sont pas nécessairement lues et alourdissent l'algorithme. Préférer les exceptions qui, de surcroît, alimentent les logs.
  • Tests unitaires propres Ils doivent être aussi propres que le code en production !
  • Classes évolutives Penser à ce qui peut être hérité pour ne pas avoir à tout réadapter.
  • Règle du boy scout "Laissez toujours le code un peu plus propre que vous l'avez trouvé en sortant " ;-)

Sources

Enregistrer

jeudi, 23 juillet 2015

Télécharger des vidéos en ligne

Je m'entends sur le choix de Firefox comme navigateur web. Sous Firefox, des modules tels que Flashgot (pour ne citer que celui-là) permettent de récupérer un bon paquet de fichiers multimédia, dont des vidéos (MP4, MPG, FLV, 3GP, etc.). C'est la solution que je privilégie pour télécharger des vidéos issues de Youtube, Dailymotion, Vimeo ou autres sites apparentés. En raison du grand nombre de tutoriels qui vous accompagnent à l'installation et à l'utilisation de cet outil, je m'attarderai ci-après sur les extractions de vidéos qui donnent davantage de fil à retordre. Pour identifier à quel type de vidéo vous avez affaire, remettez-vous en au code source... Les vidéos en streaming RTMP ((RTMP (Real Time Messaging Protocol) est un protocole réseau propriétaire, développé par Adobe Systems, pour la diffusion de flux de données en streaming entre un serveur et un client, généralement le lecteur Flash (Source : Wikipédia).))

  • Se rendre sur la page de la vidéo,
  • Repérer l’adresse du flux dans le code source (rtmp:// …)

Exemple :

sources: [{
file: "rtmp://37.187.156.238:1935/vod/mp4:" + "EMG002561" + ".mp4"},{
file: "http://37.187.156.238:1935/vod/mp4:" + "EMG002561" + ".mp4" + "/playlist.m3u8"
}]

Option lente mais simple

Cette méthode prend le temps de la diffusion parce que c'est un flux... Autrement dit, si la vidéo fait 20 minutes, son extraction durera, elle aussi, 20 minutes (voire plus).

  • Reconstituer l’adresse si elle fait l’objet d’une concaténation Dans le cas présent, "rtmp://37.187.156.238:1935/vod/mp4:" + "EMG002561" + ".mp4" devient donc rtmp://37.187.156.238:1935/vod/mp4:EMG002561.mp4
  • Lancer le logiciel VLC
  • Accéder à Média > Convertir/Enregistrer > Onglet "Réseau"
  • Saisir l'adresse du flux (‘rtmp://37.187.156.238:1935/vod/mp4:EMG002561.mp4’, par exemple)
  • Valider une première fois
  • Saisir la destination et le nom du fichier + le codec adéquat
  • Lancer la diffusion
  • Récupérer la vidéo à l'emplacement spécifié une fois que le processus a atteint 100%

Option rapide mais complexe*

*Pour les amateurs d'Ouverture facile... ;)

  • Se rendre sur la page de la vidéo,
  • Repérer l’adresse du flux qui se termine par .m3u dans le code source
  • Saisir l’adresse déconcaténée dans la barre d’URL du navigateur (à savoir : 'http://37.187.156.238:1935/vod/mp4:EMG002561.mp4/playlist.m3u8' sur base de l’exemple précité)
  • Télécharger le fichier playlist
  • Ouvrir le fichier avec un éditeur de texte (tel que Notepad ++)

Dans l’exemple observé, le fichier téléchargé contient ce contenu suivant :

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1435055,CODECS="avc1.66.30,mp4a.40.2",RESOLUTION=720x406
chunklist_w1190672595.m3u8
  • Récupérer le nom du fichier contenu dans le fichier (ici : chunklist_w1190672595.m3u8)
  • Substituer le nom de ce fichier au premier fichier « playlist.m3u » dans la barre d’adresse (ce qui donne dans notre exemple : http://37.187.156.238:1935/vod/mp4:EMG002561.mp4/chunklist_w1190672595.m3u8)
  • Ouvrir le fichier avec un éditeur de texte (tel que Notepad ++)
  • Répéter l’opération autant de fois qu’il y a de poupées russes, jusqu’à temps de se retrouver face à une suite de fichiers audiovisuels (.ts, .avi…) (ex : http://37.187.156.238:1935/vod/mp4:EMG002561.mp4/media_w1190672595_12.ts )
  • Télécharger l'ensemble des fichiers, et les concaténer (how to : to do)

Les vidéos F4F

  • Préalable : installer WampServer ((Dédié au développement web, ce logiciel permet de lire les pages codées en langage interprété et simule le fonctionnement d’un serveur web localement.))
  • Sous wamp/bin/php/phpX.X ((Version de php nativement installée sous Wamp)), coller le fichier AdobeHDS.php (à créer sur base du RAW)
  • Sous Firefox, installer le module HDS link detector
  • Lancer la vidéo F4F en ligne et récupérer la ligne de commande que propose HDS link Detector : le texte à récupérer s’affiche automatiquement à la lecture de la vidéo dans une pop-up qui surgit dans le coin inférieur droit. Cliquer sur cette pop-up pour copier le code dans le presse papier.
  • Lancer le terminal de commande
  • Naviguer (cd) vers wamp/vin/php/phpX.X/
  • À l’endroit où se trouve php.exe (vérifier via l’explorateur de fichiers), coller le code copié avec HDS link detector
  • Exécuter le script
  • Se rendre dans le dossier correspondant pour récupérer le fichier fusionné et converti en FLV
  • Répéter l’opération autant de fois qu’il y a de fichiers F4F, et fusionner ensuite les FLV avec Any Video Converter (AVC)* s’il s’agit de parties qui forment un tout.

*Pour fusionner les vidéos avec AVC :

  • Ouvrir AVC
  • Importer massivement dans AVC toutes les vidéos devant faire l’objet d’une fusion
  • Sélectionner toutes les vidéos (ctrl+A)
  • Clic droit > joindre tous les fichiers
  • Privilégier customized mp4 format, et cliquer sur « convertir ! »
  • Une fois la conversion faite, le dossier où est stocké le fichier fusionné s’ouvre normalement automatiquement. Si ce n’est pas le cas, jeter un œil sous Dossier usager/Videos/Any video converter/[format-privilégié]

La liste de procédures liées aux vidéos dont l'extraction est ardue est loin d'être terminée. Cet article est donc amené à s'étoffer peu à peu...

- page 2 de 4 -