Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Unsung Heroes of PHP

5,486 views

Published on

A talk to describe under utilized tools that exist in PHP. Filter_var, iterators, xml libraries

Published in: Technology
  • Be the first to comment

Unsung Heroes of PHP

  1. 1. UNSUNG HEROES OF PHP JAKE SMITHhttp://joind.in/talk/view/2971
  2. 2. Jake Smith[t] @jakefolio[w] http://jakefolio.com[e] me@jakefolio.com
  3. 3. Clean Your Inputs with filter_var();
  4. 4. filter_var/filter_input • Available since PHP 5.2.x • Validate or Sanitize variable/input • Input = GET, POST, ENV, COOKIE, SERVER • The input can not be manipulatedSource: http://www.php.net/manual/en/filter.filters.php
  5. 5. filter_input/filter_has_varCan not add additional fields to filter_inputif ($_POST) { $_POST[additional_field] = "valid string"; $result = filter_input(INPUT_POST, additional_field, FILTER_SANITIZE_STRING); // false $result2 = filter_has_var(INPUT_POST, additional_field); // false}
  6. 6. Filter - Email • FILTER_VALIDATE_EMAIL • FILTER_SANITIZE_EMAIL • Strip all non-email characters • Email standards based on RFC 822Source: http://www.faqs.org/rfcs/rfc822.html
  7. 7. Filter - emailOfficial RFC822 regular expression(?:(?:rn)?[ t])*(?:(?:(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*))*@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*|(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)*<(?:(?:rn)?[ t])*(?:@(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*(?:,@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["(<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*)*:(?:(?:rn)?[ t])*)?(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?(?:rn)?[ t])*))*@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*>(?:(?:rn)?[ t])*)|(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)*:(?:(?:rn)?[ t])*(?:(?:(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*))*@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*|(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)*<(?:(?:rn)?[ t])*(?:@(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*(?:,@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*)*:(?:(?:rn)?[ t])*)?(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*))*@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*>(?:(?:rn)?[ t])*)(?:,s*(?:(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*))*@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*|(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)*<(?:(?:rn)?[ t])*(?:@(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*(?:,@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*)*:(?:(?:rn)?[ t])*)?(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|"(?:[^"r]|.|(?:(?:rn)?[ t]))*"(?:(?:rn)?[ t])*))*@(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*)(?:.(?:(?:rn)?[ t])*(?:[^()<>@,;:".[] 000-031]+(?:(?:(?:rn)?[ t])+|Z|(?=[["()<>@,;:".[]]))|[([^[]r]|.)*](?:(?:rn)?[ t])*))*>(?:(?:rn)?[ t])*))*)?;s*)
  8. 8. Filter - emailValidate email examples: returns string if valid and false on failureif (preg_match(/^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,4})$/, $email)) { echo "Email Good";}// test good email addressecho filter_var("chris@example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Good// test good email addressecho filter_var("chris@a.b.c.example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Good// not allowed . before @echo filter_var("chris.@example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Bad// not allowed .. in domain partecho filter_var("chris@example..com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Bad// not allowed . after @echo filter_var("chris@.example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Bad// not allowed double @echo filter_var("chris@@example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Bad// not allowed @ more than once anywhereecho filter_var("chris@exa@mple.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Bad// must have @echo filter_var("chris#example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // BadSource: http://www.electrictoolbox.com/php-email-validation-filter-var/
  9. 9. Filter - URL • FILTER_VALIDATE_URL • FILTER_SANITIZE_URL • Strip all non-url characters • URL standards based on RFC 2396 • Note that the function will only find ASCII URLs to be valid; internationalized domain names (containing non-ASCII characters) will fail.Source: http://www.faqs.org/rfcs/rfc2396
  10. 10. Filter - urlURLS to be tested for validation$urls = array( http://www.lonestarphp.com, http://www.lonestarphp.com, http://www.lonestarphp.com/blog, http://www.lonestarphp.com/index.html#anchor, http://www.lonestarphp.com/index.html?q=123, lonestarphp.com, www.lonestarphp.com, www.lonestarphp.com/blog, www.lonestarphp.com/index.html?q=123, /index.html?q=123, https://www.lonestarphp.com/, https://localhost, https://localhost/, https://127.0.0.1/, http://.com, http://..., http://, http://ime really trying to break this url!!!"£$"%$&*());
  11. 11. Filter - urlURLS validation combinationsforeach ($urls AS $i => $url) { $result[$i][base] = filter_var($url, FILTER_VALIDATE_URL) ? PASS : FAIL; $result[$i][path_required] = filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED) ?PASS : FAIL; $result[$i][query_required] = filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED) ?PASS : FAIL; $result[$i][path_scheme_required] = filter_var($url, FILTER_VALIDATE_URL,FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_PATH_REQUIRED) ? PASS : FAIL;}
  12. 12. Filter - urlURLS validation results
  13. 13. Filter - String• FILTER_SANITIZE_STRING • Strip tags• Flags: • FILTER_FLAG_NO_ENCODE_QUOTES • FILTER_FLAG_STRIP_LOW / FILTER_FLAG_STRIP_HIGH • FILTER_FLAG_ENCODE_LOW / FILTER_FLAG_ENCODE_HIGH • FILTER_FLAG_ENCODE_AMP
  14. 14. Filter - stringSanitize string utilizing different flags$string = "<strong>tcafén</strong>";// Removes HTML tags (acts like strip_tags())echo filter_var($string, FILTER_SANITIZE_STRING) . "<br>";// This will remove the tab, the line break and HTML tagsecho filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);// This will remove the é and HTML tags.echo filter_var($string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);
  15. 15. Filter - stringASCII TableSource: http://www.asciitable.com/
  16. 16. Filter - urlASCII Extended TableSource: http://www.asciitable.com/
  17. 17. Filter - Boolean• FILTER_VALIDATE_BOOLEAN • returns true for: “yes”, 1, “on”, true • returns false for: “non”, 0, “off”, false
  18. 18. Filter - booleanSanitize string utilizing different flags$data = array( terms_of_service => yes, logged_in_user => true, forged_field => 3523621, opt_in => no);$result = filter_var_array($data, FILTER_VALIDATE_BOOLEAN);var_dump($result);foreach($result AS $key => $val) { if ($val === null) { echo $key . Can Not Validate <br>; } if ($val === false) { echo $key . Failed Validation <br>; }}/* OUTPUTarray(4) { ["terms_of_service"]=> bool(true) ["logged_in_user"]=> bool(true) ["forged_field"]=> bool(false) ["opt_in"]=> bool(false) }*/
  19. 19. Filter - booleanApply filter and flag on each element$result = filter_var_array($data, array( terms_of_service => array( filter => FILTER_VALIDATE_BOOLEAN, flags => FILTER_NULL_ON_FAILURE ), logged_in_user => array( filter => FILTER_VALIDATE_BOOLEAN, flags => FILTER_NULL_ON_FAILURE ), forged_field => array( filter => FILTER_VALIDATE_BOOLEAN, flags => FILTER_NULL_ON_FAILURE ), opt_in => array( filter => FILTER_VALIDATE_BOOLEAN, flags => FILTER_NULL_ON_FAILURE )));var_dump($result);/* OUTPUTarray(4) { ["terms_of_service"]=> bool(true) ["logged_in_user"]=> bool(true) ["forged_field"]=> NULL ["opt_in"]=> bool(false) }*/
  20. 20. Filter - booleanApply filter and flag to all elements with PHP 5.3 closure$result = filter_var_array($data, array_map(function() { return array( filter => FILTER_VALIDATE_BOOLEAN, flags => FILTER_NULL_ON_FAILURE ); }, $data));var_dump($result);/* OUTPUTarray(4) { ["terms_of_service"]=> bool(true) ["logged_in_user"]=> bool(true) ["forged_field"]=> NULL ["opt_in"]=> bool(false) }*/
  21. 21. Filter - Integer• FILTER_VALIDATE_INT• FILTER_SANITIZE_INT • remove all characters except digits and +-
  22. 22. Filter - integerValidate integer using extra options$year = filter_var(2032, FILTER_VALIDATE_INT, array( min_range => 1927, max_range => 2011));
  23. 23. Filter - Float• FILTER_VALIDATE_FLOAT • FILTER_FLAG_ALLOW_THOUSAND• FILTER_SANITIZE_FLOAT • FILTER_FLAG_ALLOW_FRACTION • FILTER_FLAG_ALLOW_SCIENTIFIC
  24. 24. Filter - floatShow different types of validation/sanitization// Removes the , even though its a validate and not a sanitize$totalDonation[] = filter_var(123,523.72, FILTER_VALIDATE_FLOAT, FILTER_FLAG_ALLOW_THOUSAND);// Fails because the ALLOW_THOUSAND flag is not set$totalDonation[] = filter_var(123,523.72, FILTER_VALIDATE_FLOAT);// No sanitization needed$totalDonation[] = filter_var(123,523.72, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_THOUSAND |FILTER_FLAG_ALLOW_FRACTION);// Removes ,$totalDonation[] = filter_var(123,523.72, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);$sciNotation = filter_var(2352e28, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_SCIENTIFIC);foreach($totalDonation AS $donation) { // Failed validation if false returned. if ($donation === false) { echo "FAILED VALIDATION"; } echo $donation . "<br>";}echo $sciNotation;
  25. 25. Putting it all together!
  26. 26. filter_input_arrayBasic Contact Form HTML<form action="" method="post"> <p> <label>First Name</label><br> <input type="text" name="first_name"> </p> <p> <label>Last Name</label><br> <input type="text" name="last_name"> </p> <p> <label>E-mail</label><br> <input type="email" name="email"> </p> <p> <label>Cell Number</label><br> <input type="text" name="cell_phone"> </p> <p> <label>Feedback</label><br> <textarea name="message">Please add feedback</textarea> </p> <p> <label>Disclaimer</label><br> <input type="checkbox" name="disclaimer" value="yes"> Check box for generic disclaimer </p> <p><input type="submit" value="Submit Form"></p></form>
  27. 27. filter_input_arrayBasic Contact Form without filter_input_arrayif ($_POST) { foreach($_POST AS $id => $val) { $_POST[$id] = strip_tags($val); } if (empty($_POST[first_name])) { $errors[] = "First Name is a required field."; } if (empty($_POST[last_name])) { $errors[] = "Last Name is a required field."; } if (!preg_match( /^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,4})$/, $_POST[email])) { $errors[] = "Email is invalid."; } if (!isset($_POST[disclaimer]) || $_POST[disclaimer] != yes) { $errors[] = "You must accept the disclaimer."; }}
  28. 28. Filter - stringBasic Contact Form WITH filter_input_arrayif ($_POST) { $results = filter_input_array(INPUT_POST, array( // Strip Tags first_name => FILTER_SANITIZE_STRING, // Strip Tags last_name => FILTER_SANITIZE_STRING, // Validate Email email => FILTER_VALIDATE_EMAIL, // Strip all non-numeric characters cell_phone => FILTER_SANITIZE_NUMBER_INT, // Strip Tags message => FILTER_SANITIZE_STRING, // Validate Boolean value, return null if can not evaluate to boolean disclaimer => array( filter => FILTER_VALIDATE_BOOLEAN, flags => FILTER_NULL_ON_FAILURE ) )); // Set Errors foreach($results AS $id => $val) { if ($val === NULL || $val === false) { $errors[] = "{$id} is invalid."; } }}
  29. 29. Breaking intoXML with PHP
  30. 30. XML Libraries• SimpleXML• DOMDocument• XMLReader/Writer
  31. 31. XML SectionData Feed (Compliments of BreweryDB.com)$data = <<<XML <beers> <beer> <id>6204</id> <name>"My" Bock</name> <description> Amber, malty and not too heavy, all around favorite even for the drinkers of the yellow fizzy stuff </description> <brewery>1428</brewery> <created>2011-06-01T09:39:12+00:00</created> <updated/> </beer> <beer> <id>7219</id> <name>"Ptarmigan" Pilsner</name> <description> Ptarmigan Pilsner our GABF Silver Medal Winner is A traditional European Style Pilsner with a light hop aroma, smooth malt flavorand a distinctively clean finish. </description> <brewery>64</brewery> <created>2011-02-25T05:40:25+00:00</created> <updated/> </beer> <beer> <id>7218</id> <name>"Wheeler" Wheat</name> <description> Wheeler Wheat is a light and refreshing beer to quench your thirst after a hard day of adventure seeking. An American-style wheatbeer with just a hint of orange peel and coriander, enjoy it with a slice of fruit if you like, we recommend a slice of orange! </description> <brewery>64</brewery> <created>2011-02-25T05:36:45+00:00</created> <updated/> </beer> </beers>XML;
  32. 32. SimpleXML • Tree Parser • Really awesome for quick and dirty reading • Xpath built-inSource: http://us.php.net/manual/en/class.simplexmlelement.php
  33. 33. SimpleXMLRead XML string and inject node//$xml = simplexml_load_file();$xml = simplexml_load_string($data); // $xml = new SimpleXMLElement($data);echo "Enjoy some {$xml->beer[0]->name} <br>";$result = $xml->xpath(//beer[brewery=64]);foreach($result AS $beer) { echo "Found a {$beer->name} <br>";}// Add my brew$myBeer = $xml->addChild(beer);$myBeer->addChild(id, 12252);$myBeer->addChild(name, 512 Pecan Porter);$myBeer->addChild(description, Delicious beer from Austin go try!);$exportedXML = $xml->asXML(); // $xml->saveXML();Source: http://us.php.net/manual/en/class.simplexmlelement.php
  34. 34. SimpleXMLScrape Craigslist - Searching for “leather” under “furniture”$html = new DOMDocument();$html->loadHTML(file_get_contents(http://dallas.craigslist.org/search/fua?query=leather&srchType=A&minAsk=&maxAsk=));$xml = simplexml_import_dom($html);$results = $xml->xpath(//p[@class="row"]);foreach($results as $listing) { // Strip the " -" from the end of the title $title = substr($listing->a, 0, -2); // Get Image filename from HTML id $imagePath = substr( $listing->span[0]->attributes()->id, strpos($listing->span[0]->attributes()->id, :)+1 ); echo <p>; echo ($imagePath) ? <img src="http://images.craigslist.org/ . $imagePath . "> : ; echo $title; echo </p>;}Source: http://us.php.net/manual/en/class.simplexmlelement.php
  35. 35. DOMDocument • Tree Parser • Great at importing HTML/XHTML • Great at modifying/injecting nodes • Xpath built-inSource: http://us.php.net/domdocument
  36. 36. DOMDocumentRead XML string and inject node$newBeer = <<<XML <beer> <id>3252</id> <name>512 Pecan Porter</name> <description> Delicious nutty beer. </description> <brewery>23</brewery> <created>2011-06-11T05:36:45+00:00</created> <updated/> </beer>XML;$xml = new DOMDocument();$xml->loadXML($exportedXML);// Show name of first beer in xml document (from root, no xpath query)echo $xml->getElementsByTagName(beer)->item(0)->getElementsByTagName(name)->item(0)->nodeValue;$xpath = new DOMXpath($xml);$res = $xpath->query(//beer[1]/name);// Show name of first beer in xml document (DOMXpath)echo $res->item(0)->nodeValue;$beerXML = new DOMDocument();$beerXML->loadXML($newBeer);$node = $xml->importNode($beerXML->documentElement, true);$xml->appendChild($node);// $xml->replaceChild();// $xml->removeChild();echo $xml->saveXML();Source: http://us.php.net/domdocument
  37. 37. DOMDocumentScrape Craigslist - Searching for “leather” under “furniture”$html = new DOMDocument();$html->loadHTML(file_get_contents(http://dallas.craigslist.org/search/fua?query=leather&srchType=A&minAsk=&maxAsk=));$xpath = new DOMXpath($html);$result = $xpath->query(//p[@class="row"]);foreach($result AS $listing) { $title = substr($listing->getElementsByTagName(a)->item(0)->nodeValue, 0, -2); $imagePath = $listing->getElementsByTagName(span)->item(0)->getAttribute(id); $imagePath = substr($imagePath, strpos($imagePath, :)+1); echo <p>; echo ($imagePath) ? <img src="http://images.craigslist.org/ . $imagePath . "> : ; echo $title; echo </p>;}Source: http://us.php.net/domdocument
  38. 38. XMLReader/Writer• Pull Parser• Full Steam Ahead - only moves forward• Great for large XML documents• Reads/Writes line by line, small memory footprint
  39. 39. XMLReaderIterate Feed$reader = new XMLReader();$reader->open("http://www.brewerydb.com/api/beers/?apikey={$apiKey}");while($reader->read()) { if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == "beer") { echo "<p>"; } if ($reader->nodeType == XMLReader::ELEMENT || $reader->nodeType == XMLReader::TEXT) { switch($reader->name) { case "id"; case "name"; case "brewery"; case "description"; case "created"; case "updated"; echo $reader->name . ": "; continue; break; default: } if ($reader->nodeType == XMLReader::TEXT && $reader->value) { echo $reader->value . "<br>"; } if ($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == "beer") { echo "</p>"; } }}Source: http://us.php.net/manual/en/class.xmlreader.php
  40. 40. XMLWriterHeaders and Dataheader("Content-Type: text/html/force-download");header("Content-Disposition: attachment; filename=beers.xml");$beerArray = array( 0 => array( id => 12451, name => Shiner 102, brewery => 526, description => Lone Star Approved!, created => 2011-06-11T05:36:45+00:00 ), 1 => array( id => 23551, name => 512 Pecan Porter, brewery => 126, description => A bit nutty, created => 2011-06-11T05:36:45+00:00 ), 2 => array( id => 35351, name => Brooklyn Lager, brewery => 226, description => New York City?, reviews => array( 0 => Great, 1 => Good, 2 => Above Average ), created => 2011-06-11T05:36:45+00:00 ),);Source: http://us.php.net/manual/en/ref.xmlwriter.php
  41. 41. XMLWriterSetupclass XMLRecursiveIteratorIterator extends RecursiveIteratorIterator { protected $xml; public function __construct($it, $flag = RecursiveIteratorIterator::SELF_FIRST, XMLWriter $xml) { parent::__construct($it, $flag); $this->xml = $xml; } public function endChildren() { $this->xml->endElement(); }}$xml = new XMLWriter();$xml->openURI(php://output);$xml->startDocument(1.0, UTF-8);$xml->setIndent(4);Source: http://us.php.net/manual/en/ref.xmlwriter.php
  42. 42. XMLWriterIterationforeach($beers AS $key => $value) { // If back to the top level create new beer if ($beers->getDepth() == 0) { $xml->startElement(beer); continue; } // Change current parent to reviews if ($key == "reviews") { $currentParent = "reviews"; } // Check if current value is a review or not $current = (is_int($key) && $currentParent == "reviews") ? "review" : $key; $xml->startElement($current); // Dont end the element if it is the start of a child list if (!$beers->hasChildren()) { $xml->text($value); $xml->endElement(); }}// Close all open tags$xml->endDocument();Source: http://us.php.net/manual/en/ref.xmlwriter.php
  43. 43. XML Recap - SimpleXML• Great for reading XML• Is Iterable (we’ll talk more on this)• Is NOT the end all be all for XML• Has xpath (tree traversing)
  44. 44. XML Recap - DOMDocument• Great for manipulating XML• Can properly load (X)HTML files• Has xpath (tree traversing)
  45. 45. XML Recap - XMLReader/Writer• Extremely fast• Handles stream context for source• Best used with large XML docs or streams• Forward moving (pull)
  46. 46. 1...Iterator2...Iterator3...Iterator floor();
  47. 47. What is an Iterator? “ An iterator is an object that enables a programmer to traverse a container. Various types of iterators are often provided via a containers interface. ”Source: http://en.wikipedia.org/wiki/Iterator
  48. 48. Quotes in the Community “ PHP also have a lot of awesome features; at least two of them are in my opinion largely underused: Iterators and Streams. Fabien Potencier (Lead Developer of Symfony Project) ”Source: http://fabien.potencier.org/article/44/php-iterators-and-streams-are-awesome
  49. 49. Iterator Interfaces • Traversable • Iterator • RecursiveIterator • Countable • SeekableIteratorSource: http://www.php.net/manual/en/spl.iterators.php
  50. 50. Interface - Iterator Iterator extends Traversable { /* Methods */ abstract public mixed current ( void ) abstract public scalar key ( void ) abstract public void next ( void ) abstract public void rewind ( void ) abstract public boolean valid ( void ) }Source: http://us.php.net/manual/en/class.iterator.php
  51. 51. Interface - RecursiveIterator RecursiveIterator extends Iterator { /* Methods */ public RecursiveIterator getChildren ( void ) public bool hasChildren ( void ) /* Inherited methods */ abstract public mixed Iterator::current ( void ) abstract public scalar Iterator::key ( void ) abstract public void Iterator::next ( void ) abstract public void Iterator::rewind ( void ) abstract public boolean Iterator::valid ( void ) }Source: http://www.php.net/manual/en/spl.iterators.php
  52. 52. DIRECTORY ITERATORS
  53. 53. DirectoryIteratorOutput directory content for Zend Framework$it = new DirectoryIterator(lib/Zend);foreach ($it AS $file) { echo $file->getFilename() . "<br>";}OUTPUT:....DS_StoreAclAcl.phpAmfApplicationApplication.phpAuthAuth.phpBarcodeBarcode.phpCacheCache.phpCaptchaCloudCodeGeneratorConfigConfig.phpConsoleControllerCryptCrypt.phpCurrencyCurrency.phpDateSource: http://us.php.net/manual/en/class.directoryiterator.php
  54. 54. DirectoryIterator - SPLFileInfoMethods available$it = new DirectoryIterator(lib/Zend);foreach ($it AS $file) { echo $file->getFilename() . "<br>";}OUTPUT: /* Methods available for $file public int getATime ( void ) public string getBasename ([ string $suffix ] ) public int getCTime ( void ) public string getExtension ( void ) public SplFileInfo getFileInfo ([ string $class_name ] ) public string getFilename ( void ) public int getGroup ( void ) public int getInode ( void ) public string getLinkTarget ( void ) public int getMTime ( void ) public int getOwner ( void ) public string getPath ( void ) public SplFileInfo getPathInfo ([ string $class_name ] ) public string getPathname ( void ) public int getPerms ( void ) public string getRealPath ( void ) public int getSize ( void ) public string getType ( void ) public bool isDir ( void ) public bool isExecutable ( void ) public bool isFile ( void ) public bool isLink ( void ) public bool isReadable ( void ) public bool isWritable ( void ) */Source: http://us.php.net/manual/en/class.splfileinfo.php
  55. 55. FileSystemIterator (PHP 5.3.x)Output directory content for Zend Framework$it = new FileSystemIterator(lib/Zend);foreach ($it AS $path => $file) { echo $path . " - " . $file->getFilename() . "<br>";}OUTPUT:lib/Zend/.DS_Store - .DS_Storelib/Zend/Acl - Acllib/Zend/Acl.php - Acl.phplib/Zend/Amf - Amflib/Zend/Application - Applicationlib/Zend/Application.php - Application.phplib/Zend/Auth - Authlib/Zend/Auth.php - Auth.phplib/Zend/Barcode - Barcodelib/Zend/Barcode.php - Barcode.phplib/Zend/Cache - Cachelib/Zend/Cache.php - Cache.phplib/Zend/Captcha - Captchalib/Zend/Cloud - Cloudlib/Zend/CodeGenerator - CodeGeneratorlib/Zend/Config - Configlib/Zend/Config.php - Config.phplib/Zend/Console - ConsoleSource: http://us.php.net/manual/en/class.filesystemiterator.php
  56. 56. GlobIterator (PHP 5.3.x)Output directory content for Zend Framework$it = new GlobIterator(lib/Zend/*);foreach ($it AS $path => $file) { echo $path . " - " . $file->getFilename() . "<br>";}OUTPUT:lib/Zend/Acl - Acllib/Zend/Acl.php - Acl.phplib/Zend/Amf - Amflib/Zend/Application - Applicationlib/Zend/Application.php - Application.phplib/Zend/Auth - Authlib/Zend/Auth.php - Auth.phplib/Zend/Barcode - Barcodelib/Zend/Barcode.php - Barcode.phplib/Zend/Cache - Cachelib/Zend/Cache.php - Cache.phplib/Zend/Captcha - Captchalib/Zend/Cloud - Cloudlib/Zend/CodeGenerator - CodeGeneratorlib/Zend/Config - Configlib/Zend/Config.php - Config.phplib/Zend/Console - ConsoleSource: http://us.php.net/manual/en/class.globiterator.php
  57. 57. RecursiveTreeIterator (PHP 5.3.x)Output ASCII view of Directory Structure$it = new RecursiveDirectoryIterator(lib/Zend);foreach (new RecursiveTreeIterator($it) AS $file) { echo $file . "n";}OUTPUT:|-lib/Zend/Acl| |-lib/Zend/Acl/Assert| | -lib/Zend/Acl/Assert/Interface.php| |-lib/Zend/Acl/Exception.php| |-lib/Zend/Acl/Resource| | -lib/Zend/Acl/Resource/Interface.php| |-lib/Zend/Acl/Resource.php| |-lib/Zend/Acl/Role| | |-lib/Zend/Acl/Role/Interface.php| | |-lib/Zend/Acl/Role/Registry| | | -lib/Zend/Acl/Role/Registry/Exception.php| | -lib/Zend/Acl/Role/Registry.php| -lib/Zend/Acl/Role.php|-lib/Zend/Acl.php|-lib/Zend/Amf| |-lib/Zend/Amf/Adobe| | |-lib/Zend/Amf/Adobe/Auth.php| | |-lib/Zend/Amf/Adobe/DbInspector.php| | -lib/Zend/Amf/Adobe/Introspector.php| |-lib/Zend/Amf/Auth| | -lib/Zend/Amf/Auth/Abstract.php| |-lib/Zend/Amf/Constants.php| |-lib/Zend/Amf/Exception.phpSource: http://us.php.net/manual/en/class.recursivetreeiterator.php
  58. 58. FILTER ITERATORS
  59. 59. Problem: Need to view all files in a directory, but it keeps returning Version Control folders (.svn and .git).Source: http://www.php.net/manual/en/spl.iterators.php
  60. 60. FilterIteratorDo not show Version Control foldersclass NoVCSIterator extends FilterIterator{ public function accept() { $file = $this->getInnerIterator()->current(); if ($file->isDir() && ($file->getFilename() == .git || $file->getFilename() == .svn)) { return false; } return true; }}
  61. 61. Problem: I need to see all images that are over 5MB that have been uploaded.Source: http://www.php.net/manual/en/spl.iterators.php
  62. 62. FilterIteratorOnly show images greater than 5MBclass LargeImageFilter extends FilterIterator{ protected $safeImageTypes = array(jpg, gif, png); public function __construct(Iterator $it, $imageTypes) { parent::__construct($it); if (count($imageTypes) > 0) { $this->safeImageTypes = $imageTypes; } } public function accept() { $file = $this->getInnerIterator()->current(); if (in_array($file->getExtension(), $this->safeImageTypes) && $file->getSize() > 5242880) return true; }}$dir = new DirectoryIterator(UPLOADS_PATH);foreach(new LargeImageFilter($dir) AS $file) { echo $file->getFileName();}
  63. 63. RegexIteratorMove integers from front to the back (example from php.net)/** RegexIterator::MATCH* RegexIterator::REPLACE* RegexIterator::ALL_MATCHES* RegexIterator::SPLIT*/$a = new ArrayIterator(array(test1, test2, test3));$it = new RegexIterator($a, /^(test)(d+)/, RegexIterator::REPLACE);$it->replacement = $2:$1;foreach($it AS $el) { echo $el;}Source: http://us3.php.net/manual/en/class.regexiterator.php
  64. 64. Problem: Currently receiving a feed that returns 50 results, but you need to paginate with 10 results per page.Source: http://www.php.net/manual/en/spl.iterators.php
  65. 65. LimitIteratorLimit feed to 10 per page$page = (int) $_GET[page] ?: 1;$perPage = 10;$resultOffset = ($page * $perPage) - $perPage;$it = new ArrayIterator($data);// If the offset is greater than the data an exception is thrown "OutOfBoundsException"try{ foreach(new LimitIterator($it, $resultOffset, $perPage) AS $result) { echo "{$result[name]} <br>"; }} catch (OutOfBoundsException $e) { echo No Records Found;} catch (Exception $e) { echo $e->getMessage();}
  66. 66. Filter Iterators in the wild Symfony2 ChainIterator • CustomFilterIterator • DateRangeFilterIterator • ExcludeDirectoryFilterIterator • FileTypeFilterIterator • FilenameFilterIterator • IgnoreVcsFilterIterator • LimitDepthFilterIterator • SizeRangeFilterIterator • SortableIteratorSource: https://github.com/symfony/symfony/tree/master/src/Symfony/Component/Finder/Iterator
  67. 67. Other Iterators • AppendIterator • Iterate over multiple iterators • Caching Iterator • More of a look ahead, pointer is always one stop behindSource: http://www.php.net/manual/en/spl.iterators.php
  68. 68. Iterator Functions • iterator_to_array • iterator_apply • similar to array_walk • iterator_count • used when iterator doesn’t implement countableSource: http://us.php.net/manual/en/ref.spl.php
  69. 69. Questions? Concerns? Complaints?
  70. 70. Thanks for listening! http://joind.in/talk/view/2971

×