]> Raphaël G. Git Repositories - blogbundle/blob - DataFixtures/ORM/Fixtures.php
Fix included template name
[blogbundle] / DataFixtures / ORM / Fixtures.php
1 <?php
2
3 namespace Rapsys\BlogBundle\DataFixtures\ORM;
4
5 #Article.php ArticleTranslation.php Author.php Keyword.php KeywordTranslation.php Language.php Site.php SiteTranslation.php
6
7 class Fixtures extends \Doctrine\Bundle\FixturesBundle\Fixture {
8 public function load(\Doctrine\Common\Persistence\ObjectManager $manager) {
9 //Convert all title to safe slug
10 function slugify($str) {
11 return preg_replace('/[\/_|+ -]+/', '-', strtolower(trim(preg_replace('/[^a-zA-Z0-9\/_|+ -]/', '', str_replace(array('\'', '"'), ' ', iconv('UTF-8', 'ASCII//TRANSLIT', $str))), '-')));
12 }
13 //Language tree
14 $langTree = array(
15 'fr' => array(
16 'iso6391' => 'fr',
17 'iso6393' => 'fra',
18 'locales' => array(
19 'fr' => 'Français',
20 'en' => 'French'
21 )
22 ),
23 'en' => array(
24 'iso6391' => 'en',
25 'iso6393' => 'eng',
26 'locales' => array(
27 'en' => 'English',
28 'fr' => 'Anglais'
29 )
30 )
31 );
32
33 //Create languages
34 $languages = array();
35 foreach($langTree as $langs) {
36 $language = new \Rapsys\BlogBundle\Entity\Language();
37 $language->setIso6391($langs['iso6391']);
38 $language->setIso6393($langs['iso6393']);
39 $language->setCreated(new \DateTime('now'));
40 $language->setUpdated(new \DateTime('now'));
41 $manager->persist($language);
42 $languages[$langs['iso6391']] = $language;
43 unset($language);
44 }
45
46 //Flush to get the ids
47 $manager->flush();
48
49 //Create language translations
50 foreach($langTree as $target => $langs) {
51 foreach($langs['locales'] as $lang => $title) {
52 $languageTranslation = new \Rapsys\BlogBundle\Entity\LanguageTranslation();
53 $languageTranslation->setTitle($title);
54 $languageTranslation->setLanguage($languages[$lang]);
55 $languageTranslation->setLanguageId($languages[$lang]->getId());
56 $languageTranslation->setTarget($languages[$target]);
57 $languageTranslation->setTargetId($languages[$target]->getId());
58 $languageTranslation->setCreated(new \DateTime('now'));
59 $languageTranslation->setUpdated(new \DateTime('now'));
60 $manager->persist($languageTranslation);
61 $manager->flush();
62 unset($languageTranslation);
63 }
64 }
65
66 //Create 3 sites
67 $sites = array();
68 foreach(array('blog.rapsys.eu') as $domain) {
69 $site = new \Rapsys\BlogBundle\Entity\Site();
70 $site->setDomain($domain);
71 $site->setCreated(new \DateTime('now'));
72 $site->setUpdated(new \DateTime('now'));
73 $manager->persist($site);
74 $sites[] = $site;
75 unset($site);
76 }
77
78 //Author tree
79 $authorTree = array(
80 /*'Ernest Hemingway' => array(
81 'fr' => 'Né le 21 juillet 1899 à Oak Park dans l\'Illinois aux États-Unis, mort le 2 juillet 1961 à Ketchum, fût un écrivain, journaliste et correspondant de guerre américain.',
82 'en' => 'Born on July 21, 1899 in Oak Park, Illinois, deceased on July 2, 1961 in Ketchum, was an American novelist, short story writer and journalist.'
83 ),
84 'William Shakespeare' => array(
85 'fr' => 'Baptisé le 26 avril 1564 à Stratford-upon-Avon et mort le 23 avril 1616 dans la même ville, est considéré comme l\'un des plus grands poètes, dramaturges et écrivains de la culture anglaise.',
86 'en' => 'Baptised on April 26, 1564, deceased on April 23, 1616, was an English poet, playwright and actor, widely regarded as the greatest writer in the English language and the world\'s pre-eminent dramatist.'
87 ),
88 'George Orwell' => array(
89 'fr' => 'Eric Arthur Blair, né le 25 juin 1903 à Motihari pendant la période du Raj britannique et mort le 21 janvier 1950 à Londres, plus connu sous son nom de plume, est un écrivain et journaliste anglais.',
90 'en' => 'Eric Arthur Blair, born on June 25, 1903, deceased on January 21, 1950, better known by his pen name, was an English novelist, essayist, journalist, and critic.'
91 )*/
92 'raphaël g.' => array(
93 'fr' => 'Raphaël G., 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.',
94 'en' => 'Raphaël G., 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.'
95 )
96 );
97
98 //Create 3 authors
99 $authors = array();
100 foreach($authorTree as $name => $data) {
101 $author = new \Rapsys\BlogBundle\Entity\Author();
102 $author->setName($name);
103 $author->setSlug(slugify($name));
104 $author->setCreated(new \DateTime('now'));
105 $author->setUpdated(new \DateTime('now'));
106 $manager->persist($author);
107 //Flush to get the id
108 $manager->flush();
109 $authors[] = $author;
110 foreach($data as $lang => $description) {
111 $authorTranslation = new \Rapsys\BlogBundle\Entity\AuthorTranslation();
112 $authorTranslation->setDescription($description);
113 $authorTranslation->setAuthor($author);
114 $authorTranslation->setAuthorId($author->getId());
115 $authorTranslation->setLanguage($languages[$lang]);
116 $authorTranslation->setLanguageId($languages[$lang]->getId());
117 $authorTranslation->setCreated(new \DateTime('now'));
118 $authorTranslation->setUpdated(new \DateTime('now'));
119 $manager->persist($authorTranslation);
120 }
121 unset($author);
122 }
123
124 //Keyword tree
125 $keywordTree = array(
126 'png' => array(
127 'fr' => array(
128 'title' => 'PNG',
129 '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'
130 ),
131 'en' => array(
132 'title' => 'PNG',
133 'description' => 'Portable Network Graphics (PNG) is an raster graphics file open format that supports lossless data compression'
134 )
135 ),
136 'imagick' => array(
137 'fr' => array(
138 'title' => 'Imagick',
139 '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'
140 ),
141 'en' => array(
142 'title' => 'Imagick',
143 'description' => 'ImageMagick is a free and open-source software suite for displaying, converting, and editing raster image and vector image files'
144 )
145 ),
146 'image' => array(
147 'fr' => array(
148 'title' => 'Image',
149 'description' => 'Une image est une représentation visuelle, voire mentale, de quelque chose'
150 ),
151 'en' => array(
152 'title' => 'Image',
153 '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'
154 )
155 ),
156 'varnish' => array(
157 'fr' => array(
158 'title' => 'Varnish',
159 'description' => 'Varnish est un serveur de cache HTTP déployé en tant que proxy inverse entre les serveurs d\'application et les clients'
160 ),
161 'en' => array(
162 'title' => 'Varnish',
163 'description' => 'Varnish is an HTTP cache server deployed as a reverse proxy between applications servers and clients'
164 )
165 ),
166 'webservice' => array(
167 'fr' => array(
168 'title' => 'Service web',
169 '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'
170 ),
171 'en' => array(
172 'title' => 'Web service',
173 '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'
174 )
175 ),
176 'rest' => array(
177 'fr' => array(
178 'title' => 'REST',
179 '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'
180 ),
181 'en' => array(
182 'title' => 'REST',
183 'description' => 'Representational state transfer (REST) or RESTful web services are a way of providing interoperability between computer systems on the Internet'
184 )
185 ),
186 'hateoas' => array(
187 'fr' => array(
188 'title' => 'HATEOAS',
189 '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'
190 ),
191 'en' => array(
192 'title' => 'HATEOAS',
193 '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'
194 )
195 ),
196 'uri' => array(
197 'fr' => array(
198 'title' => 'URI',
199 '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'
200 ),
201 'en' => array(
202 'title' => 'URI',
203 'description' => 'In information technology, a Uniform Resource Identifier (URI) is a string of characters used to identify a resource'
204 )
205 ),
206 'cidr' => array(
207 'fr' => array(
208 'title' => 'CIDR',
209 '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'
210 ),
211 'en' => array(
212 'title' => 'CIDR',
213 'description' => 'Classless Inter-Domain Routing, CIDR, is a method for aggregating IP addresses and route them'
214 )
215 ),
216 'amazon' => array(
217 'fr' => array(
218 'title' => 'Amazon',
219 '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'
220 ),
221 'en' => array(
222 'title' => 'Amazon',
223 'description' => 'Amazon Elastic Compute Cloud or EC2 is an Amazon server renting service allowing third party to run their own web application'
224 )
225 ),
226 'php' => array(
227 'fr' => array(
228 'title' => 'PHP',
229 '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'
230 ),
231 'en' => array(
232 'title' => 'PHP',
233 'description' => 'PHP: Hypertext Preprocessor, better known as PHP, is an open programming language, used mostly to produce dynamic web pages through an HTTP server'
234 )
235 ),
236 'mysql' => array(
237 'fr' => array(
238 'title' => 'MySQL',
239 'description' => 'MySQL est un système de gestion de bases de données relationnelles libre'
240 ),
241 'en' => array(
242 'title' => 'MySQL',
243 'description' => 'MySQL is an open-source relational database management system, RDBMS'
244 )
245 ),
246 'azure' => array(
247 'fr' => array(
248 'title' => 'Azure',
249 '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'
250 ),
251 'en' => array(
252 'title' => 'Azure',
253 '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'
254 )
255 ),
256 'microsoft' => array(
257 'fr' => array(
258 'title' => 'Microsoft',
259 'description' => 'Microsoft Corporation est une multinationale informatique et micro-informatique américaine, fondée en 1975 par Bill Gates et Paul Allen'
260 ),
261 'en' => array(
262 'title' => 'Microsoft',
263 'description' => 'Microsoft Corporation is an american multinational technology company, founded in 1975 by Bill Gates and Paul Allen'
264 )
265 )
266 );
267
268 //Create 3 keywords
269 $keywords = array();
270 foreach($keywordTree as $name => $data) {
271 $keyword = new \Rapsys\BlogBundle\Entity\Keyword();
272 $keyword->setCreated(new \DateTime('now'));
273 $keyword->setUpdated(new \DateTime('now'));
274 $manager->persist($keyword);
275 //Flush to get the id
276 $manager->flush();
277 $keywords[$name] = $keyword;
278 foreach($data as $lang => $datas) {
279 $keywordTranslation = new \Rapsys\BlogBundle\Entity\KeywordTranslation();
280 $keywordTranslation->setTitle($datas['title']);
281 $keywordTranslation->setSlug(slugify($datas['title']));
282 $keywordTranslation->setDescription($datas['description']);
283 $keywordTranslation->setKeyword($keyword);
284 $keywordTranslation->setKeywordId($keyword->getId());
285 $keywordTranslation->setLanguage($languages[$lang]);
286 $keywordTranslation->setLanguageId($languages[$lang]->getId());
287 $keywordTranslation->setCreated(new \DateTime('now'));
288 $keywordTranslation->setUpdated(new \DateTime('now'));
289 $manager->persist($keywordTranslation);
290 }
291 unset($keyword);
292 }
293
294 //Article tree
295 $articleTree = array(
296 array(
297 'keywords' => array('image', 'imagick', 'png'),
298 'fr' => array(
299 'title' => 'Comment détecter la tranparence dans des images PNG en PHP de manière fiable',
300 'description' => 'J\'ai récemment du trouver comment détecter en PHP les images PNG transparentes.
301 Les codes trouvés ne semblaient pas fonctionner de manière satisfaisante pour les différents types de PNG à contrôler.
302 Voici la fonction que j\'ai fini par utiliser.',
303 'body' => 'J\'ai récemment du trouver comment détecter en PHP les images PNG transparentes.
304 Les codes trouvés ne semblaient pas fonctionner de manière satisfaisante pour les différents types de PNG à contrôler.
305 J\'ai fini par utiliser la fonction suivante:
306 [code=php]
307 function png_has_transparency($im) {
308 //Retrieve content from imagick object
309 $content = $im->getImageBlob();
310
311 //Detect 32bit png (each pixel has tranparency level)
312 if (ord(substr($content, 25, 1)) & 4) {
313 //Fetch iterator
314 $p = $im->getPixelIterator();
315
316 //Loop on each row
317 foreach($p as $r) {
318 //Loop on each row pixel
319 foreach($r as $pix) {
320 //Check if pixel has partial transparency
321 if ($pix->getColorValue(Imagick::COLOR_ALPHA) != 1) {
322 return true;
323 }
324 }
325 }
326 //Check 8bit png transparency
327 } elseif (stripos($content, \'PLTE\') !== false || stripos($content, \'tRNS\') !== false) {
328 return true;
329 }
330
331 //Didn\'t found clue of transparency
332 return false;
333 }
334 [/code]
335
336 Cette fonction fonctionne avec les deux seules possibilités : PNG 8 et 32 bits.
337
338 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.
339
340 Le second cas est un PNG 8 bits, on a simplement à détecter un marqueur de transparence dans le contenu du fichier.
341
342 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.
343
344 Les pires cas seront un PNG 32 bits avec marqueur de transparence sans pixel transparent ou PNG 8 bits sans marqueur de transparence.
345
346 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.
347
348 Un grand merci à ces articles qui expliquent plus en détail comment fonctionnent les différentes parties de ce code:
349 [ul]
350 [li][url]https://www.jonefox.com/blog/2011/04/15/how-to-detect-transparency-in-png-images[/url][/li]
351 [li][url]http://camendesign.com/code/uth1_is-png-32bit[/url][/li]
352 [li][url]https://stackoverflow.com/questions/5495275/how-to-check-if-an-image-has-transparency-using-gd[/url][/li]
353 [/ul]
354
355 En espérant que cela puisse aider quelques personnes.'
356 ),
357 'en' => array(
358 'title' => 'How to reliably detect PNG image transparency with PHP',
359 'description' => 'I recently had to find out if a PNG has transparency using PHP.
360 All the code I found didn\'t seemed to work correctly for the various kind of PNG I had to deal with.
361 Here is the function I used.',
362 'body' => 'I recently had to find out if a PNG has transparency using PHP.
363 All the code I found didn\'t seemed to work correctly for the various kind of PNG I had to deal with.
364
365 I finished using the following function:
366 [code=php]
367 function png_has_transparency($im) {
368 //Retrieve content from imagick object
369 $content = $im->getImageBlob();
370
371 //Detect 32-bit png (each pixel has tranparency level)
372 if (ord(substr($content, 25, 1)) & 4) {
373 //Fetch iterator
374 $p = $im->getPixelIterator();
375
376 //Loop on each row
377 foreach($p as $r) {
378 //Loop on each row pixel
379 foreach($r as $pix) {
380 //Check if pixel has partial transparency
381 if ($pix->getColorValue(Imagick::COLOR_ALPHA) != 1) {
382 return true;
383 }
384 }
385 }
386 //Check 8-bit png transparency
387 } elseif (stripos($content, \'PLTE\') !== false || stripos($content, \'tRNS\') !== false) {
388 return true;
389 }
390
391 //Didn\'t found clue of transparency
392 return false;
393 }
394 [/code]
395
396 This function works with the only two transparency possibilities: 8 and 32-bit PNG.
397
398 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.
399
400 The second case is a 8-bit PNG, then we only have to look the file content for transparency markers.
401
402 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.
403
404 The worst case scenario will be 32-bit PNG with transparency flag without transparency or 8-bit PNG without transparency flag.
405
406 Depending on how likely you are to have transparency in each cases you might want to reverse the flow of this function.
407
408 Big thanks to these articles which expains how these parts work in a bit more detail:
409 [ul]
410 [li][url]https://www.jonefox.com/blog/2011/04/15/how-to-detect-transparency-in-png-images[/url][/li]
411 [li][url]http://camendesign.com/code/uth1_is-png-32bit[/url][/li]
412 [li][url]https://stackoverflow.com/questions/5495275/how-to-check-if-an-image-has-transparency-using-gd[/url][/li]
413 [/ul]
414
415 Hope this helps someone else out there.'
416 )
417 ),
418 array(
419 'keywords' => array('hateoas', 'rest', 'uri', 'varnish', 'webservice'),
420 'fr' => array(
421 'title' => 'Mise en cache de webservice avec varnish',
422 'description' => 'J\'ai eu récemment à trouver comment mettre en cache les réponses d\'un webservice.
423 Voici la configuration varnish qui a répondu à mes besoins.',
424 'body' => 'J\'ai eu récemment à trouver comment mettre en cache les réponses d\'un webservice.
425
426 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.
427
428 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 !
429
430 Forçons le fonctionnement standard avec l\'en-tête pour le préfixe de l\'uri de notre webservice:
431 [code=varnish]
432 sub vcl_recv {
433 # Force la mise en cache de la réponse même avec req.http.Authorization présent
434 if (req.http.Authorization) {
435 if (req.url ~ "^/webservice/uri/prefix/") {
436 return (lookup);
437 }
438 }
439 }
440 [/code]
441
442 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.
443
444 Il est important de valider la valeur de l\'en-tête Authorization avant de fournir le résultat depuis le cache.
445
446 Notre webservice a trois réponses possibles :
447 [ul]
448 [li]200: les données en JSON[/li]
449 [li]404: données non trouvées[/li]
450 [li]410: données plus jamais disponibles[/li]
451 [/ul]
452
453 Mettons en cache les résultats selon le code de retour :
454 [code=varnish]
455 sub vcl_fetch {
456 if (req.url ~ "^/webservice/uri/prefix/") {
457 if (beresp.status == 404) {
458 set beresp.ttl = 7d;
459 }
460 if (beresp.status == 410) {
461 set beresp.ttl = 7d;
462 }
463 if (beresp.status == 200) {
464 set beresp.ttl = 24h;
465 }
466 }
467 }
468 [/code]
469
470 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.'
471 ),
472 'en' => array(
473 'title' => 'Caching webservice with varnish',
474 'description' => 'I recently had to find a way to cache a webservice anwsers.
475 Here is the Varnish configuration fitting my needs.',
476 'body' => 'I recently had to find a way to cache a webservice anwsers.
477
478 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.
479
480 The first surprise is that if your well educated client, sending you a header Authorization: Bearer, will not be cached by default by Varnish !
481
482 Let\'s force back the standard behaviour with this header for our webservice uri prefix:
483 [code=varnish]
484 sub vcl_recv {
485 # Force cache response even with req.http.Authorization set
486 if (req.http.Authorization) {
487 if (req.url ~ "^/webservice/uri/prefix/") {
488 return (lookup);
489 }
490 }
491 }
492 [/code]
493
494 This has security implication, because anyone allowed to request varnish will be able to retrieve a cached result without authentification.
495
496 It is important to validate the Authorization header value before serving the result from cache.
497
498 Now, our webservice has three possibles answers :
499 [ul]
500 [li]200: the data in JSON[/li]
501 [li]404: data was not found[/li]
502 [li]410: data is not available anymore[/li]
503 [/ul]
504
505 Let\'s cache our results depending on the reponse code:
506 [code=varnish]
507 sub vcl_fetch {
508 if (req.url ~ "^/webservice/uri/prefix/") {
509 if (beresp.status == 404) {
510 set beresp.ttl = 7d;
511 }
512 if (beresp.status == 410) {
513 set beresp.ttl = 7d;
514 }
515 if (beresp.status == 200) {
516 set beresp.ttl = 24h;
517 }
518 }
519 }
520 [/code]
521
522 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.'
523 )
524 ),
525 array(
526 'keywords' => array('amazon', 'azure', 'cidr', 'microsoft', 'mysql', 'php', 'webservice'),
527 'fr' => array(
528 'title' => 'Gestion des plages d\'IP en PHP/MySQL',
529 '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.',
530 'body' => 'J\'ai récemment du autoriser l\'accès à un service en ligne à seulement quelques plages d\'IP.
531
532 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 :
533 [code=php]
534 $range = array(\'127.0.0.1\', 8);
535 function rangeBegin($range) {
536 return $range[0];
537 }
538 function rangeEnd($range) {
539 return long2ip(ip2long($range[0]) | ((1 << (32 - $range[1])) - 1));
540 }
541 [/code]
542
543 Maintenant comment vérifier si une IP est présente dans une plage (bloc CIDR) :
544 [code=php]
545 $ip = \'127.0.0.1\';
546 $range = array(\'127.0.0.1\', 8);
547 function ipInRange($ip, $range) {
548 if (ip2long($range[0]) <= ip2long($ip) && ip2long($ip) <= (ip2long($range[0]) | ((1 << (32 - $range[1])) - 1))) {
549 return true;
550 }
551 return false;
552 }
553 [/code]
554
555 En premier bonus, comment récupérer les plages d\'IP d\'amazon :
556 [code=php]
557 function fetchAmazonRange() {
558 //Init array
559 $amazonRanges = array();
560
561 $ctx = stream_context_create(
562 array(
563 \'http\' => array(
564 \'method\' => \'GET\',
565 \'max_redirects\' => 0,
566 \'timeout\' => 5,
567 \'ignore_errors\' => false,
568 \'header\' => array(
569 \'Connection: close\',
570 \'Accept: application/json\'
571 )
572 )
573 )
574 );
575
576 //Fetch json
577 if (($json = file_get_contents(\'https://ip-ranges.amazonaws.com/ip-ranges.json\', false, $ctx)) === false) {
578 return null;
579 }
580
581 //Decode it
582 if (($json = json_decode($json)) === null || empty($json->prefixes)) {
583 return false;
584 }
585
586 //Deal with prefixes
587 foreach($json->prefixes as $range) {
588 //Skip ipv6 and invalid ranges
589 if (empty($range->ip_prefix)||!preg_match(\'/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/\', $range->ip_prefix, $matche
590 s)) {
591 continue;
592 }
593 //Remove whole match
594 array_shift($matches);
595 //Add ip and mask
596 $amazonRanges[] = $matches;
597 }
598
599 //Send back result
600 return $amazonRanges;
601 }
602 [/code]
603
604 Urls pour les plages d\'IP de Microsoft Azure :
605 [ul]
606 [li][url]https://www.microsoft.com/en-us/download/details.aspx?id=41653[/url][/li]
607 [li][url]https://msdn.microsoft.com/library/mt757330.aspx[/url][/li]
608 [/ul]'
609 ),
610 'en' => array(
611 'title' => 'Dealing with IP range in PHP/MySQL',
612 'description' => 'I recently had to deal with CIDR blocks to tighten some webservice security.
613 Here is how I designed it to fulfill my needs.',
614 'body' => 'I recently had to deal with CIDR blocks to tighten some webservice security.
615
616 First let\'s see how to compute the first and last address of an IP range with just the block base IP and mask:
617 [code=php]
618 $range = array(\'127.0.0.1\', 8);
619 function rangeBegin($range) {
620 return $range[0];
621 }
622 function rangeEnd($range) {
623 return long2ip(ip2long($range[0]) | ((1 << (32 - $range[1])) - 1));
624 }
625 [/code]
626
627 How to detect if an IP is present in a CIDR block:
628 [code=php]
629 $ip = \'127.0.0.1\';
630 $range = array(\'127.0.0.1\', 8);
631 function ipInRange($ip, $range) {
632 if (ip2long($range[0]) <= ip2long($ip) && ip2long($ip) <= (ip2long($range[0]) | ((1 << (32 - $range[1])) - 1))) {
633 return true;
634 }
635 return false;
636 }
637 [/code]
638
639 As a first bonus, how to retrieve amazon IP ranges:
640 [code=php]
641 function fetchAmazonRange() {
642 //Init array
643 $amazonRanges = array();
644
645 $ctx = stream_context_create(
646 array(
647 \'http\' => array(
648 \'method\' => \'GET\',
649 \'max_redirects\' => 0,
650 \'timeout\' => 5,
651 \'ignore_errors\' => false,
652 \'header\' => array(
653 \'Connection: close\',
654 \'Accept: application/json\'
655 )
656 )
657 )
658 );
659
660 //Fetch json
661 if (($json = file_get_contents(\'https://ip-ranges.amazonaws.com/ip-ranges.json\', false, $ctx)) === false) {
662 return null;
663 }
664
665 //Decode it
666 if (($json = json_decode($json)) === null || empty($json->prefixes)) {
667 return false;
668 }
669
670 //Deal with prefixes
671 foreach($json->prefixes as $range) {
672 //Skip ipv6 and invalid ranges
673 if (empty($range->ip_prefix)||!preg_match(\'/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/\', $range->ip_prefix, $matche
674 s)) {
675 continue;
676 }
677 //Remove whole match
678 array_shift($matches);
679 //Add ip and mask
680 $amazonRanges[] = $matches;
681 }
682
683 //Send back result
684 return $amazonRanges;
685 }
686 [/code]
687
688 Microsoft Azure Ip ranges urls:
689 [ul]
690 [li][url]https://www.microsoft.com/en-us/download/details.aspx?id=41653[/url][/li]
691 [li][url]https://msdn.microsoft.com/library/mt757330.aspx[/url][/li]
692 [/ul]'
693 )
694 ),
695 );
696
697 //Create 3 articles
698 foreach($articleTree as $i => $data) {
699 $article = new \Rapsys\BlogBundle\Entity\Article();
700 $article->setCreated(new \DateTime('now'));
701 $article->setUpdated(new \DateTime('now'));
702 foreach($data['keywords'] as $keyword) {
703 $article->addKeyword($keywords[$keyword]);
704 }
705 unset($data['keywords']);
706 $article->setSite($sites[0]);
707 $article->setAuthor($authors[0]);
708 $manager->persist($article);
709 //Flush to get the id
710 $manager->flush();
711 $articles[] = $article;
712 foreach($data as $lang => $datas) {
713 $articleTranslation = new \Rapsys\BlogBundle\Entity\ArticleTranslation();
714 $articleTranslation->setTitle($datas['title']);
715 $articleTranslation->setSlug(slugify($datas['title']));
716 $articleTranslation->setDescription($datas['description']);
717 $articleTranslation->setBody($datas['body']);
718 $articleTranslation->setArticle($article);
719 $articleTranslation->setArticleId($article->getId());
720 $articleTranslation->setLanguage($languages[$lang]);
721 $articleTranslation->setLanguageId($languages[$lang]->getId());
722 $articleTranslation->setCreated(new \DateTime('now'));
723 $articleTranslation->setUpdated(new \DateTime('now'));
724 $manager->persist($articleTranslation);
725 }
726 unset($article);
727 }
728
729 $manager->flush();
730 }
731 }
732
733 //TODO:
734 //- add disqus article
735 //- add code for ip range detection
736 //- add code for amazon ip range detection
737 //- add code for microsoft ip range detection
738 //- add ??? article*/
739 //
740 //- add article ihttpd
741 //- add article distgen
742 //- add article distcook
743 //- add article install
744 //
745 //while [ ! -z "$(pidof dd)" ]; do killall -USR1 dd; sleep 300; done; echo 'Server ready' | mail -r 'aurae@rapsys.eu' -s 'Server ready' aurae@rapsys.eu
746
747
748 /*
749 Pour l'article sur distgen, un coup d'explication sur le perl
750
751 #! /usr/bin/perl
752
753 use strict;
754 use warnings;
755
756 use Socket qw(AF_INET inet_ntop inet_pton);
757
758 my ($ip, $mask) = @ARGV;
759
760 # binmask
761 #print (2**$mask-1)<<(32-$mask), "\n";
762
763 # first ip
764 #print Socket::inet_ntop(Socket::AF_INET, pack('N', unpack('N', Socket::inet_pton(Socket::AF_INET, $ip)) & (2**$mask-1)<<(32-$mask))), "\n";
765
766 # doted mask
767 #print join('.', unpack('C4', pack('N', (2**$mask-1)<<(32-$mask)))), "\n";
768
769 # last ip
770 #print Socket::inet_ntop(Socket::AF_INET, pack('N', unpack('N', Socket::inet_pton(Socket::AF_INET, $ip)) | (2**(32 - $mask)))), "\n";
771
772 */