SlideShare a Scribd company logo
UNSUNG HEROES OF PHP
                                 JAKE SMITH




http://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 manipulated

Source: http://www.php.net/manual/en/filter.filters.php
filter_input/filter_has_var
Can not add additional fields to filter_input
if ($_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 822

Source: http://www.faqs.org/rfcs/rfc822.html
Filter - email
Official 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]|.|(?:(?:r
n)?[ 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])*))*@(?:(?:r
n)?[ 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]))*"(?:(?:r
n)?[ 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 - email
Validate email examples: returns string if valid and false on failure
if (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 address
echo filter_var("chris@example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Good

// test good email address
echo 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 part
echo 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 anywhere
echo 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"; // Bad




Source: 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 - url
URLS 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://i'me really trying to break this url!!!"£$"%$&*()'
);
Filter - url
URLS validation combinations
foreach ($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 - url
URLS 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 - string
Sanitize 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 tags
echo 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 - string
ASCII Table




Source: http://www.asciitable.com/
Filter - url
ASCII Extended Table




Source: http://www.asciitable.com/
Filter - Boolean



• FILTER_VALIDATE_BOOLEAN
 • returns true for: “yes”, 1, “on”, true
 • returns false for: “non”, 0, “off”, false
Filter - boolean
Sanitize 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>';
  }
}

/* OUTPUT
array(4) {
   ["terms_of_service"]=> bool(true)
   ["logged_in_user"]=> bool(true)
   ["forged_field"]=> bool(false)
   ["opt_in"]=> bool(false) }
*/
Filter - boolean
Apply 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);

/* OUTPUT
array(4) {
   ["terms_of_service"]=> bool(true)
   ["logged_in_user"]=> bool(true)
   ["forged_field"]=> NULL
   ["opt_in"]=> bool(false) }
*/
Filter - boolean
Apply 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);

/* OUTPUT
array(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 - integer
Validate 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 - float
Show different types of validation/sanitization
// Removes the , even though it's 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_array
Basic 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_array
Basic Contact Form without filter_input_array
if ($_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 - string
Basic Contact Form WITH filter_input_array
if ($_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 into
XML with PHP
XML Libraries



• SimpleXML
• DOMDocument
• XMLReader/Writer
XML Section
Data 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 flavor
and 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 wheat
beer 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-in

Source: http://us.php.net/manual/en/class.simplexmlelement.php
SimpleXML
Read 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
SimpleXML
Scrape 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-in

Source: http://us.php.net/domdocument
DOMDocument
Read 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
DOMDocument
Scrape 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
XMLReader
Iterate 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
XMLWriter
Headers and Data
header("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
XMLWriter
Setup
class 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
XMLWriter
Iteration
foreach($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);

  // Don't 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...Iterator
2...Iterator
3...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 container's 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
                   • SeekableIterator
Source: 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
DirectoryIterator
Output directory content for Zend Framework
$it = new DirectoryIterator('lib/Zend');
foreach ($it AS $file) {
  echo $file->getFilename() . "<br>";
}

OUTPUT:
.
..
.DS_Store
Acl
Acl.php
Amf
Application
Application.php
Auth
Auth.php
Barcode
Barcode.php
Cache
Cache.php
Captcha
Cloud
CodeGenerator
Config
Config.php
Console
Controller
Crypt
Crypt.php
Currency
Currency.php
Date


Source: http://us.php.net/manual/en/class.directoryiterator.php
DirectoryIterator - SPLFileInfo
Methods 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_Store
lib/Zend/Acl - Acl
lib/Zend/Acl.php - Acl.php
lib/Zend/Amf - Amf
lib/Zend/Application - Application
lib/Zend/Application.php - Application.php
lib/Zend/Auth - Auth
lib/Zend/Auth.php - Auth.php
lib/Zend/Barcode - Barcode
lib/Zend/Barcode.php - Barcode.php
lib/Zend/Cache - Cache
lib/Zend/Cache.php - Cache.php
lib/Zend/Captcha - Captcha
lib/Zend/Cloud - Cloud
lib/Zend/CodeGenerator - CodeGenerator
lib/Zend/Config - Config
lib/Zend/Config.php - Config.php
lib/Zend/Console - Console




Source: 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 - Acl
lib/Zend/Acl.php - Acl.php
lib/Zend/Amf - Amf
lib/Zend/Application - Application
lib/Zend/Application.php - Application.php
lib/Zend/Auth - Auth
lib/Zend/Auth.php - Auth.php
lib/Zend/Barcode - Barcode
lib/Zend/Barcode.php - Barcode.php
lib/Zend/Cache - Cache
lib/Zend/Cache.php - Cache.php
lib/Zend/Captcha - Captcha
lib/Zend/Cloud - Cloud
lib/Zend/CodeGenerator - CodeGenerator
lib/Zend/Config - Config
lib/Zend/Config.php - Config.php
lib/Zend/Console - Console




Source: 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.php




Source: 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
FilterIterator
Do not show Version Control folders
class 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
FilterIterator
Only show images greater than 5MB
class 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();
}
RegexIterator
Move 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
LimitIterator
Limit 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
            •   SortableIterator




Source: 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 behind


Source: 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 countable

Source: http://us.php.net/manual/en/ref.spl.php
Questions? Concerns? Complaints?
Thanks for listening!




    http://joind.in/talk/view/2971

More Related Content

Unsung Heroes of PHP

  • 1. UNSUNG HEROES OF PHP JAKE SMITH http://joind.in/talk/view/2971
  • 2. Jake Smith [t] @jakefolio [w] http://jakefolio.com [e] me@jakefolio.com
  • 3. Clean Your Inputs with filter_var();
  • 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 manipulated Source: http://www.php.net/manual/en/filter.filters.php
  • 5. filter_input/filter_has_var Can not add additional fields to filter_input if ($_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. Filter - Email • FILTER_VALIDATE_EMAIL • FILTER_SANITIZE_EMAIL • Strip all non-email characters • Email standards based on RFC 822 Source: http://www.faqs.org/rfcs/rfc822.html
  • 7. Filter - email Official 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]|.|(?:(?:r n)?[ 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])*))*@(?:(?:r n)?[ 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]))*"(?:(?:r n)?[ 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. Filter - email Validate email examples: returns string if valid and false on failure if (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 address echo filter_var("chris@example.com", FILTER_VALIDATE_EMAIL) ? "goodn" : "badn"; // Good // test good email address echo 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 part echo 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 anywhere echo 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"; // Bad Source: http://www.electrictoolbox.com/php-email-validation-filter-var/
  • 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. Filter - url URLS 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://i'me really trying to break this url!!!"£$"%$&*()' );
  • 11. Filter - url URLS validation combinations foreach ($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. Filter - url URLS validation results
  • 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. Filter - string Sanitize 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 tags echo 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. Filter - string ASCII Table Source: http://www.asciitable.com/
  • 16. Filter - url ASCII Extended Table Source: http://www.asciitable.com/
  • 17. Filter - Boolean • FILTER_VALIDATE_BOOLEAN • returns true for: “yes”, 1, “on”, true • returns false for: “non”, 0, “off”, false
  • 18. Filter - boolean Sanitize 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>'; } } /* OUTPUT array(4) { ["terms_of_service"]=> bool(true) ["logged_in_user"]=> bool(true) ["forged_field"]=> bool(false) ["opt_in"]=> bool(false) } */
  • 19. Filter - boolean Apply 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); /* OUTPUT array(4) { ["terms_of_service"]=> bool(true) ["logged_in_user"]=> bool(true) ["forged_field"]=> NULL ["opt_in"]=> bool(false) } */
  • 20. Filter - boolean Apply 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); /* OUTPUT array(4) { ["terms_of_service"]=> bool(true) ["logged_in_user"]=> bool(true) ["forged_field"]=> NULL ["opt_in"]=> bool(false) } */
  • 21. Filter - Integer • FILTER_VALIDATE_INT • FILTER_SANITIZE_INT • remove all characters except digits and +-
  • 22. Filter - integer Validate integer using extra options $year = filter_var('2032', FILTER_VALIDATE_INT, array( 'min_range' => 1927, 'max_range' => 2011) );
  • 23. Filter - Float • FILTER_VALIDATE_FLOAT • FILTER_FLAG_ALLOW_THOUSAND • FILTER_SANITIZE_FLOAT • FILTER_FLAG_ALLOW_FRACTION • FILTER_FLAG_ALLOW_SCIENTIFIC
  • 24. Filter - float Show different types of validation/sanitization // Removes the , even though it's 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. Putting it all together!
  • 26. filter_input_array Basic 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. filter_input_array Basic Contact Form without filter_input_array if ($_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. Filter - string Basic Contact Form WITH filter_input_array if ($_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."; } } }
  • 30. XML Libraries • SimpleXML • DOMDocument • XMLReader/Writer
  • 31. XML Section Data 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 flavor and 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 wheat beer 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. SimpleXML • Tree Parser • Really awesome for quick and dirty reading • Xpath built-in Source: http://us.php.net/manual/en/class.simplexmlelement.php
  • 33. SimpleXML Read 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. SimpleXML Scrape 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. DOMDocument • Tree Parser • Great at importing HTML/XHTML • Great at modifying/injecting nodes • Xpath built-in Source: http://us.php.net/domdocument
  • 36. DOMDocument Read 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. DOMDocument Scrape 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. XMLReader/Writer • Pull Parser • Full Steam Ahead - only moves forward • Great for large XML documents • Reads/Writes line by line, small memory footprint
  • 39. XMLReader Iterate 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. XMLWriter Headers and Data header("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. XMLWriter Setup class 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. XMLWriter Iteration foreach($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); // Don't 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. 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. XML Recap - DOMDocument • Great for manipulating XML • Can properly load (X)HTML files • Has xpath (tree traversing)
  • 45. XML Recap - XMLReader/Writer • Extremely fast • Handles stream context for source • Best used with large XML docs or streams • Forward moving (pull)
  • 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 container's interface. ” Source: http://en.wikipedia.org/wiki/Iterator
  • 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. Iterator Interfaces • Traversable • Iterator • RecursiveIterator • Countable • SeekableIterator Source: http://www.php.net/manual/en/spl.iterators.php
  • 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. 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
  • 53. DirectoryIterator Output directory content for Zend Framework $it = new DirectoryIterator('lib/Zend'); foreach ($it AS $file) { echo $file->getFilename() . "<br>"; } OUTPUT: . .. .DS_Store Acl Acl.php Amf Application Application.php Auth Auth.php Barcode Barcode.php Cache Cache.php Captcha Cloud CodeGenerator Config Config.php Console Controller Crypt Crypt.php Currency Currency.php Date Source: http://us.php.net/manual/en/class.directoryiterator.php
  • 54. DirectoryIterator - SPLFileInfo Methods 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. 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_Store lib/Zend/Acl - Acl lib/Zend/Acl.php - Acl.php lib/Zend/Amf - Amf lib/Zend/Application - Application lib/Zend/Application.php - Application.php lib/Zend/Auth - Auth lib/Zend/Auth.php - Auth.php lib/Zend/Barcode - Barcode lib/Zend/Barcode.php - Barcode.php lib/Zend/Cache - Cache lib/Zend/Cache.php - Cache.php lib/Zend/Captcha - Captcha lib/Zend/Cloud - Cloud lib/Zend/CodeGenerator - CodeGenerator lib/Zend/Config - Config lib/Zend/Config.php - Config.php lib/Zend/Console - Console Source: http://us.php.net/manual/en/class.filesystemiterator.php
  • 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 - Acl lib/Zend/Acl.php - Acl.php lib/Zend/Amf - Amf lib/Zend/Application - Application lib/Zend/Application.php - Application.php lib/Zend/Auth - Auth lib/Zend/Auth.php - Auth.php lib/Zend/Barcode - Barcode lib/Zend/Barcode.php - Barcode.php lib/Zend/Cache - Cache lib/Zend/Cache.php - Cache.php lib/Zend/Captcha - Captcha lib/Zend/Cloud - Cloud lib/Zend/CodeGenerator - CodeGenerator lib/Zend/Config - Config lib/Zend/Config.php - Config.php lib/Zend/Console - Console Source: http://us.php.net/manual/en/class.globiterator.php
  • 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.php Source: http://us.php.net/manual/en/class.recursivetreeiterator.php
  • 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. FilterIterator Do not show Version Control folders class NoVCSIterator extends FilterIterator { public function accept() { $file = $this->getInnerIterator()->current(); if ($file->isDir() && ($file->getFilename() == '.git' || $file->getFilename() == '.svn')) { return false; } return true; } }
  • 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. FilterIterator Only show images greater than 5MB class 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. RegexIterator Move 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. 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. LimitIterator Limit 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. Filter Iterators in the wild Symfony2 ChainIterator • CustomFilterIterator • DateRangeFilterIterator • ExcludeDirectoryFilterIterator • FileTypeFilterIterator • FilenameFilterIterator • IgnoreVcsFilterIterator • LimitDepthFilterIterator • SizeRangeFilterIterator • SortableIterator Source: https://github.com/symfony/symfony/tree/master/src/Symfony/Component/Finder/Iterator
  • 67. Other Iterators • AppendIterator • Iterate over multiple iterators • Caching Iterator • More of a look ahead, pointer is always one stop behind Source: http://www.php.net/manual/en/spl.iterators.php
  • 68. Iterator Functions • iterator_to_array • iterator_apply • similar to array_walk • iterator_count • used when iterator doesn’t implement countable Source: http://us.php.net/manual/en/ref.spl.php
  • 70. Thanks for listening! http://joind.in/talk/view/2971