Apache 2’s CONTEXT_PREFIX and CONTEXT_DOCUMENT_ROOT Variables

There seems to be some discussion online, but no actual, y’know… documentation regarding these two server variables.

Apparently they were introduced in Apache 2.3, and they are wicked useful, it turns out. At least, wicked useful if what you want to do is figure out what the URL of a to a specific file on the server is, assuming that you have only its path and some other file’s URL.

What follows seems to be empirically correct, but I welcome corrections:

DOCUMENT_ROOT is the system file path to the root of the web server’s document directory (usually something like '/var/www/')

But, imagine that per-user web directories have been enabled on your server. That is, if my user is foo, then there is a directory /home/foo/public_html in which all of foo’s web documents are stored (and served from). This is (probably) outside of the main server document root directory. The URL of foo’s web files would be something like http://example.net/~foo/index.html.

And this is where our variables enter the story.

The Empirically-based Theory

CONTEXT_PREFIX is the portion of the REQUEST_URI that triggered the server to serve up a file outside of the document root. And CONTEXT_DOCUMENT_ROOT is the root directory that that particular CONTEXT_PREFIX is rooted at. Nota bene: conveniently CONTEXT_DOCUMENT_ROOT contains the path the document root for whichever context this particular script was accessed through (so it would be the same as DOCUMENT_ROOT within the server’s document root, while CONTEXT_PREFIX would be an empty string, since there is no context prefix within the server’s document root.

A file in a user web directory

Consider this extended example:

User foo has placed files in that user’s public_html directory. There are nested directories within that public_html directory, and we are accessing a file at this URL:

http://example.com/~foo/dir1/dir2/dir3/file.php?paramA=bar#baz

This file is stored at the following path in the file system:

/home/foo/public_html/dir1/dir2/dir3/file.php

Thus, a sampling of relevant server variables (presented in $_SERVER for the PHP users amongst us) would be:

REQUEST_URI is /~foo/dir1/dir2/dir3/file.php?paramA

SCRIPT_NAME is /~foo/dir1/dir2/dir3/file.php

CONTEXT_PREFIX is /~foo

CONTEXT_DOCUMENT_ROOT is /home/foo/public_html

A file within server’s document root

Alternatively, a similar example within the server’s document root:

http://example.com/dir1/dir2/dir3/file.php?paramA=bar#baz

is a URL that access a file at:

/var/www/dir1/dir2/dir3/file.php

This results in the following values:

REQUEST_URI is /dir1/dir2/dir3/file.php?paramA

SCRIPT_NAME is /dir1/dir2/dir3/file.php

CONTEXT_PREFIX is (the empty string)

CONTEXT_DOCUMENT_ROOT is /var/www

For giggles, I cooked up some code to generate the URL of particular directory based on this information. I used the following little snippet to do this in DataUtilities::overlap() in battis/data-utilities:

use Battis\DataUtilities;
 
$path = __FILE__;
$url = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != 'on' ?
		'http://' :
		'https://'
	) .
	$_SERVER['SERVER_NAME'] .
	$_SERVER['CONTEXT_PREFIX'] .
	str_replace(
		$_SERVER['CONTEXT_DOCUMENT_ROOT'],
		'',
		$path
	);

Why doesn’t Unity Remote work with my dang iPhone?

So, my students in Advanced CS are working on their second semester projects. One project group is working on mastering Unity to build an iPhone game, and they just spent several days struggling with getting Unity Remote to work with their iPhones.

After much Googling and exasperation, they figured out the answer (which was not, prior to this post.

They had been able to see the iPhone in the Unity editor. They had been able to set up the remote to use the iPhone in the Unity editor in project settings. But when they “played” their game in the editor, it just sat there inertly, waiting for a connection. Consternation. Rending of garments. So forth and so on.

The trick, it turns out, is that when one installs the Unity editor, one must install iOS development support. Not a shocker. But certainly worth mentioning in an error message somewhere.

Reliably Open iTunes Library on a Shared Volume

I just mentioned that my wife switches between two different iTunes libraries, including one that lives on a shared volume on our home server. There’s a great tip on Stack Overflow for writing a script to automate that swap between iTunes libraries (rather than having to hold down option while iTunes loads and then click around to find the library you want). But it seemed like it might be nice to document for posterity the full script that we’ve built, since it handles not just the library swapping, but also the mounting of the shared volume as well.

This script takes a little prep work, both generating the library location property and storing the authentication information in the user keychain. The Stack Overflow tip explains the former, and the latter is as easy as connecting to the server and remembering to check the “Save Authentication” checkbox during the authentication process.

-- set server connection information here
property serverProtocol : "afp://"
property serverName : "your-server-name-here.local"
property volumeName : "shared-volume-name-here"
 
-- define the desired library location and save the current library location (http://stackoverflow.com/a/1693973/294171 explains exactly how to generate the appalling hexadecimal value for iTunesLibraryLocation below)
property iTunesLibraryLocation : ""
property libraryLocationPref : "com.apple.iTunes 'alis:1:iTunes Library Location'"
 
-- try to mount share from server
try
	-- authentication credentials stored in keychain
	mount volume (serverProtocol & serverName & "/" & volumeName)
on error
	-- if we can't mount the share, we're done
	display dialog "The shared volume “" & volumeName & "” on the server “" & serverName & "” could not be mounted, so the remote iTunes Library cannot be used. Please check that you are on the same network as “Leviathan” and try again later." buttons ("Le sigh") default button 1 giving up after 15
	return
end try
 
-- quit iTunes if it's running
tell application "System Events"
	if exists (application process "iTunes") then
		tell application "iTunes" to quit
	end if
end tell
 
-- set the desired library location
do shell script "defaults write " & libraryLocationPref & " " & quoted form of iTunesLibraryLocation
 
-- comment the above shell script and uncomment the one below to use the default iTunes Library
-- do shell script "defaults delete " & libraryLocationPref
 
-- (re)open iTunes
tell application "iTunes" to activate

iTunes Locked Disk Error

A bit of background: my wife has an iTunes library that is too large to fit comfortably on her MacBook Air (in all fairness: I have an iTunes library that is too large to fit on her MacBook Air, my MacBook Pro and several other laptops as well). She maintains a local library on her laptop for use at school (useful movies, songs, etc.) and stores her “real” library on our home server. Which involves a bit of fiddling to get it to work. The key issue is that she needs iTunes to load her library off of a shared disk. And, periodically (maybe every couple of months), something goes haywire and she gets this error:

The iTunes library Library file is locked, on a locked disk, or you do not have write permission for this file.

Needless to say, this is exasperating.

There are a number of suggested solutions out there, and I keep forgetting to bookmark “the one” that works. On my last search, I realized that this was because none of them are really the answer that works in our situation. Here’s what works (and I’m posting this as a note for self):

  1. Disconnect the laptop from the server (quitting iTunes first, of course).
  2. On the server, unset the nouchg flag (not 100% that this is necessary 100% of the time, but it’s necessary at least some of the time):
    sudo chflags -R nouchg <path to iTunes folder>
  3. Reboot the server.
  4. Reconnect from the laptop and rejoice.

At least, that’s what worked this evening, and it felt really familiar. (There’s an unspoken step 2a, of course: cancel the multi-hour process on the server that you had queued up moments before iTunes started misbehaving. Argh.)

Doubled Google Calendars in iCal

So many of these entries are really just an attempt to make sure that the next time I go searching for an answer to some question, by gum there will be a search result. That is: I write up things that I couldn’t find an easy answer to, so that someone else reaps the benefit of my suffering.

But, sometimes, it’s just about admitting that I’m dumb.

Case in point: I’ve been grousing on Twitter about a number of things in the past week, one of which was that, for much of the fall, many of my Google calendars have been showing up in iCal doubled. Every event shows up twice. Sometimes more than that, when Google has a hiccup. And birthdays from my contacts have shown up as many as 34 times — no joke: I counted. But the core problem has been that I’ve been seeing many of my Google calendars twice in iCal. It makes me feel busy, but otherwise it serves no purpose.

And then it hit me this evening, as I was looking at the list of calendars in iCal: with the launch of Mountain Lion, Apple revised how it handled Mail, Contacts & Calendars — so much so, in fact, that they created a separate prefpane for it. That connects to iCal, Mail and the Address Book pretty transparently. Before that upgrade, to see secondary Google calendars (the ones other than your primary calendar — a distinction about which I have some more grousing to do at a later date), you had to enable calendar delegates in the Accounts section of the iCal preferences. It was messy, and ugly (you had both the delegate and the calendar nested in the delegate… for each and every calendar). But it worked.

I never turned off the delegates when Apple upgraded to Mail, Contacts & Calendars. So I was seeing both the delegate calendar and the calendar associated with my Google account in Mail, Contacts & Calendars.

For dumb.

I just turned off delegates and everything got better. Except maybe those duplicated birthdays… we’ll see what happens with them.

Embed YouTube Playlist in IFRAME-unfriendly Blackboard 8

YouTube has changed their embed codes (several years ago) to IFRAMEs, replacing the old object embed codes. Turns out that on older web-based WYSIWYG-editors, such as Blackboard 8, the IFRAME embed codes get munged up, often with deleterious effects. In Blackboard, for example, you might lose the ability to see, edit or use a content area in which an IFRAME has been embedded. This. Is. Bad.

YouTube lets you switch to their old embed code for individual videos, but no so to embed a playlist. I wanted to embed a playlist, so I took a look at the object tag specs and the IFRAME embed code and came up with a simple script that generates an old-style object embed code for a YouTube playlist IFRAME embed code, thus:

Paste a YouTube playlist embed code below.

Moving iMovie ’11 Events and Projects to a Custom Location

I’m about to embark on a group video project in my New Media class. To that end, it’s a hassle when the video (and script!) exist only in the account of one of the group members. I saw one suggestion for how to store the iMovie events and projects on an external drive, which seemed deeply convoluted and, well… a hassle. I’m not interested in purchasing or setting up external drives, or in going through that rigamarole to set it up.

So, it occurred to me that /Users/Shared/ is a pretty fine place to store shared files. And that the modern Mac OS X seems to honor symlinks pretty regularly (something I use all the time to sync my life across machines using dropbox — symlinking whole directories to sync preferences, settings and documents that the developers haven’t — yet — moved to the cloud.)

It seems to work for iMovie as well. Here’s how I did it (stay tuned to see if it blows up on my students!):

  1. Trash the iMovie Events folder in the user’s Movies folder. (This assumes that this is, essentially, a clean install of iMovie — no previous events or projects to worry about. That’s my situation).
  2. Create a new iMovie Events folder in /Users/Shared/ (note that it is created there, not moved or copied there, so that it will inherit permissions from the Shared directory).
  3. Set the permissions on iMovie Events to let everyone read and write. I like the terminal for this:

    chmod -R a+rw /Users/Shared/iMovie\ Events
  4. In the terminal, create the symlink:

    ln -s /Users/Shared/iMovie\ Events ~/Movies/iMovie\ Events

    (Note that the space in “iMovie Events” needs to be escaped with a backslash!)

  5. In iMovie, create new projects on the hard drive (probably called Macintosh HD), rather than the user’s home folder. This will put the projects in /User/Shared/ (I didn’t know that until this experiment — cool!)

In my limited testing, this seems to work transparently. The biggest caveat is the permissions change. When creating events, iMovie seems to strip the write permissions off of the inherited permissions for the iMovie Events folder (but other users can still read and execute, which should be fine). Similarly, it’s possible that other users can only read (but not edit) the shared project.

We shall see.

Linking to a Cell in a Google Spreadsheet

Because I can’t stop playing with something that already works fine, I’ve continued to tweak my syllabus-generating spreadsheet. With the addition of an external script, I’m able to link directly to a specific cell in the spreadsheet — letting me share a link to my syllabi that takes people not just to the overall document, but to the current day (or the next day that’s closest to the current day) in the syllabus. The script could be used to link to any cell in any published Google Spreadsheet, with the caveat that if there are multiple cells with that match that value, the link will take you to the first appearance of the value in the spreadsheet.

$url = $_REQUEST["url"];
$key = $_REQUEST["key"];
$anchor = $_REQUEST["anchor"];
 
$html = file_get_contents($url);
$output = str_replace($key, "<a name="$anchor"></a>$key", $html);
$output = str_replace("href='/", "href='https://docs.google.com/", $output);
 
header("Content-Type: text/html");
echo $output;

This takes a GET URL of the format http://server/script?url=[url]&key=[key]&anchor=[anchor]#[anchor], where…

  • The URL is the URL of the published Google spreadsheet location.
  • The key is the text to search for in the spreadsheet (so you could link to anything in the published HTML, but it’s easiest to link to a unique value in a cell).
  • The anchor is the name of the HREF anchor you will be creating (note that you then need to, well… link to that anchor).
Enjoy. You can try it out on my server:
URL:
Key:
Anchor:

Nota Bene: You have to add your own link to the anchor — this is a quick, slapped-together connection to my script.

Update: I was sitting here staring at the script, trying to figure out why I hadn’t put the anchor tag around the key, and then I realized what’s going on. The key (on my spreadsheet) is formatted to be white text on a white background (Rothko-style, if you will). If it gets converted to an anchor, its styling is affected and (without more work in the script) it turns blue and underlined. Lame. So… the anchor goes before the key, so the key’s CSS style won’t be affected.

This is why you document your code. Even when it’s short.

Visual Homework Policy

Click to download a PDF of this. Feel free to reuse it — just let me know, especially if you make any particularly effective tweaks.

This policy has been gestating for some time, and I started to formulate it in conversation with one of my students who had had a brush with the academic dishonesty fairy. I presented it in class last week, and I realized that it is as good a representation as I have of my homework policy. I’m not really interested in coming up with a suitably punitive formula for docking grades for lateness, and I don’t particularly care about negotiating reasonable extensions. Mostly, like my students, I just don’t want to be bothered. But, by golly, there are things that bother me, and it would be good to steer clear of them. And it’s worth knowing how they rank in my worldview. And this expresses it.

Better not to do your work than to cheat or plagiarize to finish your work. Better to ask for an extension at the last minute than to just not do the work. But noticeably better to ask for the extension in a timely manner.

I’m pretty sure that this both made sense to and stuck with my ninth graders.

Better Ways to Share Documents (than Email Attachments)

I had hoped that someone else would have put together a handy flyer to explain better options for sharing files than sending email attachments. But in a casual search of the web, none came up. This is my initial pass at the problem of presenting the Web 2.0 and the cloud to folks who are comfortable with email, but who don’t feel confident in their use of other technologies.

The first pass is truly aimed at providing a flyer that could be tacked up next to someone’s monitor.

http://www.scribd.com/doc/111473318/So-I-want-to-share-a-document-smartly%E2%80%A6

I made a second version, which I posted to Google Docs, so that the links are clickable as well.

If you’d like to examine the assumptions and reasoning behind this, I have a flowchart that I felt… might not be as helpful in conveying these ideas.

For what it’s worth, when I was discussing the response to this broadsheet (broadside?) among the folks at school, my wife asked me if I sent this as an attachment.

She’s a funny one.