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.

Posted in html5, regex, web development | Leave a comment

Navigating the Web – slides

I gave a talk yesterday called Navigating the Web. It was an intro talk to help folks get started on the web.

Download Navigating the Web (PDF).

Posted in speaking | Leave a comment

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.

// include the class or use autoload instead.
require('/path/to/class/IPInfo.php');

// instantiate the class
$ipinfo = new IPInfo();

// option1
$oneIP = $ipinfo->getInfo('123.234.345.123');

// option2
$multipleIPs = $ipinfo->getInfo( array('123.234.345.123', '1.4.3.123') );

Download

Download the IPInfo class or copy / paste from below.

<?

/*  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)>1) {
			$ips = array_map(array(&$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&output=json&ip=".implode(',',$ipch);
				$val = $this->makeRequest($url);
				foreach($val['page']['Locations'] as $i) {
					$ipinfo[$i['Ip']] = $i;
				}
			}
			return $ipinfo;
		}
		else {
			$url = "http://ipinfodb.com/ip_query.php?timezone=false&output=json&ip=".$this->cleanIP($ips[0]);
			$val = $this->makeRequest($url);
			$ipinfo = array("{$ips[0]}" => $val['page']);
			return array("{$ips[0]}" => $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 && $tries<= 5) {
			$page = curl_exec($ch);
			$tries++;
		}
		$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		curl_close($ch);
		return array('page'=>json_decode($page,true), 'tries'=>$tries, 'httpcode' => $httpcode);
	}
}

?>
Posted in php, web analytics, web development | Leave a comment

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.

Posted in hacking, wordpress | Comments closed

Chicken Tortilla Soup

Made a Chicken Tortilla Soup this evening. It’s pretty straight-forward, yummy and filling.

  • Put ~1lb of chicken on to boil. Make sure chicken is in small enough pieces to cook through evenly.
  • Finely chop an onion and a red pepper
  • Heat a tablespoon or so of good olive oil at medium heat and then sauté the onion and pepper for several minutes
  • Add a healthy amount of cumin, oregano (I didn’t have fresh cilantro or I would have used that instead), a dash of salt, and crushed red peper
  • When onions are translucent (and look yummy) add a carton of Trader Joe’s Tomato and Roasted Red Pepper Soup and about half a carton of TJ’s chicken broth.
  • Drain and rinse two cans of black beans and add them to the soup too
  • When the chicken is cooked, pull each piece out of the water and then with two forks pull the meat apart until you have a pile of stringy chicken. Add the chicken to the soup
  • Add two cans of sweet corn
  • Season to taste with salt, crushed red pepper, and/or hot pepper sauce (my fave: Sriracha)
  • Serve with tortilla chips.

Serves 8

Today I didn’t have sour cream or cilantro — that would have been the perfect ending. Also, I think that it’s a little too thick if you follow the above directions (which I have to take full responsibility for since I made the recipe above). Next time I think I’ll add a little more broth or water and salt.

Posted in food | Comments closed

Insights from An Event Apart, Minneapolis

This past week I attended An Event Apart in Minneapolis. It was a really great time with a star-studded cast of web folks. I wanted to post some of the highlights and the insights I gained.

Whitney Hess’ talk about user interface brought up a few examples that really caught my ear. She’s a really good story-teller and I found that there were a couple of anecdotes that really stuck with me. She talked a lot about how Harvest have done a great job in developing their product partly due to how easy they make it for the user to provide feedback and get help if needed — it’s part of their culture. She also brought up an example of a guy deep within a government organization who still had a huge impact by looking at search stats. I’ve been meaning to look into search stats more and that story was the push I needed to try some new things.

Dan Cederholm and Eric Meyer gave some detailed talks on CSS3 and show some great examples of putting it into action.

Luke Wroblewski, who I hadn’t heard of before, gave a great talk advocating that we should develop applications for mobile first. A lot of the other speakers throughout the conference re-iterated how crucial mobile is and will be over the next few years. The mobile web is where the audience increasingly is and if we are to make any impact as web developers we will have to become adept at designing and developing for it. Good wake up call — now time for some development.

Ethan Marcotte gave a wonderful talk about what he’s calling Responsive Web Design. In other words, that’s designing and developing websites so that they are based on a flexible grid sytem and respond with specific styles depending on the requestor (using the new functionalitly available through @media in CSS3). He made reference to an insteresting article, A Dao of Web Design, in ALA’s Archives. He gave some great examples, some clean code, and well-thought ways of designing websites that look great on the desktop and the mobile browser.

Jeffrey Veen concluded with an inspirational (and fast-paced) talk on How the Web Works. My takeaway was that if you want to be successful on the web you need to get-the-code-out-there-already. Working code and prototypes trump all kinds of blabber and carrying on. I think this is a great principle and, in fact, for a while now, I’ve been trying to create prototypes as a starting point. The questions and answers (especially with non-developers / designers) become so much more useful when we can see and interact with something. As a developer, the biggest challenge is overcoming the inertia and just getting something working. Jeff used a great quote:

“If you’re not embarrassed when you ship your product,
you waited too long.”
- Reid Hoffman

Jeff was an incredible speaker. He has an ability to present an idea, back it up with great examples, and talk fluidly and fluently while running a parallel slideshow. The ~180 slides he showed fit his narrative very well, but very often he was showing a slide, allowing you to read or look at it, while he was continuing to talk and make a point. Quite an art.

After finishing Jeffrey offered to buy a beer for anyone who wanted to talk with him and would continue the discussion in the bar of the hotel. I was impressed — and sad that I had plans right after the conference ended.

AEA Minneapolis 2010 was a great time — I would recommend.

Posted in css3, web development | Comments closed

LDAP authentication for multi-site WordPress 3.0

I manage two WordPress installations with multi-site (previously WP MU). Logins via LDAP would be ideal. I hadn’t had any luck making the existing LDAP plugins to work with Novell eDirectory. However, we just moved to use Active Directory (AD) and so I retried some of the plugins. I now have Simple LDAP Login (plugin) working. Since I’ve installed it on a multi-site installation I made some further modifications to the plugin. Here’s how I did it.

I wanted the plugin to run on any blog so I put it in the mu-plugins folder. Anything in wp-content/mu-plugins will be run on every blog in the system and doesn’t show up in the ‘Plugins’ menu to activate / de-activate. After copying the plugin into the mu-plugin you also have to create a file in mu-plugins that includes a specific plugin file since WP won’t include folders in mu-plugins like it does with the plugins folder — it only executes the files in the mu-plugins folder itself. To cater for this, you must change the following line in Simple-LDAP-Login.php:

	require_once( WP_PLUGIN_DIR."/simple-ldap-login/adLDAP.php");

to:

	require_once( WPMU_PLUGIN_DIR."/simple-ldap-login/adLDAP.php");

I wanted the configuration for the LDAP plugin to be only accessible to Super Admin users to that individual users of any of the blogs in the system, even administrators wouldn’t be able to mess around with the settings for the pluing. To do this, you need to find the call to add_options_page() in Simple-LDAP-Login.php and change it to:

    add_options_page("Simple LDAP Login", "Simple LDAP Login", 'update_core', "simple-ldap-login", "simpleldap_menu");

The key here is the third argument. This requires that in order for a user to see this options page the user must have ‘update_core’ capability. This capability is possessed by Super Admins. See more about WordPress Roles and Capabilities.

Finally, I created a quick PHP script that will update the blog options sitewide. Point it at a WordPress database, and edit it to adjust settings that you want and this will update the options on all blogs (with exceptions if you like) on a WordPress installation. The script is rough and ready and there no protection for SQL injection, so be careful if you’re thinking about hooking this up to some user input.

<?php
	// a quick script to update blog options in a WordPress 3.0 multi-site environment.

	$conn = mysql_connection(...); // insert your db connection info here.

	// options to set. this just alters options in the wp_*_options table
	// with these 'option_name' => array('value' => 'option_value', 'autoload' => 'autoload')

	$options = array(
		// format: '<option-name>' => array('value' => '<option_value>', 'autoload' => '<yes|no>'),
		// examples
		"simpleldap_account_suffix" => array('value'=>'@domain', 'autoload'=>'yes'),
		"show_avatars" => array('value'=>0, 'autoload'=>'yes'), // hide avatars.
		);

	// blog id's to exclude.
	$wp_id_exceptions = array();	

	foreach( get_option_tables( $wp_id_exceptions ) as $table ) {
		echo "processing TABLE ". $table."\n";
		update_options($options,$table);
	}

function get_option_tables($wp_id_exceptions) {
	global $db;
	$query = " show tables like 'wp_%_options'";
	$result = mysql_query($query);
	if ($result) {
		$tables = array();
		while($row = mysql_fetch_row($result)) {
			$add = 1;
			foreach($wp_id_exceptions as $id) {
				if ($row[0] == "wp_{$id}_options") {
					$add = 0;
				}
			}
			if ($add) {
				$tables[] = $row[0];
			}
		}
	}
	return $tables;
}

function update_options($options,$table) {
	global $db;
	foreach($options as $opt_name => $info) {
		$insert = "insert into $table (option_name, option_value, autoload) values ('$opt_name','{$info['value']}','{$info['autoload']}')";
		$insert_result = mysql_query($insert);

		if ($insert_result) {
			echo "\t inserted OPTION $opt_name = {$info['value']}\n";
		}
		else if (mysql_errno() == 1062) {
			// attempt to update what's already there.
			$update_query = "update $table set option_value = '".$info['value']."', autoload = '{$info['autoload']}' where option_name = '$opt_name'	\n";
			$update_result = mysql_query($update_query);
			if ($update_result) {
				if (mysql_affected_rows()) {
					echo "\t updated OPTION $opt_name = {$info['value']}\n";
				}
				else {
					echo "\t no change OPTION $opt_name = {$info['value']}\n";
				}
			}
			else {
				echo mysql_errno() . " " . mysql_error()."\n";
			}
		}
		else {
			echo mysql_errno() . " " . mysql_error(). "\n";
		}

	}

}

?>

I wrote this script to keep the LDAP plugin up-to-date across blogs, but it has already proven really useful for other purposes.
Posted in web development, wordpress | Comments closed

Bias Peak Express 6

I just bought Bias Peak Express 6 yesterday. It’s on sale currently for $20. I wanted a solid, more reliable editor than Audacity. I’ve heard that Peak’s pretty good, and so I’m giving it a shot. I recorded this last night and used Peak to do some basic cutting. Works smoothly. When I came to export to mp3 for the web, however, I found that it seems to have the mp3 option disabled (and I’m not sure yet how to turn that on), so I used Audacity to convert to mp3 using the LAME library. Here’s the results.

Isaiah 1

I used a Zoom Handy H4n to record the speech. The audio is not EQ’d or anything. This is essentially the sound that pops right out of the H4n.

Posted in audio, bible | Comments closed

Single-sign-on with frames and javascript

Warning: this is about finding workable solutions and some of the methods are used because they are a solution not because they promote the cleanest HTML. You might run across <frame> in this article. Apologies to the HTML5 community.

Most web apps don’t give web developers many tools to integrate directly with their login system. So when it comes to creating single-sign-on scripts you’re often on your own for finding the credentials and back-engineering login systems. Often you have no direct access to the 3rd party system.

Imagine that you have access to the usernames and passwords programmatically. We then set about creating an intermediate page with a hidden form, which, when visited by the user, is populated with the correct credentials and submitted by Javascript. If everything goes to plan the user hardly notices the break in service as he is directed from (1) the single-sign-on hub to (2) the 3rd party service. (I will use these labels (1) and (2) from here on, so make sure they’re clear in your mind.)

We have a number of these type of redirects for single-sign-on at BSU and NTC. One problem that crops up is logging out of (2) doesn’t redirect the user to (1) and going back to (1) doesn’t necessarily log the user out of (2). Further, often the user may need to enter the stored password for (2) to confirm a choice but has forgotten it due to not using it to login anymore.

To solve this problem I created a frameset with two frames: the first being a bar along the top, the second being the main application window. In the top bar you have your links to a) retrieve your password for (2) after entering you password for (1), b) a link to go back to (1) and log the user out of (2) on the way and c) a link to logout of both (1) and (2). In the bottom frame you load the plain automatic redirect.

After a little work with AJAX, the first part a) was solved and I had the system returning the password to (2) when they enter the password for (1). The problem was the two links b) and c). Often you have trouble manipulating one frame with javascript from another frame. I found, however, that I could change the location.href of the bottom frame from top frame with the following statement.

top.frames['bottom'].location.href = "http://www.example.org/logout/";

Given the right URL to log out of (2), it’s possible now to force a logout in the bottom frame from the top frame. Now, by setting a timeout, we ensure that the logout from (2) is complete before commanding the entire window to go back to (1).

setTimeout('top.location.href = "https://www.originaldomain.com/";', 200);

With a little adjustment of the URL’s and setting up the event handlers, I now have two links in the top frame that will b) log the user out of (2) and redirect to (1), and c) log the user out of (2) and (1), redirecting back to the login page for (1).

Using frames is a bit 1997, but it does present a workable solution that makes the whole interface work much better for the user. An example of when one needs a solution not an ideal.

Posted in hacking, javascript, web development | Comments closed

HTML5 for Web Designers by Jeremy Keith

I just received my pre-ordered copy of HTML5 for Web Designers by Jeremy Keith. It’s certainly a brief book. The design and typography looks great so far.

On a side note, in this category you might also read Dive Into HTML5 by Mark Pilgrim.

HTML5 for Web Designers by Jeremy Keith

Posted in html5, web development | Comments closed