Unsung Heroes of PHP
Upcoming SlideShare
Loading in...5
×
 

Unsung Heroes of PHP

on

  • 3,905 views

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

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

Statistics

Views

Total Views
3,905
Views on SlideShare
3,904
Embed Views
1

Actions

Likes
5
Downloads
42
Comments
0

1 Embed 1

https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Unsung Heroes of PHP Unsung Heroes of PHP Presentation Transcript

  • UNSUNG HEROES OF PHP JAKE SMITHhttp://joind.in/talk/view/2971
  • Jake Smith[t] @jakefolio[w] http://jakefolio.com[e] me@jakefolio.com
  • Clean Your Inputs with filter_var();
  • 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
  • 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}
  • 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
  • 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*)
  • 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/
  • 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
  • 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!!!"£$"%$&*());
  • 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;}
  • Filter - urlURLS validation results
  • 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
  • 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);
  • Filter - stringASCII TableSource: http://www.asciitable.com/
  • Filter - urlASCII Extended TableSource: http://www.asciitable.com/
  • Filter - Boolean• FILTER_VALIDATE_BOOLEAN • returns true for: “yes”, 1, “on”, true • returns false for: “non”, 0, “off”, false
  • 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) }*/
  • 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) }*/
  • 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) }*/
  • Filter - Integer• FILTER_VALIDATE_INT• FILTER_SANITIZE_INT • remove all characters except digits and +-
  • Filter - integerValidate integer using extra options$year = filter_var(2032, FILTER_VALIDATE_INT, array( min_range => 1927, max_range => 2011));
  • Filter - Float• FILTER_VALIDATE_FLOAT • FILTER_FLAG_ALLOW_THOUSAND• FILTER_SANITIZE_FLOAT • FILTER_FLAG_ALLOW_FRACTION • FILTER_FLAG_ALLOW_SCIENTIFIC
  • 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;
  • Putting it all together!
  • 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>
  • 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."; }}
  • 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."; } }}
  • Breaking intoXML with PHP
  • XML Libraries• SimpleXML• DOMDocument• XMLReader/Writer
  • 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;
  • SimpleXML • Tree Parser • Really awesome for quick and dirty reading • Xpath built-inSource: http://us.php.net/manual/en/class.simplexmlelement.php
  • 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
  • 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
  • DOMDocument • Tree Parser • Great at importing HTML/XHTML • Great at modifying/injecting nodes • Xpath built-inSource: http://us.php.net/domdocument
  • 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
  • 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
  • XMLReader/Writer• Pull Parser• Full Steam Ahead - only moves forward• Great for large XML documents• Reads/Writes line by line, small memory footprint
  • 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
  • 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
  • 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
  • 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
  • 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)
  • XML Recap - DOMDocument• Great for manipulating XML• Can properly load (X)HTML files• Has xpath (tree traversing)
  • XML Recap - XMLReader/Writer• Extremely fast• Handles stream context for source• Best used with large XML docs or streams• Forward moving (pull)
  • 1...Iterator2...Iterator3...Iterator floor();
  • 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
  • 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
  • Iterator Interfaces • Traversable • Iterator • RecursiveIterator • Countable • SeekableIteratorSource: http://www.php.net/manual/en/spl.iterators.php
  • 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
  • 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
  • DIRECTORY ITERATORS
  • 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
  • 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
  • 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
  • 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
  • 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
  • FILTER ITERATORS
  • 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
  • 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; }}
  • 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
  • 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();}
  • 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
  • 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
  • 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();}
  • 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
  • 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
  • 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
  • Questions? Concerns? Complaints?
  • Thanks for listening! http://joind.in/talk/view/2971