Call to undefined function cache_get()

When debugging with Zend Studio, you may get the fatal error "Call to undefined function cache_get()" when debugging, even though your site appears just fine in the browser.

Zend Studio seems to search open files first without regard to their actual paths. In my case, I had the cache.inc file from the views module open in Zend, and Zend was loading that instead of includes/cache.inc during debugging. Simply closing the file solved the problem.

[ Submitted by John on Thu, 2008-08-21 13:03. | | ]

Zend Platform on an Intel Mac

Finally. After over a year, Zend has recompiled their debugging extension so it will run on Intel Macs. That's the good news. The bad news is that now it's part of their enterprise-class Zend Platform product.

I'm running the 30-day trial, and was able to install it by running the install shell script and choosing the manual option to enter my Apache settings. Apache wouldn't restart after the installation because of course the xdebug extension that I had enabled in my php.ini file needed to be disabled.

[ Submitted by John on Fri, 2007-03-16 20:40. | | ]

Searching Drupal code

Often I find myself in the position of having to find something in the Drupal codebase. It's easy to do; from the command line:

cd drupal5
grep -rn contact .

This recursively searches the code for Drupal 5 and returns all occurrences of the word "contact", along with the filename and line number. Suppose I'm searching for the places where the contact database table is updated in Drupal. I can pipe the results into another grep:

grep -rn contact . | grep UPDATE
./modules/contact/contact.module:227: db_query('UPDATE {contact} SET selected = 0');
./modules/contact/contact.module:242: db_query("UPDATE {contact} SET category = '%s', recipients = '%s', reply = '%s', weight = %d, selected = %d WHERE cid = %d", $form_values['category'], $form_values['recipients'], $form_values['reply'], $form_values['weight'], $form_values['selected'], $form_values['cid']);

If you find yourself doing this frequently, it's helpful to make a shell script. I use OS X, and in my user directory I have created a directory called bin in which my scripts live. Of course, I've had to modify my /Users/john/.profile file to include that path when OS X is searching for executables by adding the following line:

PATH=$PATH:/Users/john/bin

I created a file at /Users/john/bin/f that contains the following line of code:

#!/bin/bash
grep -rn $1 .

Now instead of typing grep -rn contact . I can simply type

f contact

Quick 'n' easy. For more shortcuts, see Steven's handy tips.

[ Submitted by John on Tue, 2007-03-13 09:36. | | ]

Zend Studio 5.5 debugging on OS X via Ubuntu and Parallels

Here's how to get debugging working in Zend Studio Server 5.5 for the Mac. There is no native version of Zend Platform for OS X on Intel Macs yet, so this solution uses Ubuntu on Parallels as an interim solution.

Installing Ubuntu on Parallels

I downloaded Ubuntu 6.10.
In Parallels, new virtual machine, typical installation.
Guest OS Type: Linux.
Guest OS Version: Debian Linux.
Called the Virtual Machine "Ubuntu".
Uncheck "Start guest OS installation".
Clicked on CD/DVD-ROM and changed the Emulation from Use CD/DVD-ROM to Use image file.
Pointed the image file to ubuntu-6.10-desktop-i386.iso
Blicked on Options, then Booting Options.
Changed Boot sequence to have CD-ROM boot first.
Started virtual machine which booted off the image file.
Pressed enter to boot from LiveCD.
Selected U.S. English.
Selected "Erase entire disk".
After installation, selected "Continue using LiveCD"
Powered off virtual machine.
Changed boot sequence to have hard disk boot first.
Booted and logged in.
System - Preferences - Screensaver Preferences, uncheck Activate screensaver.
Tested network connection.

Installing Apache, PHP, and Samba

You can use either the command line or Synaptic Package Manager to install software. If you use Synaptic:
System - Administration - Synaptic Package Manager
Settings - Repositories, check Community maintained Open Source software

I used the command line:

sudo bash
apt-get update
apt-get install apache2-mpm-prefork apache2 libapache2-mod-php5 php5-mysql smbfs

Mounting OS X Filesystem on Ubuntu

Now Apache and PHP are installed. Next, I wanted to mount my OS X filesystem on Ubuntu.

Started Windows File Sharing on OS X.

Firewall, chose New... and selected SMB (without netbios) (445 TCP).

Made the following addition to /etc/smb.conf on OS X (xxx.xxx.xxx.xxx is the IP of the Ubuntu virtual machine).

; allow connections only from the VM
hosts allow = xxx.xxx.xxx.xxx
; verbose logging in /var/log/samba/log.smbd
log level = 3 passdb:5 auth:10 winbind:2
; share my Sites folder
[sites]
  path = /Users/john/Sites
  read only = no
  browseable = no
  comment = Websites

And I commented out the [homes] section because I'm paranoid.

Now I went to Ubuntu's terminal to mount the share:

mkdir /home/john/sites
mount -t smbfs //my.mac.ip.address/sites /home/john/sites -o username=myosxusername

I tested and doing ls gave me a list of the files in /Users/john/Sites. OK so far.

Serving my Sites directory via Ubuntu

Now I want Apache to serve out of /home/john/sites instead of the default /var/www. (I have no other use for Apache on this VM, so I'm editing the default settings.) So in Ubuntu I said

nano /etc/apache2/sites-enabled/000-default

When I was done it looked like this:

<VirtualHost *>
	ServerAdmin my@email.address
	
	DocumentRoot /home/john/sites
	<Directory /home/john/sites
	  Options Indexes FollowSymLinks MultiViews
	  AllowOverride All
	  Order deny,allow
	  deny from all
	  allow from 127.0.0.1
	  allow from my.mac.ip.address
	</Directory>
	...

I restarted Apache with apache2ctl restart.

I made a little file called test.php with just <?php phpinfo(); ?> in it. Going to http://xxx.xxx.xxx.xxx/test.php showed the PHP info page. So Apache and PHP are now running.

Installing Zend Platform on Ubuntu

Now it's time to install Zend Platform. I downloaded it from Zend and installed it on Ubuntu:

tar -xvf ZendPlatform-3.0.0Beta-linux-glibc21-i386.tar.gz
cd ZendPlatform-3.0.0Beta-linux-glibc21-i386/
bash ./install

Note that you need to type bash ./install instead of ./install because /bin/bash is really /bin/dash on Ubuntu.

I accepted all the defaults except on the WEB SERVER SETTINGS page, where I entered /home/john/sites in the htdocs field.

I did the Express option. It took several minutes and then completed.

On Ubuntu I started Firefox and went to http://localhost/ZendPlatform and logged in. Only localhost is allowed to do debugging and profiling sessions by default, and I wanted to do that from my Mac (that's sort of the whole point of this exercise!). So I clicked on Configuration and added my host to Allowed Hosts.

Configuring Zend Studio 5.5

Now I needed to configure Zend Studio 5.5 on my Mac to use Ubuntu. In Zend Studio, I added the IP of the Ubuntu virtual machine to Tools - Preferences - debug.

One final step: the debugger on Ubuntu connects back to Zend Studio on the Mac via port 10000. So I opened that port on my firewall.

To test, I chose Tools - Test Debug Server Connection and it reported success.

Conclusion

I now have a single filesystem that I can access via normal HTTP by issuing a request to my Mac, or via debugging by using Zend Studio to issue a debugging request via Ubuntu.

Drupal ninjas will notice that I haven't installed MySQL on Ubuntu. That's because I'll configure the site-specific Drupal settings file to point to the MySQL on my Mac. One database. One filesystem. Two Apache/PHP installs. Sweet.

Note: after trying this for a bit, it seems that Zend Platform's "Dynamic Content Caching" causes Apache/2.0.55 PHP/5.1.6 to segfault. Turning it off in the Zend Platform control panel at Performance - Settings -Dynamic Content Caching made the problem go away.

Update: after more investigation, it turns out that the segfaulting is due to the Zend Optimizer. Commenting out the following line in /usr/local/Zend/Platform/etc/php.ini eliminates the segfaults:

zend_extension_manager.optimizer=/usr/local/Zend/Platform/lib/Optimizer-3.2.0

[ Submitted by John on Tue, 2007-01-02 15:31. | | ]

Safari contextual menu for applying Drupal patches

I wanted an easy way to test patches, so here's what I did.

Downloaded OnMyCommand.

Copied the OMCEdit application folder to Applications.

Ran the script Install OnMyCommandCM (I checked it out in Script Editor first.)

Logged out and logged back in.

Followed this tutorial.

I created a contextual menu item named Apply patch to Drupal installation with the following code:

#!/bin/bash
DRUPAL_HOME=/Library/WebServer/Documents/
cd $DRUPAL_HOME
touch drupaltemp
rm -R drupaltemp
cp -R drupal drupaltemp
cd drupaltemp
osascript -e 'tell Application "Safari"' -e 'get source of document 1' -e 'end tell' | perl -0ne 'print "$1\n" while (/a href=\"(http:\/\/drupal.org\/files.*?)\">.*?<\/a>/igs)' | tail -1 | sed "s/\(.*\)/--url \1/" | curl --config - > patch
bbedit patch
patch -p0 < patch

Now when I right-click on an issue and choose Apply patch to Drupal installation, the script:

  • Creates a working copy of Drupal.
  • Obtains the source of the current page from Safari.
  • Parses out URLs that designate patches (begin with drupal.org/files).
  • Find the last one, since there may be multiple patches in the issue.
  • Download the patch.
  • Open the patch in BBEdit.
  • Apply the patch to the working copy of Drupal.

Note: this is actually a workaround. I wanted to modify Safari's contextual menu for links, but was unable to find a way to hook in.

Sadly, this will probably not increase the number of patches I review, as it's not really the patching that takes time. This was more of an, I can't sleep...I wonder if I could create a contextual menu that... kind of a project.

[ Submitted by John on Sun, 2006-10-29 21:09. | | ]

Drupal 4.6 and PHP 5

I'm running PHP 5.1.6 and wanted to do some testing with the publish and subscribe modules for Drupal. This is the first time I've had PHP5 on my development machine for a variety of mundane reasons. Drupal 4.7 runs fine with PHP5, but imagine my surprise when a fresh install of Drupal 4.6.9 looked like this:

{_BLOCK_.header.logo} {_BLOCK_.header.site_name}
{secondary_links}
{primary_links}
{_BLOCK_.header.blocks}
{_BLOCK_.header.message}...

That's because Drupal 4.6.9 ships with an XTemplate-based theme called bluemarine that doesn't like PHP5. The quick 'n' easy solution was to go to /?q=admin/themes and change the theme to chameleon. (Then I installed the phptemplate engine and used phptemplate from then on.)

Unrelated note: pick up a copy of Apache Security. It's well worth it.

And another unrelated note. In a fit of Drupal server optimization, I installed the FreeBSD port of Zend Optimizer 3.0.1. However, it wasn't long before Apache was segfaulting. It turns out that I compiled PHP with the --enable-versioning flag on (since it's on by default), which is a no-no.

[ Submitted by John on Wed, 2006-10-04 16:01. | | ]

Remote PHP Debugging on Intel-based Macs with Komodo

I got a new computer. Yay! It's a Mac Pro.

So naturally I want to set up my Drupal working environment on it.

However, I use the Zend IDE and the Zend Studio Server debugger will not run on Intel-based Macs. No, seriously. It's inexcusable.

I love my real-time debugging. So I decided to try out Komodo. I've made a point to ask about OS X versions of Komodo at the ActiveState booth for as long as I've been attending OSCON. Now they've got a stable version and it supports Macintel.

Well, almost.

So, starting with my new Mac Pro, I installed XCode Tools to get cvs and all the other command-line niceties. Then I headed off to Marc Liyanage's PHP page to install PHP (even PHP treats Marc's installer as the official binary).

PHP 5 installed fine, but I got this unusual hiccup when starting Apache:

[warn] module mod_php5.c is already added, skipping

Commenting out the line

AddModule mod_php5.c

from /etc/httpd/users/+entropy-php.conf got rid of the warning. I'm guessing that Apache is somehow automatically doing an AddModule when it hits the LoadModule line. Anyway, it works fine.

Next, it was time to set up Komodo for debugging. First I wanted to make sure it found the php5 that I installed, and not Apple's php4. So I did this in /etc/profile:

PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/php5/bin"

and then moved Apple's php binaries out of the namespace:

sudo bash
cd /usr/bin
mv php php-old
mv php-config php-config-old
mv phpize phpize-old

I logged out and back in to activate the new PATH and tested:

which php
usr/local/php5/bin/php

I put this

<?php
phpinfo();

into /Library/WebServer/Documents/phpinfo.php and sure enough, http://localhost showed me the PHP info page. Good so far. On to installing Komodo.

I downloaded Komodo, copied it to Applications, and clicked on it.
Chose Trial version
Got email with URL for evaluation activation key.
Downloaded EvalLicense-KomodoProfessional-MacOSX.zip
Double-clicked to get ActiveState License Installer.
Double-clicked to install license.

Now I started Komodo. I built the "intelligence database" and set up Langugages - PHP.

Now it was time to set up debugging. I used Languages - PHP - Debugger config wizard to put the debugger's php.ini file into ~/komodo/ini and the debug extension into ~/komodo/extensions. It then informed me that the debugger extension could not be started. I did this many times.

Finally, I got annoyed with the debugger config wizard. Instead, I installed xdebug myself. Here's how. First download xdebug (I downloaded version 2.0.0beta6). Then compile it:

cd xdebug-2.x.x
phpize
./configure --enable-xdebug
make
mkdir /usr/local/xdebug
cp modules/xdebug.so /usr/local/xdebug/

Then I edited /usr/local/php5/lib/php.ini to include the following:

zend_extension=/usr/local/xdebug/xdebug.so
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_port=9000
xdebug.remote_host=127.0.0.1
xdebug.idekey=komodo

While I was editing php.ini anyway, I changed memory_limit to a sane number.

Applied my changes by restarting Apache:

apachectl restart

Next I configured Komodo to listen for xdebug by going to Preferences - Debugger - Proxy. I set Listen for debug connections on port: to 9000.

Then I went to the Debug menu and chose Listen for Remote Debugger.

And, when I went to http://localhost/phpinfo.php in my browser...wah la! Nothing happened. But when I added the xdebug parameter, like this:

http://localhost/phpinfo.php?XDEBUG_SESSION_START=komodo

then Komodo was invoked and I could step through the request, just like in Zend. Whee!

Note: I have confirmed that xdebug.so that is included with Komodo, which Komodo helpfully installs in whichever directory you specify during your time with the Debugger Config Wizard, does not work. That file has an MD5 of 8cca2df563529f950219a86cfadf2e48.

However, the version of xdebug.so I compiled does work.

This writeup dedicated to webchick, who allegedly has lost a good two weeks of her life dealing with remote debugging on Macintel.

P.S. I've tried this with MAMP 1.3.1 and it works fine. Also, it doesn't seem to matter which value I use for xdebug.idekey. Also, if you want to request some pages without the debugger firing up, turn off the Listener under Debug - Listen for Remote Debugger.

Helpful references:

Komodo 3.5 Debugging Documentation
Debugging Drupal with Activestate Komodo
xdebug documentation

[ Submitted by John on Wed, 2006-09-20 13:10. | | ]

Script for automating Drupal installation

I do a lot of testing with Drupal, so I need a quick and easy way to create a new Drupal site, create the associated database, and get started. There are probably better solutions out there, but this is what I use. It's a bash script that I developed with the help of killes sometime last year. I just updated it for Drupal 4.7.

Now when I want to create a new Drupal site I just type

newdrupal47 foo bar

where foo is the name I'm giving the new site and bar is the name of the MySQL user (the MySQL user is optional; it defaults to root). It gets the Drupal 4.7 branch from CVS, configures the settings file, creates the database, optionally runs some local SQL, and opens Safari. Here's the script (it lost the indentation, oh well):

#!/bin/bash

if [ $# = "0" ]; then
echo "newdrupal47: usage: newdrupal47 sitename db_user"
exit 1;
fi

# You may want to set HOST to be your box's domain name
HOST='localhost'
DB_USER='root'
# If second argument is nonzero we were given a db_user;
# use it instead of defaulting to root
if [ -n "$2" ]; then
DB_USER=$2
fi

# This is the location of an SQL file to run after the Drupal
# database has been given to MySQL. I use it to insert one
# line into the user roles table and one line into the user
# table, thus establishing the admin user.
LOCAL_SQL=~/newdrupal47.sql

# This is the location of your htdocs directory.
DIR="/Library/WebServer/Documents"
echo "Changing directory to $DIR"
cd $DIR

echo "Retrieving Drupal 4.7 branch..."
# Pull down drupal 4.7
cvs -z3 -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal checkout -r DRUPAL-4-7 drupal

echo "Configuring..."
# Rename the drupal site from "drupal" to whatever the first parameter was,
# e.g. newdrupal47 drupaltest results in a directory named drupaltest
mv $DIR/drupal $DIR/$1

# Make a copy of the default settings folder and name it localhost
# You may want to substitute your machine's DNS name
cp -R $DIR/$1/sites/default $DIR/$1/sites/$HOST

MYSQL_LOC=`which mysql`
if [ -x $MYSQL_LOC ]; then
echo "Enter the database password for user '$DB_USER'"
echo -n "Password: "
read -s PASS

# set local database connection
# -i means edit file in-place
# we search only lines 85-90 in the settings file
sed -i '' 85,90s#username:password@localhost/databasename#$DB_USER:$PASS@localhost/$1# $DIR/$1/sites/$HOST/settings.php

# set the base url
sed -i '' 108,110s#www.example.com#$HOST/$1# $DIR/$1/sites/$HOST/settings.php

echo "Creating database..."
mysqladmin -u$DB_USER -p$PASS create $1
$MYSQL_LOC -u$DB_USER -p$PASS $1 < $DIR/$1/database/database.4.1.mysql
echo "Checking for local configuration..."
if [ -r $LOCAL_SQL ]; then
echo "Found local configuration; executing SQL"
$MYSQL_LOC -u$DB_USER -p$PASS $1 < $LOCAL_SQL
fi
fi

echo "Done"
#opens Safari to the new site on OS X
open http://$HOST/$1

[ Submitted by John on Mon, 2006-05-08 15:38. | | ]