Lightning Talks

Tirage au sort (Part I)

Inscrivez vous sur t.afup.org pour participer au tirage au sort pour gagner un grand elePHPant AFUP!!

 

Audrey Neveu

Depuis 2012

+6500 enfants !

L'enVar du décor

Damien Alexandre

12 Factor

So 2011 ou toujours d'actualité ?

@damienalexandre - JoliCode - L'enVar du décor

Chapitre 3

Exposez la
🔐 configuration 🔐
en variable d'environnement

@damienalexandre - JoliCode - L'enVar du décor

  • La configuration d'une application varie d'un déploiement à un autre, le code jamais ;

  • Les variables d'environnement sont facile à changer sans modifier le code, sans vider le cache... ;

  • Les variables d'environnement sont indépendantes du langage et du système d'exploitation.

@damienalexandre - JoliCode - L'enVar du décor

Pourquoi ?

@damienalexandre - JoliCode - L'enVar du décor

# Configuration PHP FPM (par exemple)
[www]
env[DATABASE_HOSTNAME] = 'covfefe'
env[DATABASE_PORT] = '123'


# Dans le code
$db->connect($_SERVER['DATABASE_HOSTNAME'], $_SERVER['DATABASE_PORT']);

# Mais aussi :
getenv('DATABASE_HOSTNAME');
$_ENV['DATABASE_HOSTNAME'];

Comment ?

Aucun fichier à parser, tout au runtime !

@damienalexandre - JoliCode - L'enVar du décor

Est-ce sûr ?

@damienalexandre - JoliCode - L'enVar du décor

Est-ce sûr ?

  • Une variable passée à un process sera aussi passée à tous ses enfants (leak) ;
  • Considéré dangereux par certains Ops ;
  • Au final il y aura toujours des secrets sur le disque 💽 (configuration FPM, Crontab...)

@damienalexandre - JoliCode - L'enVar du décor

Dois-je les utiliser ?

​Ça dépend.

  • Infrastructure de production ?
  • Docker 🐳 ?
  • Cloud / Heroku / AWS / GCE ?
  • Mutualisé gratuit chez free.fr ?
  • Info-géreur "moderne" qui "maîtrise" son sujet ?

Parfois obligatoires, parfois impossible, parfois pas la recommandation...

@damienalexandre - JoliCode - L'enVar du décor

Configurez comme vous êtes !

@damienalexandre - JoliCode - L'enVar du décor

On s'y met ?

Dommage pour votre Klout Hacker News 🤓

@damienalexandre - JoliCode - L'enVar du décor

💣 Les pièges 🎃

Nommer les choses

  • Adopter une convention propre à votre application ;
  • Préfixer c'est le bien, le monde Unix le fait :
    • LC_
    • GTK_
    • NODE_…
  • Upper Snake Case : FORUM_PHP.

@damienalexandre - JoliCode - L'enVar du décor

Déclarer les partout

  • PHP-FPM
  • Crontabs
  • Script de déploiement ou de build
  • PHP-CLI...

 

Oublier une variable c'est le crash assuré.

💣 Les pièges 🎃

@damienalexandre - JoliCode - L'enVar du décor

Le préfixe HTTP_

  • PHP expose les headers HTTP dans $_SERVER
    • Ils sont préfixés par "HTTP_"
  • PHP expose les variables d'environnement
    dans $_SERVER (ainsi que $_ENV...)
  • Vous souvenez vous de HTTPoxy ?

💣 Les pièges 🎃

@damienalexandre - JoliCode - L'enVar du décor

Thread Safe

  • La fonction PHP getenv('MY_VAR') 
    n'est pas thread safe ;
  • Dans certaines configurations,
    elle ne retourne pas de résultats ;
  • Lui préférer $_SERVER['MY_VAR'],
    plus rapide et plus fiable !

💣 Les pièges 🎃

@damienalexandre - JoliCode - L'enVar du décor

Type string

  • Les Env Vars sont toujours des strings
  • Attention au type cast PHP 7 !
public function connect(string $hostname, int $port)
{
}

// This will not work properly:
$db->connect($_SERVER['DATABASE_HOSTNAME'], $_SERVER['DATABASE_PORT']);

💣 Les pièges 🎃

@damienalexandre - JoliCode - L'enVar du décor

Mes recommandations

  • Utilisez les env vars si le cœur vous en dit ;
  • Attention à leur scope et aux process enfants ;
  • N'utilisez que $_SERVER pour les lire ;
  • N'y exposer que ce qui change entre environnements ;
  • Implémentez un .env dans la stack locale.

@damienalexandre - JoliCode - L'enVar du décor

💕 Merci l'AFUP 💕

  • Plus d'informations sur notre blog !
  • @damienalexandre

Et vous, comment exposez-vous vos
🔐 secrets 🔐 en production ?

 

Venez me voir à l'apéro communautaire !

Text

Frédéric Bouchery

ISSET
<?php
$isset = 'isset';
var_dump($isset($x));
Fatal error: Uncaught Error:
Call to undefined function isset()

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
var_dump(
   isset(UNKNOWN_CONST)
);
Fatal error: Cannot use isset() on the result of an expression

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
var_dump(
   isset($x = null)
);
Fatal error: Cannot use isset() on the result of an expression

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$v = 'x';
var_dump(isset($$v));
bool(false)

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
var_dump(isset($$v));
bool(false)

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$s = ' ';
var_dump(
   isset(trim($s))
);
Fatal error: Cannot use isset() on the result of an expression

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$s = ' ';
var_dump(
   empty(trim($s))
);
bool(true)

>= PHP 5.5

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
isset($x);
isset($array['a']['b']['c']);
isset($x->prop);

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

Variable existe ?

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$x = null;
var_dump(isset($x));
bool(false)

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

$var !== null
+
notice

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$array = ['belette' => null];
var_dump(
    array_key_exists('belette', $array)
);
<?php
$array = [];
isset($array[$x]);
Notice: Undefined variable: x

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$array = [];
isset($x, $array[$x]);

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$object = new class {
    function __get($name) { return 1; }
};

var_dump(
    isset($object->x),
    $object->x
);
bool(false)

int(1)

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$object = new class {
    function __get($name) { return 1; }
    function __isset($name) { return true; }
};

var_dump(
    isset($object->x),
    $object->x
);
bool(true)

int(1)

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
var_dump($x ?? 'default');
string(7) "default"

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
$page = isset($_GET['page']) ? (int) $_GET['page'] : 0;
$s = isset($_GET['s']) ? (int) $_GET['s'] : 1;

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

<?php
$_GET += [
    'id' => 0,
    'page' => 0,
    's' => 1
];

$id = (int) $_GET['id'];
$p = (int) $_GET['page'];
$s = (int) $_GET['s'];

Secrêts d'isset - @FredBouchery - Figaro-ccmbenchmark

Text

Merci

https://quiz.ccmbg.com

@FredBouchery

Il était une fois le Web: Épisode 1 - Les User agents

Benjamin Clay

LE WEB

Ep1: Les User Agents

Les User Agents

Merci !

Des questions ?

NCSA_Mosaic/2.0

(Windows 3.1)

NCSA_Mosaic/2.0

(Windows 3.1)

Mozilla/1.0

(Win3.1)

Mosaic Killer

NCSA_Mosaic/2.0

(Windows 3.1)

Mozilla/1.0

(Win3.1)

^Mozilla/.*

NCSA_Mosaic/2.0

(Windows 3.1)

Mozilla/1.0

(Win3.1)

^Mozilla/.*

MSIE/2.0

(Windows 95)

NCSA_Mosaic/2.0

(Windows 3.1)

Mozilla/1.0

(Win3.1)

^Mozilla/.*

MSIE/2.0

(Windows 95)

Mozilla/1.22 (compatible; MSIE 2.0; Windows 95)

Mozilla/1.0

(Win3.1)

Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1) Gecko/20020826

Mozilla/1.0

(Win3.1)

Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1) Gecko/20020826

Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0

 

Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040825 Camino/0.8.1

 

Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.8) Gecko/20071008 SeaMonkey/1.0

Mozilla/1.0

(Win3.1)

Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1) Gecko/20020826

Opera/9.51 (Windows NT 5.1; U; en)

Mozilla/1.0

(Win3.1)

Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1) Gecko/20020826

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.51

Opera/9.51 (Windows NT 5.1; U; en)

Mozilla/1.0

(Win3.1)

Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.1) Gecko/20020826

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.51

Mozilla/5.0 (Windows NT 6.0; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51

Opera/9.51 (Windows NT 5.1; U; en)

KHTML

Konqueror

Mozilla/5.0 (compatible; Konqueror/3.2; Linux) KHTML

KHTML

Konqueror

Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)

KHTML

Apple WebKit

Safari

Konqueror

Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5

Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)

KHTML

Apple WebKit

Safari

Konqueror

Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5

Mozilla/5.0 (compatible; Konqueror/3.2; Linux) (KHTML, like Gecko)

Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13

Opera/9.8 (Windows NT 6.0; U; en) Presto/2.2.0

Opera/9.8 (Windows NT 6.0; U; en) Presto/2.2.0

Opera/9.8 (Windows NT 6.0; U; en) Presto/2.2.0

Opera/10.0 (Windows NT 6.0; U; en) Presto/2.2.0

media-queries // polyfills

media-queries // polyfills

HTMLMediaElement.canPlayType()

media-queries // polyfills

HTMLMediaElement.canPlayType()

  • "" (non)

media-queries // polyfills

HTMLMediaElement.canPlayType()

  • "" (non)
  • "probably" 

media-queries // polyfills

HTMLMediaElement.canPlayType()

  • "" (non)
  • "probably" 
  • "maybe" 

Merci !

 

🍻

Workflow

Grégoire Pineau

Quand utiliser un worflow ?

Chacune des étapes est nécessaire et garantit la qualité de l’article (véracité du propos, sourcing, soin de l’écriture et de la formulation…)


Ce circuit de production et de publication est une analogie efficace de ce que l’on peut retrouver dans le code

Garantir la qualité

Pourquoi un composant ?

    public function setStatus($status)
    {
        if ($status === $this->status) {
            return;
        }

        if (self::STATUS_PAID === $this->status) {
            if (self::STATUS_REFUNDED !== $status) {
                throw new \LogicException('Cannot change status of PAID order to anything but REFUNDED.');
            }
        }

        if (self::STATUS_CANCELLED === $this->status) {
            if (self::STATUS_PAID !== $status && self::STATUS_REFUSED !== $status) {
                throw new \LogicException('Cannot change status of CANCELLED order to anything but PAID or REFUSED.');
            }
        }

        if (self::STATUS_REFUSED === $this->status) {
            if (self::STATUS_PAID !== $status && self::STATUS_CANCELLED !== $status) {
                throw new \LogicException('Cannot change status of REFUSED order to anything but PAID or CANCELLED.');
            }
        }

        if (self::STATUS_REFUNDED === $this->status) {
            throw new \LogicException('Cannot change status of a REFUNDED order');
        }

        if (self::STATUS_NEW === $this->status) {
            if (self::STATUS_REFUNDED === $status) {
                throw new \LogicException('Cannot change status of NEW order to REFUNDED.');
            }
        }

        $this->status = $status;
    }

OUPS

Hello Workflow

Un workflow c'est une machine à état (*) qui définie

  • des états:
    • brouillon
    • corrigé
    • publié
  • des transitions:
    • corriger : brouillon -> corrigé
    • publier : relu -> publié

Qu'est ce qu'un workflow ?

* il existe d'autres type de worklow, mais j'ai pas le temps d'en parler ...

À quoi ça ressemble ?

Et dans Symfony ?

$definition = (new DefinitionBuilder())
    ->addPlaces(['brouillon', 'corrigé', 'publié'])
    ->addTransition(new Transition('corriger', 'brouillon', 'corrigé'))
    ->addTransition(new Transition('publier', 'corrigé', 'publié'))
    ->addTransition(new Transition('depublier', 'publié', 'corrigé'))
    ->build()
;

La Definition

Le Marking / MarkingStore

Le Marking est l'objet qui contient la liste des états (*) dans lequel est l'article.

Le MarkingStore est l'object qui s'occupe de convertir le Marking dans le format attendu par l'objet Article :

  • string[]
  • json
  • champs de bytes
  • ...

* Plusieurs états ? Oui, mais je n'ai pas le temps d'en parler ...

$article = new stdClass();
$article->marking = null;

$markingStore = new SingleStateMarkingStore();

$workflow = new Workflow($definition, $markingStore);

Le Workflow

$workflow->can($article, 'corriger'); // => true
$workflow->can($article, 'publier'); // => false
$workflow->can($article, 'depublier'); // => false

Le Workflow::can

$workflow->apply($article, 'corriger');

$workflow->can($article, 'corriger'); // => false
$workflow->can($article, 'publier'); // => true
$workflow->can($article, 'depublier'); // => false

Le Workflow::apply

C'est tout ?

Non, mais on n'a pas le temps !

  • Énormément d'events (EventDispatcher)
    • Pour logger ce qu'il se passe : AuditLog
    • Pour bloquer des transitions : Droits utilisateurs, ...
  • Une intégration avec Twig (moteur de template)
  • Un support des réseaux de Pétri : plusieurs états en même temps
  • Un Graphviz dumper : pour visualiser son workflow
  • Une intégration avec Symfony full stack
  • Une démo en ligne: http://bit.ly/workflow-php go go go
  • Des slides en FR : http://bit.ly/workflow-slide
  • Et plein d'autres choses encore ... mais on n'a pas le temps :(

Merci !

 

🍻

 

@lyrixx

Tirage au sort (part II)

Apéro communautaire

Rendez vous au café oz (3 Place Denfert-Rochereau) à partir de 19h30
Le premier verre et le snack est offert par l'AFUP et Blablacar

Made with Slides.com