OTFG: Syndication, Exif Data, and Tags
Now that I'm off the photo-hosting grid and have my local photoblog up and running, I've been working on some of the extra features. This week I set up an RSS feed and JavaScript syndication, grabbed Exif data from my photos, and set up a way to browse photos by tag. I won't go into great detail about my thinking on these—I'll just share my code and describe how I set up each one briefly.
One of Flickr's nice features that I was using before my move was their JavaScript badges. With a few lines of CSS and a single line of JavaScript, you can include a strip of photos on any website. I was using a vertical strip of five photos (check "now seeing" in the right sidebar on the front page of this site for an example). I decided to throw this together for my local photoblog, and here's the file that generates the JavaScript that generates the strip: js.php. Nothing too tricky going on here, just a
I store both rss.php and js.php outside of my public web directory. I run them every hour, piping the output to a couple of files in the public web directory. To accomplish this with Windows Task Scheduler, I have a simple
So I just run this batch file every hour and that way the feed and JavaScript file are cached and won't be re-built each time someone requests it.
I set up an .htaccess entry for the feed so it has a nicer URL:
Because the Exif data is embedded directly in the original photographs, I could just grab this info on-the-fly to display it on the site. (PHP 5 has a few Exif functions that make snagging this data fairly easy.) But I'm guessing down the road I'd like to do more with this data, such as grouping all photos by a particular camera together, or grouping all photos taken with my 50mm lens together. More control means storing everything in the database, and I put together a table called exif and a generic function to grab/store the data.
Here's the SQL to build the table: otfg_tables_6.txt, and here's the include file with the exif-grabbing function: addExif.inc. The function
After running this script I had a table full of Exif data, and I found out that 490 of my 840 photos had Exif data. Unfortunately my cell phone strips Exif data from photos before it sends them via email, which means my cell phone pictures (a large percentage) don't have any Exif data to extract. One improvement to this process that I need to write soon is setting the DateTaken value in the photos table based on the Exif DateTimeOriginal value. That way I can display both the time the photo was posted, and the time the photo was actually taken.
I'm displaying the Exif data on the photo detail page, as a single line of text. For example, the photo bandon beach shows the following Exif line below the photo:
This Exif line lists the camera make and model, the shutter speed, the aperture, and the focal length. I'll probably add ISO and exposure bias eventually because I like to see that data too, but I thought these were the basics.
Today I put together a standard tag cloud so I can visualize how I'm using tags. As usual, the larger the tag, the more frequently it's used, with red tags the most-used. Here's the code for this: tags.php.
All of this tagwork required some significant changes to photo.php and editing.js. Both of these updated scripts are getting more complex by the hour. (Beyond the tag stuff, I also improved some other JavaScript editing functions so simple HTML won't wreak havoc in captions.) I also added a few more entries to the .htaccess file to handle this new tag-space:
This just cleans up the URLs for tag pages, and paging through photos there. As you can see, photo stubs under /tag/ are just routed back to photo.php along with the tag itself. (This is also some good foreshadowing for how I'll probably handle galleries since these are basically just tag-galleries.)
All in all, going off the grid is going well. I still have a long to-do list, but I feel like I crossed some of the big features and fixes off my list this week.
Syndication
The RSS feed was fairly easy to put together. Here's the code that generates the feed: rss.php. I added a few extra constants to the ini.inc file that's included on every page because they were needed in the feed: APP_TITLE
, APP_DESCRIPTION
, BASE_URL
, PHOTO_URL
, and PHOTOGRAPHER_NAME
. I also went back through each file in the application and substituted these constants where I'd hard-coded the values. (This will make it easier to change these variables globally in the future, and it makes the code more reusable.) And I went with full-sized images in the feed. Here's the live feed if you'd like to check it out.
One of Flickr's nice features that I was using before my move was their JavaScript badges. With a few lines of CSS and a single line of JavaScript, you can include a strip of photos on any website. I was using a vertical strip of five photos (check "now seeing" in the right sidebar on the front page of this site for an example). I decided to throw this together for my local photoblog, and here's the file that generates the JavaScript that generates the strip: js.php. Nothing too tricky going on here, just a
document.write
of some HTML that displays the smaller-sized thumbnails of recent photos.
I store both rss.php and js.php outside of my public web directory. I run them every hour, piping the output to a couple of files in the public web directory. To accomplish this with Windows Task Scheduler, I have a simple
.bat
file that looks like this:
C:\path\to\php\php-win.exe C:\scripts\js.php > C:\web\site\include.js
C:\path\to\php\php-win.exe C:\scripts\rss.php > C:\web\site\rss.xml
So I just run this batch file every hour and that way the feed and JavaScript file are cached and won't be re-built each time someone requests it.
I set up an .htaccess entry for the feed so it has a nicer URL:
RewriteRule ^feed/?$ rss.xml [L]
. I'm the only one consuming the JavaScript, so that URL can be as ugly as it wants to be.
Exif Data
Most (if not all) digital cameras embed some information about the state of the camera within the photo files themselves using a format called EXIF. Flickr made great use of this data with a special page that displays quite a bit of the Exif data available in uploaded photos. (For example, More detail about bandon beach.) The Exif data gives you a quick look at your shutter speed, aperture, focal length, and a few other settings. I think it helps to look at Exif data frequently so I can remind myself which settings worked or didn't work for any particular type of photo.
Because the Exif data is embedded directly in the original photographs, I could just grab this info on-the-fly to display it on the site. (PHP 5 has a few Exif functions that make snagging this data fairly easy.) But I'm guessing down the road I'd like to do more with this data, such as grouping all photos by a particular camera together, or grouping all photos taken with my 50mm lens together. More control means storing everything in the database, and I put together a table called exif and a generic function to grab/store the data.
Here's the SQL to build the table: otfg_tables_6.txt, and here's the include file with the exif-grabbing function: addExif.inc. The function
addExif()
accepts a PhotoID and database connection, finds the original file for that photo, and extracts and saves the Exif data. I went back and added this function to the uploading files (Step 10: Adding Photos), and whipped up a quick script to add Exif data for existing photos: setExif.php.
After running this script I had a table full of Exif data, and I found out that 490 of my 840 photos had Exif data. Unfortunately my cell phone strips Exif data from photos before it sends them via email, which means my cell phone pictures (a large percentage) don't have any Exif data to extract. One improvement to this process that I need to write soon is setting the DateTaken value in the photos table based on the Exif DateTimeOriginal value. That way I can display both the time the photo was posted, and the time the photo was actually taken.
I'm displaying the Exif data on the photo detail page, as a single line of text. For example, the photo bandon beach shows the following Exif line below the photo:
This Exif line lists the camera make and model, the shutter speed, the aperture, and the focal length. I'll probably add ISO and exposure bias eventually because I like to see that data too, but I thought these were the basics.
Tags
I've also added some features around tagging. Each tag listed on the photo detail page is now linked to a tag page where viewers can see all photos with that particular tag. One example is the tag page for architecture—a tag I've used frequently. Here's the code for this page: tag.php. As viewers click photos from the tag page, they're able to stay within that tag context. So all of the back/next controls on the photo detail page reflect the viewer's most recent choice. The photo detail URL is also under the /tag directory to reflect the different context. (I've set up my robots.txt to ask robots to ignore the /tag directory so there aren't multiple locations for photo detail pages.)
Today I put together a standard tag cloud so I can visualize how I'm using tags. As usual, the larger the tag, the more frequently it's used, with red tags the most-used. Here's the code for this: tags.php.
All of this tagwork required some significant changes to photo.php and editing.js. Both of these updated scripts are getting more complex by the hour. (Beyond the tag stuff, I also improved some other JavaScript editing functions so simple HTML won't wreak havoc in captions.) I also added a few more entries to the .htaccess file to handle this new tag-space:
RewriteRule ^tag/(.*?)/(\d{1,2})/$ tag.php?tag=$1&page=$2 [L]
RewriteRule ^tag/(.*?)/(\d{4}/\d{2}/.*)$ photo.php?p=$2&tag=$1 [L]
RewriteRule ^tag/(.*?)/$ tag.php?tag=$1 [L]
This just cleans up the URLs for tag pages, and paging through photos there. As you can see, photo stubs under /tag/ are just routed back to photo.php along with the tag itself. (This is also some good foreshadowing for how I'll probably handle galleries since these are basically just tag-galleries.)
All in all, going off the grid is going well. I still have a long to-do list, but I feel like I crossed some of the big features and fixes off my list this week.