Slide 1

Slide 1 text

DES COMPOSANTS SYMFONY MÉCONNUS QUI VALENT LE DÉTOUR 1

Slide 2

Slide 2 text

ALEXANDRE DAUBOIS Développeur Symfony chez SensioLabs Certifié Symfony 6.0 (Expert Level) Auteur sur Medium Contributeur à Symfony @alexdaubois 2

Slide 3

Slide 3 text

LES COMPOSANTS 4

Slide 4

Slide 4 text

ROBUSTESSE ET RÉTROCOMPATIBILITÉ 5

Slide 5

Slide 5 text

SYMFONY.COM/DOC/CURRENT/CONTRIBUTING/CODE/BC.HTML 6

Slide 6

Slide 6 text

1 4 8

Slide 7

Slide 7 text

AVEZ-VOUS CONFIANCE EN VOS UTILISATRICES ET UTILISATEURS ? 9

Slide 8

Slide 8 text

HTMLSANITIZER 10

Slide 9

Slide 9 text

HTMLSANITIZER Symfony 6.1 (Mai 2022) Expérimental Proposé par Titouan Galopin 11

Slide 10

Slide 10 text

HTML PURIFIER GARDER AU MIEUX L'ARBORESCENCE ORIGINALE DES NOEUDS SUPPRIMER LES DONNÉES POTENTIELLEMENT DANGEREUSES TOP POUR DES DOCUMENTS STRUCTURÉS 12

Slide 11

Slide 11 text

HTML SANITIZER RECONSTRUIRE DU HTML EN EXTRAYANT LES DONNÉES SAFE DE L'INPUT LA STRUCTURE DE BASE PEUT ÊTRE PERDUE TOP POUR DU WYSIWYG PAR EXEMPLE 13

Slide 12

Slide 12 text

HTMLSANITIZERCONFIG use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; $config = (new HtmlSanitizerConfig()) // Autoriser les élements 'h1' dans la sortie ->allowElement('h1') // Retirer les élements 'h2' de la sortie mais garder leurs descendants ->blockElement('h2') // Supprimer les élements 'h3' de la sortie ainsi que l'intégralité de leurs descendants ->dropElement('h3'); 1 2 3 4 5 6 7 8 9 14

Slide 13

Slide 13 text

HTMLSANITIZERCONFIG use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; $config = (new HtmlSanitizerConfig()) // Autoriser les attributs 'data-text' des élements 'h1' ->allowAttribute('data-text', ['h1']) // Retirer les attributs 'data-text' des élements 'h2' ->blockAttribute('data-text', ['h2']) // Forcer tous les liens à s'ouvrir dans un nouvel onglet ->forceAttribute('a', '_target', 'blank'); 1 2 3 4 5 6 7 8 9 15

Slide 14

Slide 14 text

HTMLSANITIZERCONFIG FORCER HTTPS SUR LES URLS ALLOWED LINK SCHEMES / ALLOWED MEDIA SCHEMES ALLOWED LINK HOSTS / ALLOWED MEDIA HOSTS ET BIEN D'AUTRES! 16

Slide 15

Slide 15 text

HTMLSANITIZER use Symfony\Component\HtmlSanitizer\HtmlSanitizer; $config = ...; $sanitizer = new HtmlSanitizer($config); // Context unaware $sanitizer->sanitize($input); /** * Context aware, parmi : * - W3CReference::CONTEXT_HEAD / 'head' * - W3CReference::CONTEXT_BODY / 'body' * - W3CReference::CONTEXT_TEXT / 'text' */ $sanitizer->sanitizeFor($context, $input); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Slide 16

Slide 16 text

W3CREFERENCE DÉFINITION DES CONTEXTES (HEAD, BODY ET TEXT) ÉLÉMENTS ET ATTRIBUTS AUTORISÉS POUR CHAQUE CONTEXTE POUR CHAQUE ÉLÉMENT ET ATTRIBUT : EST-IL SAFE ? 18

Slide 17

Slide 17 text

HTMLSANITIZER 19

Slide 18

Slide 18 text

2 4 21

Slide 19

Slide 19 text

L'ALPHABET LATIN EST AVANTAGÉ. 22

Slide 20

Slide 20 text

STRING 23

Slide 21

Slide 21 text

STRING Symfony 5.0 (Novembre 2019) Manipulation simplifiée des Code points et Grapheme clusters 24

Slide 22

Slide 22 text

CODE POINT GRAPHEME- CLUSTER 25

Slide 23

Slide 23 text

PRENONS COMME EXEMPLE LES EMOJIS. 26

Slide 24

Slide 24 text

🙏 + "MEDIUM SKIN TONE" = 27

Slide 25

Slide 25 text

🙏 + "MEDIUM SKIN TONE" = Code point U+1F64F Code point U+1F3FD Grapheme cluster 28

Slide 26

Slide 26 text

CRÉER DES CHAÎNES // Nouvelle instance de ByteString use function Symfony\Component\String\b; $foo = new ByteString('\xc4\xf5'); $foo = b('\xc3\xf5'); // Nouvelle instance de UnicodeString use function Symfony\Component\String\u; $foo = new UnicodeString('hello'); $foo = u('hello'); // Nouvelle instance de CodePointString $foo = new CodePointString('hello'); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 PAR CONSTRUCTEUR 29

Slide 27

Slide 27 text

CRÉER DES CHAÎNES // Symfony/Component/String/Resources/functions.php namespace Symfony\Component\String; function u(?string $string = ''): UnicodeString { return new UnicodeString($string ?? ''); } function b(?string $string = ''): ByteString { return new ByteString($string ?? ''); } /** * @return UnicodeString|ByteString */ function s(?string $string = ''): AbstractString { $string ??= ''; return preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 30

Slide 28

Slide 28 text

CRÉER DES CHAÎNES $foo = ByteString::fromRandom(length: 10); $foo = UnicodeString::fromCodePoints(0x928, 0x92E, 0x938, 0x94D, 0x924, 0x947); 1 2 3 PAR FACTORIES 31

Slide 29

Slide 29 text

MANIPULER DES CHAÎNES u('https://symfony.com')->startsWith('https'); // True u('iPhone 13 Pro')->endsWith('Pro'); // True u('https://twitter.com/alexdaubois')->containsAny('daubois'); // True u('https://github.com/alexandre-daubois')->replace('alexandre-daubois', 'sensiolabs'); // https://github.com/sensiolabs u('Symfony: le Framework')->camel(); // 'symfonyLeFramework' u('Symfony: le Framework')->snake(); // 'symfony_le_framework' u('SymfonyLive Paris 2022')->truncate(9, '…'); // 'SymfonyLi…' u('0123456789')->chunk(3); // ['012', '345', '678', '9'] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 32

Slide 30

Slide 30 text

INTÉGRATION AVEC TWIG TWIG/STRING-EXTRA (INCLU DANS TWIG/EXTRA-BUNDLE) {# 1) Mise à disposition du filtre 'u' pour manipuler des UnicodeStrings ainsi que toutes leurs méthodes #} {{ 'Lorem ipsum'|u.truncate(8, '...') }} {# Lorem... #} {# 2) Mise à disposition du filtre 'slug' pour utiliser AsciiSlugger #} {{ 'SymfonyLive à Paris !'|slug }} {# symfonylive-a-paris #} 1 2 3 4 5 6 7 33

Slide 31

Slide 31 text

EN BONUS... /** * Un slugger est aussi présent dans le composant */ $slugger = new AsciiSlugger(); $slug = $slugger->slug('Comment utiliser le composant String de Symfony ?'); // $slug = 'comment-utiliser-le-composant-string-de-symfony' /** * Embarque l'ancien composant Inflector */ $inflector = new EnglishInflector(); $result = $inflector->singularize('women'); // ['woman'] $result = $inflector->singularize('radii'); // ['radius'] $result = $inflector->pluralize('news'); // ['news'] $result = $inflector->pluralize('datum'); // ['data'] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ASCIISLUGGER & INFLECTOR 34

Slide 32

Slide 32 text

STRING 35

Slide 33

Slide 33 text

3 4 37

Slide 34

Slide 34 text

AVEZ-VOUS UNE CONFIANCE ABSOLUE ? 38

Slide 35

Slide 35 text

AVEZ-VOUS CONFIANCE ? $myOptions = [ 'host' => 'live.symfony.com', 'port' => -4, 'shceme' => 'http', ]; $defaultOptions = [ 'host' => 'symfony.com', 'scheme' => 'https', 'port' => 12000, 'fragment' => '#anchor', ]; $fullOptions = array_replace($defaultOptions, $options); /** Output : array(5) { ["host"] => 🤩 string(11) "live.symfony.com" ["scheme"] => string(5) "https" ["port"] => 😢 int(-4) ["fragment"] => string(7) "#anchor" ["shceme"] => 😢 string(4) "http" } */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 39

Slide 36

Slide 36 text

OPTIONSRESOLVER 40

Slide 37

Slide 37 text

OPTIONSRESOLVER Symfony 2.1 (Septembre 2012) array_replace de la SPL, mais mieux 41

Slide 38

Slide 38 text

OPTIONSRESOLVER REPLACE, OUI, MAIS PUISSANT ! Valeurs obligatoires Callbacks Validation et typage Dépendance de valeurs entre options Dépréciation d'options Normalization 42

Slide 39

Slide 39 text

OPTIONSRESOLVER VALEURS PAR DÉFAUT, VALEURS OBLIGATOIRES $myOptions = ...; // Un tableau d'option défini par le développeur, par exemple $resolver = new OptionsResolver(); $resolver->setDefaults([ 'host' => 'symfony.com', 'scheme' => 'https', 'port' => function (Options $options) { if ('https' === $options['scheme']) { return 443; } return 80; }, ]); $resolver->setRequired(['fragment', 'protocol_version']); $options = $resolver->resolve($myOptions); // $options est un array 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 43

Slide 40

Slide 40 text

D’AILLEURS… VALEURS PAR DÉFAUT : VOUS LES MANIPULEZ DÉJÀ ! setDefaults([ 'data_class' => User::class, ]); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 44

Slide 41

Slide 41 text

OPTIONSRESOLVER VALIDATION ET OPTIONS DÉPRÉCIÉES $myOptions = ...; // Un tableau d'option défini par le développeur, par exemple $resolver = new OptionsResolver(); // ... $resolver->setAllowedTypes('host', 'string'); $resolver->setAllowedTypes('port', 'int'); // Vous pouvez aussi utiliser 'integer' $resolver->setDeprecated('port', 'phpusla/phpusla', '2.0', 'Specifying the port option is deprecated since 2.0. Use the scheme option instead.'); $options = $resolver->resolve($myOptions); // $options est un array résolu 1 2 3 4 5 6 7 8 9 10 11 45

Slide 42

Slide 42 text

OPTIONSRESOLVER À PROPOS DE LA VALIDATION // Utilisation d'un FQCN $resolver->setAllowedTypes('host', Host::class); // Validation récursive de l'option $resolver->setAllowedTypes('query_parameters', 'string[]'); // Acceptation de plusieurs type (meilleure DX), mais... $resolver->setAllowedTypes('port', ['int', 'null', 'string']); 1 2 3 4 5 6 7 8 46

Slide 43

Slide 43 text

OPTIONSRESOLVER NORMALIZATION $resolver->setAllowedTypes('port', ['int', 'null', 'string']); $resolver->setNormalizer('port', function (Options $options, $value) { if (null === $value) { return 443; } return (int) $value; }); 1 2 3 4 5 6 7 8 9 47

Slide 44

Slide 44 text

OPTIONSRESOLVER 48

Slide 45

Slide 45 text

4 4 50

Slide 46

Slide 46 text

L'INTERNATIONALISATION N'EST PAS (SEULEMENT) DE LA TRADUCTION 51

Slide 47

Slide 47 text

INTL 52

Slide 48

Slide 48 text

INTERNATIONAL COMPONENT FOR UNICODE 53

Slide 49

Slide 49 text

ICU "INTERNATIONAL COMPONENT FOR UNICODE" BIBLIOTHÈQUE C/C++ & JAVA CONSORTIUM UNICODE COLLATOR, TIMEZONE, DATE FORMATTER, NUMBER FORMATTER, LOCALE... ET PLEIN D'AUTRES CHOSES ! 54

Slide 50

Slide 50 text

ICU QUI L'UTILISE ? AMAZON APPLE GOOGLE MICROSOFT IBM ADOBE MOZILLA DEBIAN TOUT LE MONDE. 55

Slide 51

Slide 51 text

C/C++ JAVA ... PHP ? 56

Slide 52

Slide 52 text

INTL Symfony 2.3 (Mai 2013) Translation ≠ Localisation 57

Slide 53

Slide 53 text

INTL LE COMPOSANT DONNE ACCÈS À... Languages Scripts Countries Locales Currencies Time Zones Ça vous dit quelque chose ? 58

Slide 54

Slide 54 text

INTL INTENSÉMENT UTILISÉ PAR LE COMPOSANT FORM LanguageType CountryType LocaleType CurrencyType TimezoneType Et dans Validator aussi ! 59

Slide 55

Slide 55 text

INTL COMMENT L'UTILISER ? // Locale dans laquelle les résultats seront retournés \Locale::setDefault('fr'); Languages::getNames(); // array:595 [..., "am" => "amharique", "fro" => "ancien français", "tzm" => "amazighe de l’Atlas central", ...] Scripts::getNames(); /* array:199 [ ... "Sgnw" => "écriture des signes" "Zsye" => "emoji" "Egyp" => "hiéroglyphes égyptiens" "Maya" => "hiéroglyphes mayas" "Zxxx" => "non écrit" "Zmth" => "notation mathématique" ... ] */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 60

Slide 56

Slide 56 text

INTL COMMENT L'UTILISER ? Countries::getNames(); // [..., "FJ" => "Fidji", "FI" => "Finlande", "FR" => "France", ...] Locales::getNames(); // [..., "nl_SX" => "néerlandais (Saint-Martin [partie néerlandaise])", "nl_SR" => "néerlandais (Suriname)", "ne" => "népalais", ...] Currencies::getNames(); // [..., "EUR" => "euro", "CHE" => "euro WIR", "ANG" => "florin antillais", ...] Timezones::getNames(); // [..., "America/Dawson" => "heure normale du Yukon (Dawson)", "America/Whitehorse" => "heure normale du Yukon (Whitehorse)", "Etc/UTC" => "temps universel coordonné"] 1 2 3 4 5 6 7 8 9 10 11 61

Slide 57

Slide 57 text

INTL EST UN MUST-HAVE 62

Slide 58

Slide 58 text

HTMLSANITIZER STRING OPTIONSRESOLVER INTL 63

Slide 59

Slide 59 text

FAQ 64