Drupal
How to make Drupal 5.x work properly on Nearly Free Speech
Submitted by dmuth on Wed, 2008-02-20 22:29. Blog | DrupalWhen it comes to webhosting, you can't beat NearlyFreeSpeech. They're cheap, fast, and reliable. I've been a very happy customer for years, and run a number of Drupal installations under them.
However, NFSN does do things a little differently, and this can cause some interesting interactions with Drupal. The main thing that they do differently is that they use Squid and run reverse proxies at the edge of their network, which cache requests made to member websites. For most sites, this is not a problem. Drupal, however, tries to be "cache friendly" with regards to the headers it emits, and sometimes this doesn't work so well. I've seen the following symptoms happen under a virgin Drupal installation:
- Going to the site, and instead of getting the page you wanted to see, having the file download dialog come up.
- Seeing stale copies of pages.
- Logging out, and seeing pages indicating that you are still "logged in".
- Logging in, and seeing pages indicating that you are still logged out.
Here's how to fix that:
- Open the includes/bootstrap.inc file, taking care to make a backup copy first.
- Go to the function drupal_page_header() and replace the calls to header() with the following calls:
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate");
header("Cache-Control: post-check=0, pre-check=0", FALSE); - Continue down until you get to the drupal_page_cache_header() function. Comment out the header() call that emits a "304 Not Modified" header" and the following exit() call there. The rest of the header() calls in that funciton should be left alone.
- Finally, to assist with troubleshooting, edit the page.tpl.php file for whatever theme you are using, and add the following line in the footer:
Page last generated: <?php print date("r"); ?>By examining that line, you can tell whether you are retrieving the most recent copy of the page or not, and this can be a valuable tool in troubleshooting cached pages.
Once all of those things are done, any cache issues that your users are experiencing should slowly go away.
Finally, I must admit that I am not any sort of HTTP guru. I merely followed what I read in these specifications:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4
If you know of a better way to fix this problem, feel free to let me know...
Why I love relational databases (oh, and Drupal too)
Submitted by dmuth on Sun, 2008-01-20 13:17. Blog | DrupalThe problem
After I brought Anthrocon's room share and ride share forums online, I noticed that last year's posts were still present. This was a problem because people needing rides or rooms for this year's conventions did not notice the date and were replying to those posts, thus wasting everyone's time.
Now, I dislike removing content from any website I manage, since that can potentially hurt Google's PageRank on the site. If only there were some way of removing the old posts from those forums without actually deleting the posts...
Then I remembered that Drupal's database is in third-normal form and came up with this query after about 15 minutes of fiddling:
INSERT INTO temp_nids (
SELECT nid FROM term_node WHERE nid IN (
SELECT n.nid FROM node AS n
LEFT JOIN term_node AS tn ON n.nid=tn.nid
LEFT JOIN term_data AS td ON tn.tid=td.tid
WHERE td.name IN ('Room Share', 'Ride Share')
AND FROM_UNIXTIME(n.created) < '2007-08%'
)
)
DELETE FROM term_node WHERE nid IN (SELECT nid FROM temp_nids);
The innermost query (SELECT n.nid FROM node...) selects node IDs that belong to the Room Share or Ride Share forums with a creation date before August, 2007. The query around that (SELECT nid FROM term_node...) I originally had in to make sure that we got valid node IDs from term_node. Given how the query evolved, that's probably no longer necessary. The outermost query (INSERT INTO temp_nids) stored the matching node IDs in our temporary table for later use.
The final query (DELETE FROM term_node...) deletes the offending node IDs from the term_node table, which is responsible for linking nodes to taxonomy terms.
In other Drupal news, I stumbled across a nice little article the other day called 10 Reasons to Use Drupal CMS. While I knew some of the things mentioned in that article, I had no idea that entities such as The United Nations, Forbes, The Discovery Channel, AOL, and most surprisingly of all--The Grateful Dead.. all use Drupal. Fascinating stuff.
Also, I found the website Drupal Dojo which contains lots of tutorials on how to perform different tasks in Drupal. It looked just like another how-to type site (not that there's anything wrong with that!) until I came to the article on patch rolling and saw this:
Um, yeah... I sure wasn't expecting to see that particular graphic. 
How to speed up Drupal 5.2 lots
Submitted by dmuth on Thu, 2007-09-13 23:32. Blog | DrupalEarlier tonight, I was trying to figure out why a Drupal installation of mine was running kinda slow. So, I installed the awesome devel module and had it print out the list of database queries. What I found when going through the forums was on each post there were dozens and dozens of calls to drupal_lookup_path() for URLs which I never had (or will) make aliases of. Namely URLs that start with "comment/" or "user/".
So, I wrote a little patch for that function which will skip querying the database for URLs like that:
+++ includes/path.inc 2007/09/14 00:15:21
@@ -44,6 +44,21 @@
static $map = array(), $no_src = array();
static $count;
+ //
+ // Drupal does an INSANE number of these queries for comment lnks
+ // and such on long threads, and that's just unacceptable. Since
+ // I plan on like, never setting up a URL alias on a comment or
+ // a user, I'm just going to stop here...
+ //
+ if (
+ stristr($path, "comment/")
+ || stristr($path, "user/")
+ ) {
+ return(false);
+ }
+
// Use $count to avoid looking up paths in subsequent calls if there simply are no aliases
if (!isset($count)) {
$count = db_result(db_query('SELECT COUNT(pid) FROM {url_alias}'));
You will see the most gain with forum posts that have many comments, but even on regular pages you should see some benefit. Enjoy!
A Drupal backup program
Submitted by dmuth on Tue, 2007-03-13 00:05. DrupalSo, I still need to release my backup module for Drupal 5. But I haven't had a chance to sit down and actually read the documentation.
But, awhile back, I developed my own command-line utility for backing up my own Drupal websites. Since it was quicker to clean that up and release it instead of waiting for me to Finish the Drupal 5 version of the module, I figured I would do that.
The program can be downloaded from here.
It needs to be run from the root directory of DOCUMENT_ROOT from the command line. It will automatically read in your default settings.php file to get the database credentials and create its own backup of the database. Then it will backup the webserver's filesystem and store both database backup and filesystem into a nice little tarball, ready for download via your web browser.
For those of you who are worried because the file is essentially world-readable, there is a random number appended to the database dump and the final backup to prevent an attacker from guessing the name of the file. (your webserver would fall over from the 404s before someone successfully guessed a filename)
Enjoy!
How to secure a Drupal site
Submitted by dmuth on Fri, 2007-03-02 11:48. Drupal | Technical WritingsAwhile back, I was working on a private Drupal website for members only. Now, Drupal has a module called Secure Site which can be used for this. However, Secure Site throws up an HTTP 401 error to request authentication from the user. If you've ever seen a "enter username and password" box pop up in your browser, that's an HTTP 401 error. That's okay, but I don't think it's the best UI out there. I wanted something a little user-friendlier.
Drupal shows "create content" menu item to anonymous users
Submitted by dmuth on Fri, 2007-03-02 10:13. Drupal | Technical WritingsSo, I'm working on a Drupal site that, for reasons unknown, shows the "create content" menu item even when the user is logged out. Since I don't allow anonymous users to post on this site, clicking on that menu item gives a "permission denied" error. Not exactly the sort of user experience I want to provide.
Well, I just came up with this bit of code to fix the problem. It goes in index.php after the call to drupal_bootstrap():
if (strstr($_SERVER["REQUEST_URI"], "/node/add")) {
if (empty($user->uid)) {
drupal_set_message("You must be logged in to do that");A patch for Drupal's webform module
Submitted by dmuth on Sat, 2006-06-03 11:50. Blog | DrupalAwhile back, I learned the hard way that if you submit a form generated by Drupal's webform module from behind a proxy, the IP address is really TWO IP addresses (one internal and one external), separated by a comma. This plays havoc when exporting to a comma-delimited text file.
So I wrote a patch that now allows tab-delimited (TSV) files to be exported from a webform. It can be found over here. Enjoy!
If you use Drupal's poormanscron module
Submitted by dmuth on Sun, 2006-05-07 14:05. Blog | DrupalThere's a nasty race condition in it, which I wrote a fix for. It can be found at:
http://www.claws-and-paws.com/software/drupal
Enjoy!
Painless relocating of Drupal modules
Submitted by dmuth on Wed, 2006-03-15 01:00. Blog | DrupalWhile upgrading to the latest version of Drupal, I was thinking that it would be nice if the 30 or so "after market" modules that I had installed could be moved out of the (rather cluttered) modules/ directory into a sub directory. Here's one approach I found for doing this, with minimal disruption to the site:
1) mkdir modules/local
2) mv module1.module module2.module module3.module [...] local
3) Reload /admin/modules for each site that runs off of that Drupal installation
The key here is step #3. The act of merely loading the modules page causes the entire modules/ directory to be recursively searched for modules, which are then written to the system table in the database and then displayed on the screen. As soon as that table is rewritten, any attempts to load any of the modules that were moved will cause them to be read from their new location on disk.
This is with Drupal 4.6. Your mileage may vary with other versions.
Essential Drupal Tips for Drupal 4.6.5
Submitted by dmuth on Fri, 2006-02-24 18:49. Drupal | Technical WritingsI've been running Drupal for a few months and I've learned a few tips for interacting with Drupal, as well as a few "gotchas" present in Drupal. I'd like to share them with you in this article. Unless mentioned otherwise, everything in this article applies to Drupal 4.6.5.
