Extending HTML5 input types with regular expressions

I was reading Jeremy Keith’s, HTML5 for Web Designers which I’ve written about before. This quote is from the section on new <input> tag types, end of chapter 4:

The good news is that you can use the pattern attribute to specify exactly what kind of value is expected. The bad news is that you have to use a regular expression:


<label for="zip">US Zip code</label>
<input id="zip" name="zip" pattern="[d]{5}(-[d]{5})">US Zip code</label>

Most of the time, you’ll never need to use the pattern attribute. On the occasions that you do, you have my sympathy.

Although I’m appreciative of Keith’s lucid explanation, I find that I disagree with him on this point. It’s a great step that we can define input types at will; but it’s even better that the patterns are defined using regular expressions. I can’t think of a more succinct and powerful way to allow infinite extensibility.

As a side note, the example in the book will match 9-digit zip codes, but unfortunately allows other strings also (such as “asdf12345-2345″ or “12345-2345qwer”). I think the following example might be more useful for validating zip codes.


<input id="zip" name="zip" pattern="^[d]{5}(-[d]{4})?$">

The regular expression here matches either 5- or 9-digit strings and nothing else. Unfortunately, you can’t test this in a browser, since no browsers seem to support this attribute yet (I tested Chrome, Safari, Firefox). When browsers do support it, if they end up using regex parsing similar to javascript, you’d be set.

Update November 2011: I’ve come back and tested this and found that the original example does in fact limit to only 9-digit zip codes. Some regex parsers (perl, php and javascript, for example) would have matched “asdf12345-1234″ as matching the book’s regex. It seems that the browser parsers (I checked Firefox and Chrome) are a little more strict by default and don’t require you to indicate the start and end of the string with ^ and $, respectively. However, the regex I included does have the feature of accepting either 5-digit or 9-digit zip codes. So if that’s what you’re looking for, have at it!

PS. Sorry Jeremy for saying your pattern was not strict enough the first time round.

Accessing IPInfoDB with a PHP class

I am working on an analytics tool and needed to pull info from the public IPInfoDb. You can get data for 1 – 25 IP’s at a time, and the data is returned as XML or JSON. I wrote a quick Library for PHP that accesses their data using the JSON format. It selects the correct query URL based on how many IP’s you give it.

Installation and Usage

First install the script at some PHP-accessible place, for example, /path/to/class/IPInfo.php. I would also set up autoloading classes to make things simpler. Here’s an example of pulling some information on either an individual IP or several. The class returns an associative array with IP’s for the keys and information arrays (containing city, region, country, latitude, longitude) as the value.

PHP
1
2
3
4
5
6
7
8
9
10
11
// include the class or use autoload instead.
require('/path/to/class/IPInfo.php');
// instantiate the class
$ipinfo = new IPInfo();
// option1
$oneIP = $ipinfo-&gt;getInfo('123.234.345.123');
// option2
$multipleIPs = $ipinfo-&gt;getInfo( array('123.234.345.123', '1.4.3.123') );

Download

Download the IPInfo class or copy / paste from below.

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
&lt;?
/* class that grabs IP info based on a couple of IP's
using the IPInfo DB http://ipinfodb.com/
*/
class IPInfo {
function getInfo($ips) {
// expects either 1 IP or an array of ips.
if (!$ips) {
return false;
}
if (!is_array($ips)) {
$ips = array($ips);
}
//IP Info db allows multiple IP request in series of up to 25. so if there are more than one, hit the
if (count($ips)&gt;1) {
$ips = array_map(array(&amp;$this, "cleanIP"), $ips);
$ips = array_unique($ips);
$ip_chunks = array_chunk($ips,25);
$ipinfo = array();
foreach($ip_chunks as $ipch) {
$url = "http://ipinfodb.com/ip_query2.php?timezone=false&amp;output=json&amp;ip=".implode(',',$ipch);
$val = $this-&gt;makeRequest($url);
foreach($val['page']['Locations'] as $i) {
$ipinfo[$i['Ip']] = $i;
}
}
return $ipinfo;
}
else {
$url = "http://ipinfodb.com/ip_query.php?timezone=false&amp;output=json&amp;ip=".$this-&gt;cleanIP($ips[0]);
$val = $this-&gt;makeRequest($url);
$ipinfo = array("{$ips[0]}" =&gt; $val['page']);
return array("{$ips[0]}" =&gt; $val['page']);
}
}
function cleanIP($ip) {
return preg_replace('/[^0-9.]/','',$ip);
}
private function makeRequest($url) {
$referer = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_REFERER, $referer);
$tries=0;
$page=false;
while( $page===false &amp;&amp; $tries&lt;= 5) {
$page = curl_exec($ch);
$tries++;
}
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return array('page'=&gt;json_decode($page,true), 'tries'=&gt;$tries, 'httpcode' =&gt; $httpcode);
}
}
?&gt;

WP Plugin: Widget Context

Last night I ran across a WordPress plugin called Widget Context by Kaspars Dambis. The plugin gives you the ability to control on what context any widget will show up in, allowing you to narrow down widget content to certain types of posts / pages, to certain categories and URL’s. It’s really useful and allowed me to do some things within WordPress rather than making an ugly hack to a template — making things easier to maintain for non-developers in the future.

Currently, I’m using the plugin to show a custom menu on a certain set of sub-pages over on Mt Zion Church‘s website. Any WP developers out there, let me know if there’s a better way, but thanks Kaspars for the plugin — it’s certainly useful.