Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Regular expressions and php
1. Regular Expressions in PHP /(?:dave@davidstocktoncom)/ Front Range PHP User Group David Stockton
2. What is a regular expression? A pattern used to describe a part of some text “Regular” has some implications to how it can be built, but that’s not really part of this presentation Extremely powerful and useful (And often abused)
3. Regex Joke A programmer says, “I have a problem that I can solve with regular expressions.” Now, he has two problems…
4. How to use regex in PHP The preg_* functions Perl compatible regular expressions. Probably the most common regex syntax The ereg_* functions POSIX style regular expressions I am not covering these functions. Don’t use the ereg ones. They are deprecated in PHP 5.3.
5. How can we use regex in PHP? preg_match( ) – Searches a subject for a match preg_match_all( ) – Searches a subject for all matches preg_replace( ) – Searches a subject for a pattern and replaces it with something else preg_split( ) – Split a string into an array based on a regex delimiter preg_filter( ) – Identical to preg_replace except it returns only the matches preg_replace_callback( ) – Like preg_replace, but replacement is defined in a callback preg_grep( ) – Returns an array of array elements that match a pattern
6. How can we use regex in PHP? preg_quote( ) – Quotes regular expression characters preg_last_error( ) – Returns the error code of the last PCRE (Perl Compatible Regular Expression) function execution
7. How can we use regex in PHP? Those are the function calls, and we’ll play with the later. First, we need to learn how to create regex patterns since we need those for any function call.
8. Starting Pattern /[A-Z0-9_+=]+@[A-Z0-9-][A-Z]{2,4}/i This matches a series of letters, numbers, plus, dash, dots, underscores and equals, followed by an “AT” (@) sign, followed by a series of letters, numbers, dots and dashes, followed by a dot, followed by 2 to 4 letters. In other words… It matches an email address… Or rather some email addresses.
9. Matching Email Addresses What about james@smithsonian.museum? What about freddie@wherecanI.travel? Both of those are valid email addresses, but they fail because our patter only allows 2-4 character TLD parts for the email address. How can we match all valid email addresses and only valid email addresses?
12. So… How do we write this? Don’t. Other much more simple patterns have been written and will match 99.9% of valid email addresses. Use something like Zend_Validate_EmailAddress
13. So now the real learnin’… Letters and numbers match… letters and numbers /a/ - Matches a string that contains an “a” /7/ - Matches a string that contains a 7.
14. More learnin’ Match a word /regex/ - Matches a string with the word “regex” in it You can use a pipe character to give a choice /pizza|steak|cheeseburger/ - Matches a string with any of these foods
15. Delimiters The examples so far have started with / and ended with /. These are delimiters and let the regex engine know where the pattern starts and ends. You can choose another delimiter if you’d like or if it’s more convenient Match namespace: #/My/PHP/Namespace# If I used “/” in that example, I’d need to escape each of the forward slashes to differentiate them from the delimiter
16. Character Matching Continued You can match a selection of characters /[Pp][Hh][Pp]/ - Matches PHP in any mixture of upper and lowercase Ranges can be defined /[abcdefghijklmnopqrstuvwxyz]/ - Matches any lowercase alpha character /[a-z]/ - Matches any lowercase alpha character
17. Character Selection Ranges Ranges can be combined /[A-Za-z0-9]/ - Matches an alphanumeric character /[A-Fa-f0-9]/ - Matches any hex character Character Selection can be inversed /[^0-9]/ - Matches any non-digit character /[^ ]/ - Matches any non space character /[.!@#$%^*]/ - Matches some punctuation
18. Special Characters Dot (.) matches any character /./ /../ - Matches any two characters To match an actual dot character, you must escape // - Matches a single dot character Unless it’s a character selection /[.]/ - Matches a single dot character
19. Character classes means [0-9] means non-digits - [^0-9] means word characters - [A-Za-z0-9_] means non word characters – [^A-Za-z0-9_] means a whitespace character [ ] means non white space characters
20. Repeating Character Classes Match two digits in a row // /[0-9][0-9]/ /{2}/ /[0-9]{2}/ Match at least one digit (but as many as it can) /+/ Match 0 to infinite digits /*/
21. Repeating Character Classes cont. * means match 0 or more + means match 1 or more {x} where x is a number means match exactly x of the preceding selection {x,} means match at least x {x,y} means match between x and y {,y} means match up to y
22. More special characters ? Means the preceding selection is optional Putting it together Telephone Number /?({3})?[-]?({3})[-]?({4})/ Matches 720-675-7471 or (720)675-7471 or (720) 675-7471 or 7206757471 or 720 675 7471 Find a misspelled word (and get great deals on EBay) /la[bp]topcomputer[s]?/
23. Regex Anchors Anchors allow you to specify a position, like before, after or in between characters /^ab/ matches abcdefg but not cab Notice that it’s the caret character… It means start of the string in this context, but means the opposite of a character class inside the square brackets /ab$/ matches cab but not abcdefg /^[a-z]+$/ will match a string that consists only of lowercase characters
24. Word Boundaries means word boundaries Before first character if first character is a word character After last character if last character is a word character Between two characters if one is a word character and the other is not /fish/ matches fish, but not fisherman or catfish. /fish/ matches fish and catfish
25. Alternation /cow|boy/ - Matches cow, or boy or cowboy or coward, etc /(cow|boy)/ - Matches cow or boy but not cowboy or coward The above example also captures the matching word due to the parens. More on this later.
26. Greedy vs Lazy By default, regular expressions are greedy… That is, they will match as much as they can Grab a starting html tag: /<.+>/ Matches in bold: <h1>Welcome to FRPUG</h1> Not what we want Make it lazy: /<.+?>/ Now it matches <h1>Welcome to FRPUG</h1>
27. Another tag matching solution /<[^>]+>/ Literally match a less than character followed by one or more non-greater than characters followed by a greater than character This way eliminates the need for the engine to backtrack (almost certainly faster than the last example).
28. Capturing part of regex (backreference) /__(construct|destruct)/ Backreference will contain either construct or destruct so you can use it later /([a-z]+)/ Matches groups of repeated characters that repeat an even number of times. Matches aa but not a. Matches aaaaa /([a-z]{3})/ Matches words like booboo or bambam
29. Backreference Continued… Very useful when performing regex search and replace preg_replace('/?({3})?[-]?({3})[-]?({4})/', '() -', $phone) The above example will take any phone number from the previous example and return it formatted in (xxx) xxx-xxxx format
31. Non-capturing groups Match an IPv4 address /((?:{1,3}){3}{1,3})/ We’re matching 1 to 3 digits followed by a dot 3 times. We don’t care (right now) about the octets, we just want to repeat the match, so ?: says to not capture the group.
32. Pattern Modifiers Modifiers go after the last delimiter (now you know why there are delimiters) and affect how the regex engine works i – case insensitive matching (matches are case-sensitive by default) m – multiline matching s - dot matches all characters, including x – ignore all whitespace characters except if escaped or in a character class
33. Pattern Modifiers Continued… D – Anchor for the end of the string only, otherwise $ matches characters Allow username to be alphabetic only /^[A-Za-z]$/ - This will match daveextra stuff However, /^[A-Za-z]$/D will not match U – Invert the meaning of the greediness. With this on by default matches are lazy and ? makes it greedy. There are lots of other modifiers and you can see them at http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php
34. Named Capture Groups Rather than get back a numbered array of matches, get back an associative array. If you add a new capture group, you don’t have to renumber where you use the capture group
36. Named Capture Groups cont… Combined numbered and associative array Capture group 0 is the wholepattern that is matched. If our string to match against was abcde720-675 7471foobar, $matches[0] will contain720-675 7471
37. Positive Look Ahead Matches Look for a pattern follow by another pattern /p(?=h)/ - Match a “p” followed by an “h” but don’t include the “h”
38. Negative Look Ahead Look for a pattern which is not followed by some other pattern /p(?=!h)/ - pnot followed by h.
39. Look Aheads Positive and negative look aheads do not capture anything. They just determine if the pattern match is possible They are zero-width /p[^h]/ is not the same as /p(?!h)/ /ph/ is not the same as /p(?=h)/
40. Look behinds Positive look behind /(?<=oo)d/ - d which is preceded by oo Matches “food”, “mood”, match only contains the “d” Negative look behind /(?<!oo)d/ - d which is not preceded by oo Matches “dude”, “crude”, and “d”
41. With great power… Test your regular expressions before they go to production It’s much easier to get them wrong than to get themright if you don’t test
42. When to not use regex Whenever they aren’t needed. If you can use strstr or strpos or str_replace to do the job, do that. They are much faster, much simpler and easier to do correctly. However, if you cannot use those functions, regex may be your best bet. Don’t use regex when you really need a parser