]> Raphaël G. Git Repositories - blogbundle/blob - Fixture/BlogFixture.php
Skip extra entries from config flattening
[blogbundle] / Fixture / BlogFixture.php
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Rapsys BlogBundle package.
5 *
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Rapsys\BlogBundle\Fixture;
13
14 use Doctrine\Bundle\FixturesBundle\Fixture;
15 use Doctrine\Persistence\ObjectManager;
16 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
17 use Symfony\Component\DependencyInjection\ContainerInterface;
18
19 use Symfony\Component\PasswordHasher\PasswordHasherInterface;
20 use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory;
21
22 use Rapsys\PackBundle\Util\SluggerUtil;
23
24 use Rapsys\BlogBundle\Entity\Civility;
25 use Rapsys\BlogBundle\Entity\Group;
26 use Rapsys\BlogBundle\Entity\User;
27 use Rapsys\BlogBundle\Entity\UserTranslation;
28 use Rapsys\BlogBundle\Entity\Keyword;
29 use Rapsys\BlogBundle\Entity\KeywordTranslation;
30 use Rapsys\BlogBundle\Entity\Article;
31 use Rapsys\BlogBundle\Entity\ArticleTranslation;
32
33 #use Rapsys\AirBundle\Entity\Location;
34 #use Rapsys\AirBundle\Entity\Slot;
35
36 class BlogFixture extends Fixture implements ContainerAwareInterface {
37 /**
38 * @var ContainerInterface
39 */
40 private ContainerInterface $container;
41
42 /**
43 * @var PasswordHasherFactory
44 */
45 private PasswordHasherFactory $hasher;
46
47 /**
48 * @var Rapsys\PackBundle\Util\SluggerUtil
49 */
50 private SluggerUtil $slugger;
51
52 public function setContainer(ContainerInterface $container = null) {
53 $this->container = $container;
54 $this->hasher = $container->get('security.password_hasher_factory');
55 $this->slugger = $container->get('rapsys_pack.slugger_util');
56 }
57
58 /**
59 * {@inheritDoc}
60 */
61 public function load(ObjectManager $manager) {
62 //Civility tree
63 $civilityTree = [
64 'Mister',
65 'Madam',
66 'Miss'
67 ];
68
69 //Create titles
70 $civilitys = [];
71 foreach($civilityTree as $civilityData) {
72 $civility = new Civility($civilityData);
73 $manager->persist($civility);
74 $civilitys[$civilityData] = $civility;
75 unset($civility);
76 }
77
78 //Group tree
79 //XXX: ROLE_XXX is required by
80 $groupTree = [
81 'User',
82 'Admin'
83 ];
84
85 //Create groups
86 $groups = [];
87 foreach($groupTree as $groupData) {
88 $group = new Group($groupData);
89 $manager->persist($group);
90 $groups[$groupData] = $group;
91 unset($group);
92 }
93
94 //Flush to get the ids
95 $manager->flush();
96
97 //User tree
98 $userTree = [
99 [
100 'civility' => 'Mister',
101 'group' => 'Admin',
102 'mail' => 'blog@rapsys.eu',
103 'password' => 'test',
104 'forename' => 'Raphaël',
105 'surname' => 'Gertz',
106 'active' => true,
107 'disabled' => false,
108 'pseudonym' => 'Rapsys',
109 'slug' => $this->slugger->slug('Raphaël Gertz (rapsys)'),
110 'translations' => [
111 'en_gb' => 'Raphaël Gertz, born in 1984, is a web developper since 2007. Interested in free software, since 2004, when he begin contributing to a linux distribution, known now as Mageia, some path has been traveled since then.',
112 'fr_fr' => 'Raphaël Gertz, né en 1984, est développeur web depuis 2007. Passionné par le monde du logiciel libre, depuis 2004, où il commence à contribuer à une distribution linux, connue maintenant sous le nom Mageia, un certain chemin a été parcouru dès lors.'
113 ]
114 ],
115 ];
116
117 //Create users
118 $users = [];
119 foreach($userTree as $userData) {
120 $user = new User($userData['mail'], $userData['password'], $civilitys[$userData['civility']], $userData['forename'], $userData['surname'], $userData['active'], $userData['disabled'], $userData['pseudonym'], $userData['slug']);
121 #$user->setPassword($this->hasher->hashPassword($user, $userData['password']));
122 $user->addGroup($groups[$userData['group']]);
123 $manager->persist($user);
124 //Flush to get the id
125 $manager->flush();
126 $users[$userData['mail']] = $user;
127 foreach($userData['translations'] as $locale => $description) {
128 $userTranslation = new UserTranslation($users[$userData['mail']], $locale, $description);
129 $manager->persist($userTranslation);
130 unset($userTranslation);
131 }
132 unset($user);
133 }
134
135 //Flush to get the ids
136 $manager->flush();
137
138 //Keyword tree
139 $keywordTree = [
140 'png' => [
141 'en_gb' => [
142 'title' => 'PNG',
143 'description' => 'Portable Network Graphics (PNG) is an raster graphics file open format that supports lossless data compression'
144 ],
145 'fr_fr' => [
146 'title' => 'PNG',
147 'description' => 'Le Portable Network Graphics (PNG) est un format ouvert d’images numériques, qui a été créé pour remplacer le format GIF, à l’époque propriétaire et dont la compression était soumise à un brevet'
148 ]
149 ],
150 'imagick' => [
151 'en_gb' => [
152 'title' => 'Imagick',
153 'description' => 'ImageMagick is a free and open-source software suite for displaying, converting, and editing raster image and vector image files'
154 ],
155 'fr_fr' => [
156 'title' => 'Imagick',
157 'description' => 'Image Magick est une collection de logiciels libres pour afficher, convertir et modifier des images numériques matricielles ou vectorielles dans de nombreux formats'
158 ]
159 ],
160 'image' => [
161 'en_gb' => [
162 'title' => 'Image',
163 'description' => 'An image is an artifact that depicts visual perception, for example, a photo or a two-dimensional picture, that has a similar appearance to some subject'
164 ],
165 'fr_fr' => [
166 'title' => 'Image',
167 'description' => 'Une image est une représentation visuelle, voire mentale, de quelque chose'
168 ]
169 ],
170 'varnish' => [
171 'en_gb' => [
172 'title' => 'Varnish',
173 'description' => 'Varnish is an HTTP cache server deployed as a reverse proxy between applications servers and clients'
174 ],
175 'fr_fr' => [
176 'title' => 'Varnish',
177 'description' => 'Varnish est un serveur de cache HTTP déployé en tant que proxy inverse entre les serveurs d\'application et les clients'
178 ]
179 ],
180 'webservice' => [
181 'en_gb' => [
182 'title' => 'Web service',
183 'description' => 'A web service is a service offered by an electronic device to another electronic device, communicating with each other via the World Wide Web'
184 ],
185 'fr_fr' => [
186 'title' => 'Service web',
187 'description' => 'Un service web, ou service de la toile, est un protocole d\'interface informatique de la famille des technologies web permettant la communication et l\'échange de données entre applications et systèmes hétérogènes'
188 ]
189 ],
190 'rest' => [
191 'en_gb' => [
192 'title' => 'REST',
193 'description' => 'Representational state transfer (REST) or RESTful web services are a way of providing interoperability between computer systems on the Internet'
194 ],
195 'fr_fr' => [
196 'title' => 'REST',
197 'description' => 'Representational state transfer (REST) ou services web RESTful est une manière de fournir de l\'intéropérabilité entre systèmes d\'information sur Internet'
198 ]
199 ],
200 'hateoas' => [
201 'en_gb' => [
202 'title' => 'HATEOAS',
203 'description' => 'HATEOAS, abbreviation of Hypermedia As The Engine Of Application State, is a constraint of the REST application architecture that distinguishes it from other network application architectures'
204 ],
205 'fr_fr' => [
206 'title' => 'HATEOAS',
207 'description' => 'HATEOAS, abréviation d\'Hypermedia As Engine of Application State, Hypermédia en tant que moteur de l\'état d\'application, constitue une contrainte de l\'architecture d\'application REST qui la distingue de la plupart des autres architectures d\'applications réseau'
208 ]
209 ],
210 'uri' => [
211 'en_gb' => [
212 'title' => 'URI',
213 'description' => 'In information technology, a Uniform Resource Identifier (URI) is a string of characters used to identify a resource'
214 ],
215 'fr_fr' => [
216 'title' => 'URI',
217 'description' => 'En technologie de l\'information, une URI, abréviation d\'Uniform Resource Identifier, Identifiant uniforme de ressource, est une chaine de caractères utilisée pour identifier une ressource'
218 ]
219 ],
220 'cidr' => [
221 'en_gb' => [
222 'title' => 'CIDR',
223 'description' => 'Classless Inter-Domain Routing, CIDR, is a method for aggregating IP addresses and route them'
224 ],
225 'fr_fr' => [
226 'title' => 'CIDR',
227 'description' => 'Routage inter-domaine sans classe, de l\'anglais Classless Inter-Domain Routing, CIDR, est une méthode pour agréger des adresses IP et les router'
228 ]
229 ],
230 'amazon' => [
231 'en_gb' => [
232 'title' => 'Amazon',
233 'description' => 'Amazon Elastic Compute Cloud or EC2 is an Amazon server renting service allowing third party to run their own web application'
234 ],
235 'fr_fr' => [
236 'title' => 'Amazon',
237 'description' => 'Amazon Elastic Compute Cloud ou EC2 est un service proposé par Amazon permettant à des tiers de louer des serveurs sur lesquels exécuter leurs propres applications web'
238 ]
239 ],
240 'php' => [
241 'en_gb' => [
242 'title' => 'PHP',
243 'description' => 'PHP: Hypertext Preprocessor, better known as PHP, is an open programming language, used mostly to produce dynamic web pages through an HTTP server'
244 ],
245 'fr_fr' => [
246 'title' => 'PHP',
247 'description' => 'PHP : Hypertext Preprocessor, plus connu sous son sigle PHP, est un langage de programmation libre, principalement utilisé pour produire des pages Web dynamiques via un serveur HTTP'
248 ]
249 ],
250 'mysql' => [
251 'en_gb' => [
252 'title' => 'MySQL',
253 'description' => 'MySQL is an open-source relational database management system, RDBMS'
254 ],
255 'fr_fr' => [
256 'title' => 'MySQL',
257 'description' => 'MySQL est un système de gestion de bases de données relationnelles libre'
258 ]
259 ],
260 'azure' => [
261 'en_gb' => [
262 'title' => 'Azure',
263 'description' => 'Microsoft Azure, formerly Windows Azure, is a cloud computing service created by Microsoft for building, testing, deploying, and managing applications and services through a global network of Microsoft-managed data centers'
264 ],
265 'fr_fr' => [
266 'title' => 'Azure',
267 'description' => 'Microsoft Azure, anciennement Windows Azure, est une plateforme applicative en nuage crée par Microsoft pour construire, tester, déployer et gérer des applications et services sur un réseau global de centres de données opéré par Microsoft'
268 ]
269 ],
270 'microsoft' => [
271 'en_gb' => [
272 'title' => 'Microsoft',
273 'description' => 'Microsoft Corporation is an american multinational technology company, founded in 1975 by Bill Gates and Paul Allen'
274 ],
275 'fr_fr' => [
276 'title' => 'Microsoft',
277 'description' => 'Microsoft Corporation est une multinationale informatique et micro-informatique américaine, fondée en 1975 par Bill Gates et Paul Allen'
278 ]
279 ]
280 ];
281
282 //Create 3 keywords
283 $keywords = [];
284 foreach($keywordTree as $name => $data) {
285 $keyword = new Keyword();
286 $manager->persist($keyword);
287 //Flush to get the id
288 $manager->flush();
289 $keywords[$name] = $keyword;
290 foreach($data as $locale => $translation) {
291 $keywordTranslation = new KeywordTranslation($keywords[$name], $locale, $translation['description'], $this->slugger->slug($translation['title']), $translation['title']);
292 $manager->persist($keywordTranslation);
293 unset($keywordTranslation);
294 }
295 unset($keyword);
296 }
297
298 //Flush to get the ids
299 $manager->flush();
300
301 //Article tree
302 $articleTree = [
303 [
304 'mail' => 'blog@rapsys.eu',
305 'keywords' => ['image', 'imagick', 'png'],
306 'translations' => [
307 'en_gb' => [
308 'title' => 'How to reliably detect PNG image transparency with PHP',
309 'description' => 'I recently had to find out if a PNG has transparency using PHP.
310 All the code I found didn\'t seemed to work correctly for the various kind of PNG I had to deal with.
311 Here is the function I used.',
312 'body' => 'I recently had to find out if a PNG has transparency using PHP.
313 All the code I found didn\'t seemed to work correctly for the various kind of PNG I had to deal with.
314
315 I finished using the following function:
316
317 ```php
318 function png_has_transparency($im) {
319 //Retrieve content from imagick object
320 $content = $im->getImageBlob();
321
322 //Detect 32-bit png (each pixel has tranparency level)
323 if (ord(substr($content, 25, 1)) & 4) {
324 //Fetch iterator
325 $p = $im->getPixelIterator();
326
327 //Loop on each row
328 foreach($p as $r) {
329 //Loop on each row pixel
330 foreach($r as $pix) {
331 //Check if pixel has partial transparency
332 if ($pix->getColorValue(Imagick::COLOR_ALPHA) != 1) {
333 return true;
334 }
335 }
336 }
337 //Check 8-bit png transparency
338 } elseif (stripos($content, \'PLTE\') !== false || stripos($content, \'tRNS\') !== false) {
339 return true;
340 }
341
342 //Didn\'t found clue of transparency
343 return false;
344 }
345 ```
346
347 This function works with the only two transparency possibilities: 8 and 32-bit PNG.
348
349 The first case is a 32-bit PNG with transparency enabled, we have then to check every pixel to detect if it has transparent part or not.
350
351 The second case is a 8-bit PNG, then we only have to look the file content for transparency markers.
352
353 In this function configuration, we only read part of the file in 32-bit PNG until we detect one transparent pixel or parse content until transparency marker is detected in 8-bit PNG.
354
355 The worst case scenario will be 32-bit PNG with transparency flag without transparency or 8-bit PNG without transparency flag.
356
357 Depending on how likely you are to have transparency in each cases you might want to reverse the flow of this function.
358
359 Big thanks to these articles which expains how these parts work in a bit more detail:
360 - <https://www.jonefox.com/blog/2011/04/15/how-to-detect-transparency-in-png-images>
361 - <http://camendesign.com/code/uth1_is-png-32bit>
362 - <https://stackoverflow.com/questions/5495275/how-to-check-if-an-image-has-transparency-using-gd>
363
364 Hope this helps someone else out there.'
365 ],
366 'fr_fr' => [
367 'title' => 'Comment détecter la tranparence dans des images PNG en PHP de manière fiable',
368 'description' => 'J\'ai récemment du trouver comment détecter en PHP les images PNG transparentes.
369 Les codes trouvés ne semblaient pas fonctionner de manière satisfaisante pour les différents types de PNG à contrôler.
370 Voici la fonction que j\'ai fini par utiliser.',
371 'body' => 'J\'ai récemment du trouver comment détecter en PHP les images PNG transparentes.
372 Les codes trouvés ne semblaient pas fonctionner de manière satisfaisante pour les différents types de PNG à contrôler.
373 J\'ai fini par utiliser la fonction suivante:
374
375 ```php
376 function png_has_transparency($im) {
377 //Retrieve content from imagick object
378 $content = $im->getImageBlob();
379
380 //Detect 32bit png (each pixel has tranparency level)
381 if (ord(substr($content, 25, 1)) & 4) {
382 //Fetch iterator
383 $p = $im->getPixelIterator();
384
385 //Loop on each row
386 foreach($p as $r) {
387 //Loop on each row pixel
388 foreach($r as $pix) {
389 //Check if pixel has partial transparency
390 if ($pix->getColorValue(Imagick::COLOR_ALPHA) != 1) {
391 return true;
392 }
393 }
394 }
395 //Check 8bit png transparency
396 } elseif (stripos($content, \'PLTE\') !== false || stripos($content, \'tRNS\') !== false) {
397 return true;
398 }
399
400 //Didn\'t found clue of transparency
401 return false;
402 }
403 ```
404
405 Cette fonction fonctionne avec les deux seules possibilités : PNG 8 et 32 bits.
406
407 Le premier cas est un PNG 32 bits avec transparence activée, on doit alors vérifier l\'opacité de chaque pixel savoir si l\'image a de la transparence ou non.
408
409 Le second cas est un PNG 8 bits, on a simplement à détecter un marqueur de transparence dans le contenu du fichier.
410
411 Dans cette configuration de fonction, on lit seulement une partie du PNG 32 bits jusqu\'à détection d\'un pixel transparent où on analyse le contenu jusqu\'à trouver un marqueur de transparence dans un PNG 8 bits.
412
413 Les pires cas seront un PNG 32 bits avec marqueur de transparence sans pixel transparent ou PNG 8 bits sans marqueur de transparence.
414
415 Selon les probabilités de rencontrer les différents cas de transparence vous pouvez être intéressé pour renverser l\'ordre des tests de cette fonction.
416
417 Un grand merci à ces articles qui expliquent plus en détail comment fonctionnent les différentes parties de ce code:
418 - <https://www.jonefox.com/blog/2011/04/15/how-to-detect-transparency-in-png-images>
419 - <http://camendesign.com/code/uth1_is-png-32bit>
420 - <https://stackoverflow.com/questions/5495275/how-to-check-if-an-image-has-transparency-using-gd>
421
422 En espérant que cela puisse aider quelques personnes.'
423 ]
424 ]
425 ],
426 [
427 'mail' => 'blog@rapsys.eu',
428 'keywords' => ['hateoas', 'rest', 'uri', 'varnish', 'webservice'],
429 'translations' => [
430 'en_gb' => [
431 'title' => 'Caching webservice with varnish',
432 'description' => 'I recently had to find a way to cache a webservice anwsers.
433 Here is the Varnish configuration fitting my needs.',
434 'body' => 'I recently had to find a way to cache a webservice anwsers.
435
436 The webservice is a RESTfull API serving as a gateway between a private HATEOAS API and a client generating more than 500 000 requests a day.
437
438 The first surprise is that if your well educated client, sending you a header Authorization: Bearer, will not be cached by default by Varnish !
439
440 Let\'s force back the standard behaviour with this header for our webservice uri prefix:
441
442 ```varnish
443 sub vcl_recv {
444 # Force cache response even with req.http.Authorization set
445 if (req.http.Authorization) {
446 if (req.url ~ "^/webservice/uri/prefix/") {
447 return (lookup);
448 }
449 }
450 }
451 ```
452
453 This has security implication, because anyone allowed to request varnish will be able to retrieve a cached result without authentification.
454
455 It is important to validate the Authorization header value before serving the result from cache.
456
457 Now, our webservice has three possibles answers :
458 - 200: the data in JSON
459 - 404: data was not found
460 - 410: data is not available anymore
461
462 Let\'s cache our results depending on the reponse code:
463
464 ```varnish
465 sub vcl_fetch {
466 if (req.url ~ "^/webservice/uri/prefix/") {
467 if (beresp.status == 404) {
468 set beresp.ttl = 7d;
469 }
470 if (beresp.status == 410) {
471 set beresp.ttl = 7d;
472 }
473 if (beresp.status == 200) {
474 set beresp.ttl = 24h;
475 }
476 }
477 }
478 ```
479
480 With this configuration, we divided by 5 the quantity of request on our gateway from the client who was not able to cache our result himself.'
481 ],
482 'fr_fr' => [
483 'title' => 'Mise en cache de webservice avec varnish',
484 'description' => 'J\'ai eu récemment à trouver comment mettre en cache les réponses d\'un webservice.
485 Voici la configuration varnish qui a répondu à mes besoins.',
486 'body' => 'J\'ai eu récemment à trouver comment mettre en cache les réponses d\'un webservice.
487
488 L\'API RESTfull du webservice sert de passerelle entre un API privé HATEOAS et un client générant plus de 500 000 requêtes par jour.
489
490 La première surprise est qu\'un client bien élevé, envoyant un en-tête Authorization: Bearer, ne sera pas mis en cache par Varnish par défaut !
491
492 Forçons le fonctionnement standard avec l\'en-tête pour le préfixe de l\'uri de notre webservice:
493
494 ```varnish
495 sub vcl_recv {
496 # Force la mise en cache de la réponse même avec req.http.Authorization présent
497 if (req.http.Authorization) {
498 if (req.url ~ "^/webservice/uri/prefix/") {
499 return (lookup);
500 }
501 }
502 }
503 ```
504
505 Ce changement a des conséquences sur la sécurité, puisque n\'importe quelle personne autorisée à interroger Varnish sera en mesure de récupérer un résultat en cache sans s\'identifier.
506
507 Il est important de valider la valeur de l\'en-tête Authorization avant de fournir le résultat depuis le cache.
508
509 Notre webservice a trois réponses possibles :
510 - 200: les données en JSON
511 - 404: données non trouvées
512 - 410: données plus jamais disponibles
513
514 Mettons en cache les résultats selon le code de retour :
515
516 ```varnish
517 sub vcl_fetch {
518 if (req.url ~ "^/webservice/uri/prefix/") {
519 if (beresp.status == 404) {
520 set beresp.ttl = 7d;
521 }
522 if (beresp.status == 410) {
523 set beresp.ttl = 7d;
524 }
525 if (beresp.status == 200) {
526 set beresp.ttl = 24h;
527 }
528 }
529 }
530 ```
531
532 Avec cette configuration, on a divisé par 5 la quantité de demandes sur notre passerelle pour le client qui n\'était pas en mesure de mettre en cache lui-même nos résultats.'
533 ]
534 ]
535 ],
536 [
537 'mail' => 'blog@rapsys.eu',
538 'keywords' => ['amazon', 'azure', 'cidr', 'microsoft', 'mysql', 'php', 'webservice'],
539 'translations' => [
540 'en_gb' => [
541 'title' => 'Dealing with IP range in PHP/MySQL',
542 'description' => 'I recently had to deal with CIDR blocks to tighten some webservice security.
543 Here is how I designed it to fulfill my needs.',
544 'body' => 'I recently had to deal with CIDR blocks to tighten some webservice security.
545
546 First let\'s see how to compute the first and last address of an IP range with just the block base IP and mask:
547
548 ```php
549 $range = [\'127.0.0.1\', 8];
550 function rangeBegin($range) {
551 return $range[0];
552 }
553 function rangeEnd($range) {
554 return long2ip(ip2long($range[0]) | ((1 << (32 - $range[1])) - 1));
555 }
556 ```
557
558 How to detect if an IP is present in a CIDR block:
559
560 ```php
561 $ip = \'127.0.0.1\';
562 $range = [\'127.0.0.1\', 8];
563 function ipInRange($ip, $range) {
564 if (ip2long($range[0]) <= ip2long($ip) && ip2long($ip) <= (ip2long($range[0]) | ((1 << (32 - $range[1])) - 1))) {
565 return true;
566 }
567 return false;
568 }
569 ```
570
571 As a first bonus, how to retrieve amazon IP ranges:
572
573 ```php
574 function fetchAmazonRange() {
575 //Init array
576 $amazonRanges = [];
577
578 $ctx = stream_context_create(
579 [
580 \'http\' => [
581 \'method\' => \'GET\',
582 \'max_redirects\' => 0,
583 \'timeout\' => 5,
584 \'ignore_errors\' => false,
585 \'header\' => [
586 \'Connection: close\',
587 \'Accept: application/json\'
588 ]
589 ]
590 ]
591 ];
592
593 //Fetch json
594 if (($json = file_get_contents(\'https://ip-ranges.amazonaws.com/ip-ranges.json\', false, $ctx)) === false) {
595 return null;
596 }
597
598 //Decode it
599 if (($json = json_decode($json)) === null || empty($json->prefixes)) {
600 return false;
601 }
602
603 //Deal with prefixes
604 foreach($json->prefixes as $range) {
605 //Skip ipv6 and invalid ranges
606 if (empty($range->ip_prefix)||!preg_match(\'/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/\', $range->ip_prefix, $matche
607 s)) {
608 continue;
609 }
610 //Remove whole match
611 array_shift($matches);
612 //Add ip and mask
613 $amazonRanges[] = $matches;
614 }
615
616 //Send back result
617 return $amazonRanges;
618 }
619 ```
620
621 Microsoft Azure Ip ranges urls:
622 - <https://www.microsoft.com/en-us/download/details.aspx?id=41653>
623 - <https://msdn.microsoft.com/library/mt757330.aspx>'
624 ],
625 'fr_fr' => [
626 'title' => 'Gestion des plages d\'IP en PHP/MySQL',
627 'description' => 'J\'ai eu récemment à trouver comment restreindre l\'accès à un service en ligne à certaines plages d\'IP. Voici la solution qui a répondu à mes besoins.',
628 'body' => 'J\'ai récemment du autoriser l\'accès à un service en ligne à seulement quelques plages d\'IP.
629
630 Premièrement, voyons comment calculer la première et la dernière adresse IP d\'une plage (bloc CIDR) avec sa base et son masque :
631
632 ```php
633 $range = [\'127.0.0.1\', 8];
634 function rangeBegin($range) {
635 return $range[0];
636 }
637 function rangeEnd($range) {
638 return long2ip(ip2long($range[0]) | ((1 << (32 - $range[1])) - 1));
639 }
640 ```
641
642 Maintenant comment vérifier si une IP est présente dans une plage (bloc CIDR) :
643
644 ```php
645 $ip = \'127.0.0.1\';
646 $range = [\'127.0.0.1\', 8];
647 function ipInRange($ip, $range) {
648 if (ip2long($range[0]) <= ip2long($ip) && ip2long($ip) <= (ip2long($range[0]) | ((1 << (32 - $range[1])) - 1))) {
649 return true;
650 }
651 return false;
652 }
653 ```
654
655 En premier bonus, comment récupérer les plages d\'IP d\'amazon :
656
657 ```php
658 function fetchAmazonRange() {
659 //Init array
660 $amazonRanges = [];
661
662 $ctx = stream_context_create(
663 [
664 \'http\' => [
665 \'method\' => \'GET\',
666 \'max_redirects\' => 0,
667 \'timeout\' => 5,
668 \'ignore_errors\' => false,
669 \'header\' => [
670 \'Connection: close\',
671 \'Accept: application/json\'
672 ]
673 ]
674 ]
675 ];
676
677 //Fetch json
678 if (($json = file_get_contents(\'https://ip-ranges.amazonaws.com/ip-ranges.json\', false, $ctx)) === false) {
679 return null;
680 }
681
682 //Decode it
683 if (($json = json_decode($json)) === null || empty($json->prefixes)) {
684 return false;
685 }
686
687 //Deal with prefixes
688 foreach($json->prefixes as $range) {
689 //Skip ipv6 and invalid ranges
690 if (empty($range->ip_prefix)||!preg_match(\'/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/\', $range->ip_prefix, $matche
691 s)) {
692 continue;
693 }
694 //Remove whole match
695 array_shift($matches);
696 //Add ip and mask
697 $amazonRanges[] = $matches;
698 }
699
700 //Send back result
701 return $amazonRanges;
702 }
703 ```
704
705 Urls pour les plages d\'IP de Microsoft Azure :
706 - <https://www.microsoft.com/en-us/download/details.aspx?id=41653>
707 - <https://msdn.microsoft.com/library/mt757330.aspx>'
708 ]
709 ]
710 ],
711 ];
712
713 //Create 3 articles
714 foreach($articleTree as $i => $data) {
715 $article = new Article($users[$data['mail']]);
716 foreach($data['keywords'] as $keyword) {
717 $article->addKeyword($keywords[$keyword]);
718 }
719 $manager->persist($article);
720 //Flush to get the id
721 $manager->flush();
722 $articles[$i] = $article;
723 foreach($data['translations'] as $locale => $translation) {
724 $articleTranslation = new ArticleTranslation($articles[$i], $locale, $translation['body'], $translation['description'], $this->slugger->slug($translation['title']), $translation['title']);
725 $manager->persist($articleTranslation);
726 }
727 unset($article);
728 }
729
730 //Flush to get the ids
731 $manager->flush();
732 }
733 }