Recently my brother got a SPOT emergency beacon. One of the features is a non-emergency “check in” feature. He hits a button and it logs his location. Turns out, that log has an RSS feed. So I built an application to take the feed and put the items in a database. Then I build a page with a Google Map. The map pulls coordinates from the database and puts little markers on the map. Each marker is clickable, and a little balloon pops up that says “At such and such a date and time, I was at some address.” The markers are connected chronologically by lines. The most recent marker is a different color, and the map centers on that location.
Archive for the 'PHP' Category
A popular home page design is a sort of newspaper layout, with lots of little blocks of content. An example of that is this website we did for Gilda’s Club.

What we want to do is make the “Mission” block, in the middle right, editable through Wordpress. It’s actually pretty easy to do.
1. Create a new page. Call it something like Home Page: Mission. Copy/Paste the content in there.
2. If you have the kind of navigation that picks up pages automatically, you’re going to need to add the page id to an exclude list in your wp_list_pages() call. This may be the header navigation, sidebar, and/or footer.
3. Now we’re going to modify our template. Find the part where that block content is hardcoded into the template. Replace it with this:
$page_id = 541; // change to your page id, obviously $post = get_page($page_id); setup_postdata($post); the_content();
And you’re done.
The last few days I’ve been playing with Google’s Chart API. It’s much simpler than their other APIs. This is pretty close to dirt simple. My only “complaint” is that a lot of the variable names are a bit obscure. I’m unlikely to remember that chxl means chart axis labels. So I started writing a little class to help.
$chart = new googleChart($data, $title, $width, $height)
data should be an associative array
- your keys become the x axis
- your values become the y axis
title, width, and height are optional
$chart->title = ‘This is my title!’;
$chart->width = 400;
$chart->height = 400;
color is the color of the line
it must be a hex code
$chart->color = ‘ff8800′;
fill is the color of the space under the line
it must be a hex code
$chart->fill = ‘ffff80′;
then all you have to do is call
$url = $chart->getURL();
You can check out my “alpha release” here.
I’m working on a project where we have a ton of images that we’ll need to import into image galleries in Drupal 6. There are a bunch of nice modules to do this, but they expect the end user to have the correct JRE installed, or fail to function with .htaccess authentication. We needed something simpler.
There’s a module called “image_import_zip” which allows you to upload a zip file full of images without using FTP. It extracts them, and then you can use “image_import” to turn them all into image nodes. Which sounds nice, except that “image_import_zip” is only for Drupal 5, and the people responsible tell you to go use something Flashy for Drupal 6.
So I went ahead and hacked the module to work with Drupal 6. Enjoy.
I’m using wp-table for a Wordpress project, and you can read in data from a csv file and it builds a table for you. At least, that’s the theory. In fact, it uses PHP’s built-in fgetcsv() function. Which blows.
fgetcsv() does a good job of parsing lines which are comma separated values, but it’s really profoundly retarded about understanding that the end of a line is the end of a record. If you read in 1000 bytes, you could have 10 records/line in there, but it mashes them all into one array.
So I wrote my own. It’s pretty basic, but it works.
function parse_csv_file($file, $columnheadings = false, $delimiter = ';', $enclosure = '"') { $row = 1; $rows = array(); $file_contents = file_get_contents($file); // determine the line break character sequence $line_break = chr(13) . chr(10); $pos = strpos($file_contents, $line_break); if ($pos === false) { // didn't find that $line_break = chr(10); $pos = strpos($file_contents, $line_break); if ($pos === false) { // not that either $line_break = chr(13); $pos = strpos($file_contents, $line_break); if ($pos === false) { // uh oh // Cannot determine line break character sequence. exit; } else { // Line breaks on 13 } } else { // Line breaks on 10 } } else { // Line breaks on 13.10 } $lines = split($line_break, file_get_contents($file)); foreach ($lines as $line_num => $line) { $line = trim($line); if ($line == '') continue; $l = array(); $enc = false; $v = ''; for ($i = 0; $i < strlen($line); $i++) { $char = substr($line, $i, 1); if ($char == $enclosure) { if ($enc) { $enc = false; } else { $enc = true; } } else if ($char == $delimiter) { if ($enc) { $v .= $char; } else { $l[] = $v; $v = ''; } } else { $v .= $char; } } // end foreach character in this line $rows[] = $l; } return $rows; }
So you have an address for a location, or maybe a bunch of addresses for different locations, and you want to use Google’s Map API to draw a map with icons for all the locations. Thing is, Google’s Map API requires that you know the latitude and longitude, not the address. You could go and look these up, one at a time, manually. Or you could use a batch geocoder. But maybe you want a programmatic solution. You want to do something like:
$geocode = getGeocode($fullAddress);
Here’s the getGeocode function:
/* get the geocode for a particular address * @param string the full address on one line * @return string geocode like x,y */ function getGeocode($address) { $address_url = urlencode($address); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://www.domain.com/path/to/getGeocode.php?address=" . $address_url); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $geocode = curl_exec($ch); curl_close($ch); return $geocode; }
And then you’ll need this file to go out and get the geocodes:
$address = $_REQUEST['address']; $address_url = urlencode($address); $key = 'your-google-map-api-key-here'; $geo = 'http://maps.google.com/maps/geo?q=' . $address_url . '&output=xml&key=' . $key; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $geo); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $getback = curl_exec($ch); curl_close($ch); $xml = simplexml_load_string($getback); echo $xml->Response[0]->Placemark->Point->coordinates;
If you felt like tinkering, you could dump that xml out and have a look at it. There’s a “status” field which you could make use of.
You’re going to get a string back that looks something like “a,b,c” and each value is a number. The last one is often 0. I’m sure this has something to do with how accurate these points are. All you really care about are the first two numbers. And I *think* those are backwards. You define a GLatLng by passing latitude, then longitude, but I think their geocoder returns longitude, then latitude. So you may have to do some manipulating.
In general, Google says making requests like this is time and resource intensive. If you had a database of 60 something addresses that you wanted to put on a map, it is going to be a little slow to run all of those. In my opinion, it would be better to stores the geocodes in the database, and make your address forms handle it.
Today I was disappointed to find that Drupal does not automatically close HTML tags when it generates a teaser from the body text. So I wrote a function for us. It is not sophisticated. It is not classy. But it appears to work, ha ha.
/* this function closes any open tags * in the correct order */ function balanceTags($html) { // basically we're going to walk through the string and // push open tags to the stack // pop close tags from the stack // return a nicer string $stack = array(); $pointer = 0; $len = strlen($html); $mode = 0; $tag = ''; $closetag = false; while ($pointer < $len) { $c = substr($html, $pointer, 1); if ($c == '<') { // this is the beginning of a tag $mode = 1; } else if ($c == '>') { // this is the end of a tag $mode = 0; if ($closetag) { // this is a closetag like </div> if (count($stack)) { $last_tag = array_pop($stack); // let's strip off any atrributes $space = strpos($last_tag, ' '); if ($space !== false) { $last_tag = substr($last_tag, 0, $space); } while ($last_tag != $tag && $last_tag != '') { // they don't match, so we need to close the one we just popped $newhtml .= '</' . $last_tag . '>'; $last_tag = array_pop($stack); // let's strip off any atrributes $space = strpos($last_tag, ' '); if ($space !== false) { $last_tag = substr($last_tag, 0, $space); } } if ($last_tag) { $newhtml .= '</' . $tag . '>'; } } else { } $closetag = false; $tag = ''; } else { // okay, so we're going to push this tag on the stack array_push($stack, $tag); $newhtml .= '<' . $tag . '>'; $tag = ''; } } else if ($c == '/' && $mode == 1) { // this is the / part of a close tag $closetag = true; } else { if ($mode == 0) { // this is just text $newhtml .= $c; } else if ($mode == 1) { // we're building a tag $tag .= $c; } } $pointer++; } // alright, so, do we have anything hanging around? while (count($stack)) { $last_tag = array_pop($stack); // let's strip off any atrributes $space = strpos($last_tag, ' '); if ($space !== false) { $last_tag = substr($last_tag, 0, $space); } $newhtml .= '</' . $last_tag . '>'; } return $newhtml; } // end balanceTags
Wordpress has all these neat functions for handling parts of a Post, like the_title() and the_exceprt(). Some of them are nice enough to return the value so that you can use it in your PHP code. the_content() is not one of them. But you can hack that function in /wp-includes/post-template.php
function the_content($more_link_text = '(more...)', $stripteaser = 0, $more_file = '', $passback = false) { $content = get_the_content($more_link_text, $stripteaser, $more_file); $content = apply_filters('the_content', $content); $content = str_replace(']]>', ']]>', $content); if (!$passback) { echo $content; } else { return $content; } }
I copied these functions from the Fold Page List plug-in for Wordpress and modified them a little. They are very handy for building breadcrumbs.
/** get_parent_id * get the id of the parent of a given page * @param int page id * @return int the id of the page's parent page */ function get_parent_id ( $child = 0 ) { global $wpdb; // Make sure there is a child ID to process if ( $child > 0 ) { $result = $wpdb->get_var("SELECT post_parent FROM $wpdb->posts WHERE ID = $child"); } else { // ... or set a zero result. $result = 0; } // return $result; } /** get_ancestor_ids * get an array of ancestor ids for a given page * you get an array that looks something like * [0] this page id * [1] parent page id * [2] grandparent page id * @param int page you want the ancestry of * @param boolean include this page in the tree (optional, default true) * @param boolean results top down (optional, default true) * @return an array of ancestor ids */ function get_ancestor_ids ( $child = 0, $inclusive=true, $topdown=true ) { if ( $child && $inclusive ) $ancestors[] = $child; while ($parent = get_parent_id ( $child ) ) { $ancestors[] = $parent; $child = $parent; } // If there are ancestors, test for resorting, and apply if ($ancestors && $topdown) krsort($ancestors); if ( !$ancestors ) $ancestors[] = 0; // return $ancestors; }
Here’s my bread crumb function …
function buildBreadCrumbTrail($showThis = true) { global $post; echo '<a href="/">Home</a>' . chr(10); $ancestors = get_ancestor_ids($post->ID, false); $num_ancestors = count($ancestors); foreach ($ancestors as $i => $ancestor_id) { if ($ancestor_id > 0) { echo ' > <a href="'.get_permalink($ancestor_id).'">'.get_the_title($ancestor_id).'</a>'; } } if ($showThis) { echo ' > <a href="'; the_permalink(); echo '">'; the_title(); echo '</a>' . chr(10); } } // end buildBreadCrumbTrail
I’m still learning how Drupal (6) puts things together. We have a situation where we have a page that has an image attached to it. When we view the page, we need the full path to the image that’s attached. You would think it would be pretty simple. You would expect that somewhere in the $node object is a url for the image that is attached. But that’s just not the case.
Drupal calls the page a node. It also calls the image a node. You have a table that says “this node is attached to that node” by ids. Specificially, image_attach.nid is your page, and image_attach.iid is the node id of the image. Then you have an image table, which lists the images by node id, with a size, and a file id. (Confused yet?) We use image_attach.iid and the size we’re looking for to get image.fid. And then there’s one last table, which is files, which lists by id, and has the actual filepath. We can use image.fid to get the files.filepath we want.
So I wrote a function to do all of that nonsense for me. You pass it the node id of the page which has the image attached to it, and it returns the path/to/the/attached/image/thank/you/very/much.jpg.
function lookupImagePath($nid, $thumbnail = false) { if ($thumbnail) { $size = 'thumbnail'; } else { $size = '_original'; } $sql = 'SELECT f.filepath '; $sql .= 'FROM image_attach a, image i, files f '; $sql .= 'WHERE a.iid = i.nid '; $sql .= 'AND i.fid = f.fid '; $sql .= 'AND a.nid = ' . $nid . ' '; $sql .= 'AND i.image_size = "' . $size . '" '; $res = db_query($sql); $row = db_fetch_array($res); $filepath = $row['filepath']; return $filepath; } // end lookupImagePath