15.9.1 Problem
15.9.2 Solution
Don't keep the
images in your document root, but store them elsewhere. To deliver a file,
manually open it and send it to the browser:
header('Content-Type: image/png');
readfile('/path/to/graphic.png');
15.9.3 Discussion
The first line in the Solution sends the
Content-type header to
the browser, so the browser knows what type of object is coming and displays it
accordingly. The second opens a file off a disk (or from a remote URL) for
reading, reads it in, dumps it directly to the browser, and closes the file.
The typical way to serve up an image is to use an
<img> tag and set the src attribute to point to a file
on your web site. If you want to protect those images, you probably should use
some form of password authentication. One method is HTTP Basic Authentication,
which is covered in Section 8.10.
The typical way, however, may not always be the best. First,
what happens if you want to restrict the files people can view, but you don't
want to make things complex by using usernames and passwords? One option is to
link only to the files; if users can't click on the link, they can't view the
file. They might, however, bookmark old files, or they may also try and guess
other filenames based on your naming scheme and manually enter the URL into the
browser.
If your content is embargoed, you don't want people to be able
to guess your naming scheme and view images. When information is embargoed, a
select group of people, usually reporters, are given a preview release, so they
can write stories about the topic or be ready to distribute it the moment the
embargo is lifted. You can fix this by making sure only legal content is under
the document root, but this requires a lot of file shuffling back and forth from
directory to directory. Instead, you can keep all the files in one constant
place, and deliver only files that pass a check inside your code.
For example, let's say you have a contract with a publishing
corporation to redistribute one of their comics on your web site. However, they
don't want you to create a virtual archive, so you agree to let your users view
only the last two weeks worth of strips. For everything else, they'll need to go
to the official site. Also, you may get comics in advance of their publication
date, but you don't want to let people get a free preview; you want them to keep
coming back to your site on a daily basis.
Here's the solution. Files arrive named by date, so it's easy
to identify which files belong to which day. Now, to lock out strips outside the
rolling 14-day window, use code like this:
// display a comic if it's less than 14 days old and not in the future
// calculate the current date
list($now_m,$now_d,$now_y) = explode(',',date('m,d,Y'));
$now = mktime(0,0,0,$now_m,$now_d,$now_y);
// two hour boundary on either side to account for dst
$min_ok = $now - 14*86400 - 7200; // 14 days ago
$max_ok = $now + 7200; // today
// find the time stamp of the requested comic
$asked_for = mktime(0,0,0,$_REQUEST['mo'],$_REQUEST['dy'],$_REQUEST['yr']);
// compare the dates
if (($min_ok > $asked_for) || ($max_ok < $asked_for)) {
echo 'You are not allowed to view the comic for that day.';
} else {
header('Content-type: image/png');
readfile("/www/comics/$_REQUEST['mo']$_REQUEST['dy'] $_REQUEST['yr'].png");
}