Error message

Notice: Undefined index: localized_options in menu_navigation_links() (line 1861 of /net/council/home/www/drupal/includes/menu.inc).

Drupal 7 Core Cache Won't Follow Symlinks (Workaround)

Well, I just finally worked through a nasty bug of sorts present in Drupal 7 caching logic.

It is very, very closely related to this bug:

http://drupal.org/node/155781

I always hated this issue with my Drupal 6 install, and I had to use that 'hack' to get imagecache working. The suggestions around the net seemed to imply that with the re-working that Drupal had done for the Drupal 7 core related to the 'files' storage, plus the fact that this same 'caching' logic had been built into Drupal 7 that this issue would no longer apply. Well let me say very, VERY clearly, '''this is not the case, this issue does still entirely exist in Drupal 7, it's just now wonderfully built into core'''.

Really, 1/2 the reason I was excited to upgrade to Drupal 7 was to put this issue in the past and no longer have to comment out part of their security model just to have perfectly valid code work with symlinks. No deals.

The work-around is pretty much identical to the fix in the post above, applied to the Drupal 7 core code where the name of the function has changed.

Fix is this, in the file includes/stream_wrappers.inc, in function getLocalPath, around line 361, comment out the following lines:
{{{
if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) {
return FALSE;
}
}}}
So they read like
{{{
#if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) {
#return FALSE;
}}}
For example

'''NOTE: This is a security risk of sorts and I am not trying to downplay this!!!''' What this code is supposed to do is recursively validate the path that is passed into it as existing at the explicit location as passed into the function. One thing that it is checking is that the path is not using '..' in it's path. There may be other security-sensitive cases where this check also would correctly return false. However, since when it's logic plays out if it is traversing and checking a symlink it also then returns the physical path once it crosses the symlink into the target directory and that 'if' statement which is commented out returns false because it can't meet the 'strpos' check. There are 2 things of note here regarding this check in the context where I use it. First, if I link directly to the path of an image inside the symlink directory as a path for an image for example, Drupal will display the image happily, but if I pass that same path then into a function to create the cache/thumbnail version (in my case) it fails to generate a thumbnail for a location that it could otherwise display and access.... seems broken to me. Second, the security check to prevent parent paths can be handled by appropriately configuring apache2 and php outside of Drupal, so a 'correctly' and 'securely' configured apache2 web server makes this check somewhat irrelevant.

Bottom line, IMHO, Drupal should not be breaking the use of symlinks in this nature. I have a folder where I keep my pictures when I take them off a camera and carefully archive them, this is outside the web root. I like the Drupal configuration in the sense that it expects all paths to exist below it's destination for 'public' or 'private' files. I wish to use and allow direct, read-only, properly configured, properly chmod'ed access to my pictures (and music and movies later) and creating a duplicate copy is absolutely not in my interest. Symlinks have existed in linux for ages for this purpose, no other linux systems refuse to handle symlinks as normal files. So, even though this is in the name of security, this shouldn't be the first exception to this rule!