Tracking and Protecting Web-Based Downloads (In PHP)

There’s a consistent need to either protect a file from being downloaded unless a user has been properly authorized/authenticated to access it or to track those files using a JavaScript tracking system like Google Analytics. I ran into this issue a few years ago and came up with what I thought was an elegant solution given the parameters – access those files using a PHP page.

The idea is simple: Send the filename as part of a request to a specified php page (in this case, download.php). That page will perform whatever authorization/authentication checks are necessary, ensure the file exists and – if everything passes muster – immediately begin sending the file to the user’s browser. You can use Google Analytics to track these downloads as well either by using the PHP CURL library or creating a redirect page.

Here’s some generic code to show this in action. Please Note: this code is an edited version from a full set of code. I’ve tried to make this standalone, but I haven’t actually tested it. You’ll want to fill in the blanks and give this a shot yourself – this is not a simple drop-and-go solution.

<?php
	//If you need to confirm that this user is logged in, etc.
	//you should handle the authentication/authorization stuff
	//here

	//Set this to wherever you will be storing the actual files
	define('DOWNLOAD_PATH', '/home/username/protected_files');

	//Format of URL: http://www.mysite.com/download.php?f=
	$filename = $_REQUEST["f"];
	$filePath = DOWNLOAD_PATH."/".$filename;

	//Handle this error however you want.
	if(file_exists($filePath)) {
		trigger_error("Could not find file: ".$filePath, E_USER_ERROR);
		exit();
	}

	$pathParts = pathinfo($filePath);

	header("Server: Apache/PHP", true);
	header("Cache-Control: no-store, no-cache, must-revalidate", true);
	header("Keep Alive: timeout=15; max=89", true);
	header("Connection: Keep-Alive", true);
	//NOTE: mime_type is a custom function - see below
	header("Content-Type: ".mime_type($filePath), true);
	header("Content-Disposition: attachment; filename=\"".$pathParts["basename"]."\"", true);

	//readfile() outputs the given file directly to the buffer which, in this case, goes to the browser.
	if(!@readfile($filePath)) {
		//Handle this error however you want
		trigger_error("Failed to open and read file ".$filePath, E_USER_ERROR);
		exit();
	}

	/**
	 Determines the MIME type of the given file. Requires a valid mime types file.

	 @param $file The file name/filepath fo the file being checked.
	 @returns string a mime-type string for a content header based on the file extension if found, otherwise returns false.
	*/
.
	function mime_type($file) {
		//Replace with the location of your mime.type file (I got mine from Apache)
		$mimeFile = "./mime.type";
		$mimeFound = false;
		$mime = -1;
		$fileInfo = pathinfo($file);
		if(is_file($mimeFile)) {
			if($fp = fopen($mimeFile, 'r')) {
				while ((!feof($fp)) && !$mimeFound) {
					$string = fgets($fp, 4096);
					$tempArray = preg_split("/\s+/", $string);
					//Eliminate comment lines
					if(!(strstr($tempArray[0], '#') == 1)) {
						for ($n = 1; $n < sizeof($tempArray); $n++) {
							if(strtolower($tempArray[$n]) == strtolower($fileInfo["extension"])) {
								//Found the mime type!
								$mime = $tempArray[0];
								$mimeFound = true;
								break;
							}
						}
					}
				}
				fclose($fp);
			} else {
				trigger_error("Cannot open ".$mimeFile, E_USER_WARNING);
			}
		} else {
			trigger_error("Cannot find ".$mimeFile, E_USER_WARNING);
		}
		return $mime;
	}

?>

Career Changes and Such

Been quiet here lately. Too quiet. I’m hoping to fix that.

In September, I was presented an opportunity to begin working for a company for which I have a great deal of respect in a position that was ideally suited to my unique set of skills as both a programmer and a strategist. In October, I began working full time for VerticalResponse as their Partner Integration Manager. I support the Partner API, which represents an incredible revenue opportunity to those offering software as a service who are looking quickly and easily add email marketing services to their mix of offerings.

This is the first job I’ve had where programming was not one of my chief duties, though I’m still producing a lot of code for testing, support and proof-of-concept purposes. This has freed me up a bit to explore some other topics of programming in my spare time – specifically, programming for my new HTC Hero with Google Android. I’m also being tasked with creating a developer community around our API, which is, perhaps, the one opportunity that has me the most excited about this big change.

My goal here is to continue writing about programming and web development topics as I see fit, as well as discuss some of my experiences facing the challenges of my new position. I hope you’ll stick with me through the ride and let me know what you’d like to talk about. I’m also working on a couple of WordPress plugins that I hope to release soon that I will continue supporting here. If you’re not already subscribing to this blog via email, Twitter or RSS, why not start now?

American Sign Language and User Interfaces

I’ve recently become intrigued by the concept of “Baby Sign Language” and the idea that my 10-month-old son, who’s not quite yet up to walking, may be able to communicate with me using his hands. To explore this, I sat down with a baby signing book that described pictorially many of the signs that could be useful to teach to my son. In order that we both learn a useful skill, all of the signs are taken directly from American Sign Language (ASL).

What really struck me about ASL is how easy it is to learn new words. Just about every sign has a real-life analogue that makes it easy to remember. The sign for “ball” for instance is made by putting your hands together as if you’re holding an invisible ball. The sign for “boy” has you drawing your hand away from your forehead as if you’re stroking the bill to a baseball cap.

This all came to mind this morning as I was building a small, simple database in Microsoft Access for a client. I had two Excel files that I needed to match using the email column in each of them. I imported both tables into Access, then went to create a query using the query designer. Identifying which fields to include in the output for the query was a no-brainer – for each field I wanted, I just double clicked on it in the table at the top and it appeared in the query below. Figuring out how to set the criteria for each table, however, was not so simple.

I tried clicking on the first criteria row for the email output column for table A, then double clicking on the email column in table B to signify that I needed them to be equal. That didn’t work. I thought through all of the ways that should work, then realized there was a SQL view I could be using. Thank God I know SQL – I’d think a majority of the target market for Access does not.

The key and mouse combinations I was using in the design view are what made me think of ASL – I was using my hands to communicate with the program instead of my words. When I switched to SQL, it was like I was speaking in the program’s native tongue. I’m certain there’s a way to use gestures to fill in the criteria for each column, but none of the ones I’m familiar with seemed to work.

In ASL, if I’m speaking with someone who’s deaf and I don’t know a particular sign, I can either spell out the word using the ASL alphabet or pantomime what I’m trying to say. In either case, the meaning is likely to come through. User interface designers could take a cue from this – they should consider all the ways in which a user, communicating with the program using only a keyboard and mouse, might be able to convey their meaning to the program and attempt to implement as many of these as feasible. It’s definitely a lot of work, but the increase in usability would be worth it. Not every Access user knows to type in the table name and field name in the criteria box to indicate equality. My act of trying to drag a field or click on the field I wanted to appear in that box is not at all an unreasonable assumption for communicating my desire to the program. Adding a function to properly react to that gesture wouldn’t be a huge burden, and it would have made the process of creating this query so much faster.

Perhaps it should be a requirement of UI designers to learn some ASL.

How To Program Like Mahatma Gandhi

“Be the change you want to see in the world.”

If you work with software long enough, especially open source software, you’ll find yourself saying the words, “This is great, but it would be INCREDIBLE if it could…” If you work with closed source software – that is, software that you’re not allowed to modify – the best you can hope for is to let the development team know of your wishes and hope and pray they add them to the next release.

If you’re working with open source software, you have an opportunity to make actual change. You may have noticed that I’ve recently posted a couple of downloads for WordPress plugins. I’ve been working on a new site built entirely using WordPress and free plugins, all of which are open source. It’s unbelievable what you can do with just these resources, but there were a few instances where I needed just a wee bit more than the plugin could provide.

Since they were open source to begin with, and since I knew I wasn’t the only one who would need them, I went in and made the changes myself. I’m fortunate in that I’m a PHP expert – making these changes was a pretty trivial process once I understood how WordPress’s plugin architecture worked. Still, it cost me time – probably about five hours total – which does directly translate into time taken away from paying client work. While it did cost me something, it was a rather small price to pay considering how much time I saved by using the original plugins to begin with. I felt these plugins needed something added, so I took the time and added them. Since they were open source to begin with, I re-released them on my own site with my added code intact so that others can use it and modify it as needed. I saw a change I felt needed to happen, I made it happen and now, the world benefits.

But we’re not here to talk about how awesome I am. This idea of improving on something and giving it back to the community is the core of the open source business model. If you don’t have the money to contribute to something, you should contribute your time and talents. If you see a need in the software world, you should take steps to fill it. Too many people whine about what should be, not enough people take action to make it as it should be.

But what if you’re not a programmer? If a project you admire needs your talents – marketing, evangelism, graphic design, etc. – you can build a great reputation by pitching in. If that doesn’t work, why not adopt a programmer? For example, if I was unable to modify the plugins I needed changed for my application, I could have hired a programmer to do it for me, then re-release those changes for all to use, thus strengthening the overall community. If that was cost prohibitive, perhaps I could have pooled my money with other non-programmers who need the same things and together we could hire someone who can make it happen. I could have found these like-minded souls in the comments sections on the plugin homepages – they’re frequently filled with messages saying, “Great plugin, but I need it to…” with no offers of either talent or money.

Open source software is never free. Programmers pay for it with their time and knowledge. They’re compensated either with money from the clients they’re working for or by using other open source code from like-minded programmers. It’s that old time = money value exchange. If you value a project and want to see it evolve to better meet your needs, then take it upon yourself to make it happen!

Download: Widgetized PHPList Integration Plugin for WordPress

Can you guess that I’m working on a WordPress-driven site? I launched Get Out Bay Area quietly last week and have been slowly adding more functionality to it. One of the big pieces is a newsletter component, which I’ll be using PHPList to run. Jesse Heap took the time to write a plugin that integrates PHPList with WordPress and damned if it didn’t work great out of the box. The only thing missing was the ability to add it as a widget. So, riding on the success of widgetizing the Google Calendar Parser, I decided to widgetize this bad boy. So, here it is:

Download the Widgetized PHPList Integration Plugin

I take no credit or responsibility for the original – all I did was add the widget part. Thanks again to Jesse Heap for the original – it was exactly what I needed.

Download: Rob Z’s Widgetized WordPress Google Calendar

First off, I did NOT write the bulk of this code – the bulk of it was written by Justin Bennett and the original can be found on his site. I take no responsibility or credit for the original code, only for my modifications. Having said that, the original version totally kicks butt.

The Google Calendar Feed Parser takes a Google Calendar Feed URL and… well, parses it for display on WordPress. The original version required you to embed the code somewhere in your template, but WordPress’ new widget infrastructure makes it so you shouldn’t have to do that. Justin didn’t get around to widgetizing his parser, so I did it for him ’cause I needed it NOW! 😉

You can download my version of his feed parser – complete with widget – by clicking here: WordPress Google Calendar Feed Parser Plugin with Widget.

The Importance of Following Code Conventions

I’ve found one of the trickiest issues in working with other people’s code is trying to decipher the way they do things programmatically. You can learn an awful lot about how a programmer thinks by reading their code. All too often, the first thing I learn is that they’re wildly disorganized.

Freelancers are frequently self-taught and lack the experience of working in an environment with a lot of other programmers. As a result, they only ever program for themself – not for the poor schlep (me) who has to come along later and try to figure out just what the heck they were trying to do. There’s a distinct lack of useful comments, consistent code structure or well-named functions and variables.

When you work in an environment with a group of programmers, the project lead should define the code conventions that all the programmers need to follow, enforcing them during regular code reviews. This creates a discipline a lot of solo coders lack.

I’ve been lucky to work within groups of programmers, so I know how valuable setting such code conventions can be. When I went out to find freelancers to help us at TechKnowMe, the very first thing I did was set up a code conventions document I expected everyone to follow. It’s very short and very simple. You can download it as a PDF here:

The TechKnowMe Coding Conventions Document

In it, I define my general programming philosophy so that those working with me understand where I’m coming from and what I expect. I then go into the details of how functions and variables should be named and even where brackets should appear. Much of what is in this doc should not be uncommon to most professional programmers, but if you’re a freelancer working alone, I’d strongly recommend adopting either the policies laid out here or setting some of your own.

Of course, creating code conventions is the easy part. Developing the discipline to actually stick to them is the real tricky bit. It’s this discipline, however, that separates the amateur hobbyist from the professional developer.


Why I Built The TKM Website Manager

In the previous post, I railed against custom code, then made a wane effort to defend my decision to create a custom CMS. The TKM Website Manager, which is currently only available to my clients, but which I’ve been debating releasing under the GPL or MPL, was designed to address a fatal flaw I’ve seen with most content management systems out there. Specifically – it works the way users expect a website manager to work.

We have trained users to think of web sites in terms of pages and URLs. In the past, when we worked primarily with static sites, we’ve given our users tools like Dreamweaver or Contribute to make content updates – tools that are either wildly dangerous if the user doesn’t have the time to really learn them or wildly inadequate, especially now that a majority of sites are dynamic and database-driven. Despite those flaws, they at least stuck with the page/URL paradigm.

Continue reading Why I Built The TKM Website Manager

The Problem With Custom Code

It seems these days that 90% of my work is cleaning up after other programmers. My annoyance with this fact – and the solutions I think you as programmers, designers, etc. should use – will probably become one of the major themes of this blog.

There’s a desire among us to create, and that’s a worthy desire. However, the requirements for so many small business sites are so simple and common that creating new code from scratch to run them is not only inefficient, it’s downright dangerous. There’s no such thing and “clean” code – all code is buggy to one degree or another. Custom code, which has been exposed to a much smaller audience of developers and seen limited public release, has the potential to be among the buggiest, most insecure code of all.

Continue reading The Problem With Custom Code

JSRedir-R / Gumblar.cn – I Can Clean It Up For You

I’m kinda hoping this will be my last blog post on this topic – I’m afraid this blog is going to get pigeon-holed as the “JSRedir-R / Gumblar.cn” blog.

I now have quite a bit of experience cleaning the Gumblar trojan out of servers, so if you’re not especially technically inclined or would rather just have someone else deal with it, Give me a call at 925-246-5449 or use the handy contact form. My rates are reasonable considering the amount of work this takes and I should be able to get it done within a day. I won’t be available starting Friday until Tuesday morning, though, so you may want to get on the schedule now.