Quickie how-to for getting PHP upgraded on CentOS 5

Today I had to get PHP upgraded from 5.1 to 5.2.X on someone else’s server and didn’t have time to screw around. I have a PHP configuration that I’ve used in the past but it frankly can take too long to get set up, if time is of the essence. So here are my “quickie steps” (tested for the current release, 5.2.11 on CentOS 32- and 64-bit). Follow these and you can be running in 20 minutes (if you type fast!):

Download the latest stable PHP build from http://php.net and extract.

# back stuff up, just in case
cp -rv /usr/lib/php/modules /usr/lib/php/modules-bak
cp -v /usr/lib/httpd/modules/libphp5.so  /usr/lib/httpd/modules/libphp5.so.bak

# or, if you're on 64-bit:
mv /usr/lib64/php/modules /usr/lib64/php/modules-bak
ln -s /usr/local/lib/20090626/ /usr/lib/php64/modules
cp -v /usr/lib64/httpd/modules/libphp5.so  /usr/lib64/httpd/modules/libphp5.so.bak

# the ones after mysql-devel might be optional if you're pressed for time, but they're needed by phpmyadmin etc.
yum install httpd-devel mysql-devel libmcrypt-devel libxml2-devel zlib-devel libmhash curl-devel

# you may need to do the following, if compiling on 64-bit
export LDFLAGS=-L/usr/lib64/mysql

./configure --with-apxs2 --with-mysql=shared --with-mcrypt --enable-mbstring --with-curl --with-zlib
make clean && make install

# if the build fails, you may need to recompile libmcrypt as per http://marc.info/?l=php-install&m=108030891925096&w=2
wget http://sourceforge.net/projects/mhash/files/mhash/0.9.9.9/mhash-0.9.9.9.tar.gz/download
./configure
make clean && make install
wget http://sourceforge.net/projects/mcrypt/files/Libmcrypt/2.5.8/libmcrypt-2.5.8.tar.gz/download
./configure --disable-posix-threads
make clean && make install
cd libltdl
./configure --enable-ltdl-install
make clean && make install

# now for some reason by default PHP might be looking in /usr/local/lib for the php.ini, so symlink to it
cd /usr/local/lib
ln –s /etc/php.ini

Also add the following to /etc/php.ini (in case it doesn’t know to scan /etc/php.d by default):

...
[MySQL]
extension=mysql.so
; Allow or prevent persistent links.
mysql.allow_persistent = On
...

You’ll need to add the same for mbstring.so, etc. if you built them as well.

Got a few minutes left? If so install eaccelerator:

./configure
make
make install
cp /usr/local/lib/php/extensions/no-debug-non-zts-20060613/eaccelerator.so  /usr/lib/php/modules

mkdir /tmp/eaccelerator
chmod 777 /tmp/eaccelerator

and add the following to /etc/php.ini:
...
[eaccelerator]
extension=
eaccelerator.so
eaccelerator.cache_dir = "/tmp/eaccelerator"
eaccelerator.enable = "1"
eaccelerator.debug = "0"
eaccelerator.optimizer = "1"

Update 12/12/2010: To build a more sophisticated 32-bit version of PHP 5.3.4, do the following:

yum install httpd-devel mysql-devel libmcrypt-devel libxml2-devel zlib-devel libmhash curl-devel libtidy-devel pcre-devel libjpeg-devel libpng-devel freetype-devel gmp-devel

'./configure' '--build=i686-redhat-linux-gnu' '--host=i686-redhat-linux-gnu' '--target=i386-redhat-linux-gnu' '--program-prefix=' '--prefix=/usr' '--exec-prefix=/usr' '--bindir=/usr/bin' \
'--sbindir=/usr/sbin' '--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include' '--libdir=/usr/lib' '--libexecdir=/usr/libexec' '--localstatedir=/var' '--sharedstatedir=/usr/com' \
'--mandir=/usr/share/man' '--infodir=/usr/share/info' '--cache-file=config.cache' '--with-config-file-path=/etc' '--with-config-file-scan-dir=/etc/php.d' '--disable-debug' '--with-pic' \
'--disable-rpath' '--with-pear' '--with-curl' '--with-exec-dir=/usr/bin' \
'--enable-gd-native-ttf' '--without-gdbm' '--with-gettext' '--with-gmp' '--with-kerberos' \
'--with-iconv' '--with-openssl' '--with-zlib' '--with-layout=GNU' \
'--enable-magic-quotes' '--enable-sockets' '--enable-sysvsem' '--enable-sysvshm' '--enable-sysvmsg'  \
'--enable-ucd-snmp-hack'  '--without-sqlite' \
'--with-libxml-dir=/usr' '--enable-pcntl' \
'--enable-mbstring=shared' '--enable-mbregex'  \
'--with-gd=shared' '--enable-dba=shared' '--with-xmlrpc=shared' '--with-ldap=shared' \
'--with-mysql=shared,/usr' '--with-mysqli=mysqlnd' '--enable-dom=shared'  \
'--enable-soap=shared' '--enable-xmlreader=shared' '--enable-xmlwriter=shared' '--with-mcrypt'  '--with-mhash'  \
'--with-freetype-dir=/usr/lib' \
'--with-apxs2=/usr/sbin/apxs' \
'--disable-pdo' '--without-pdo-sqlite' '--with-tidy' '--with-pcre-dir' '--with-jpeg-dir' '--enable-zip'

An ExtJS form helper for CakePHP

ExtJS allows you to make really elaborate Javascript-based UI once you get the hang of it. Unfortunately (unless there is some project I missed) it hasn’t yet been integrated with CakePHP so you end up hand-coding a bunch of stuff in order to get simple stuff (like client-side form validation) to work. The world is ready for a helper class, or at least I was.

So I put this together. Currently it only supports text, password, and hidden fields but you get the idea. The CakePHP FormHelper class inspired some of the logic dealing with camelcasing the field names.

app/views/helpers/extjs.php

class ExtjsHelper extends AppHelper {

	function init()
	{
		return '';
	}
	function input($fieldName, $options = array())
	{
		// see the API definition of FormHelper::input()
		$view =& ClassRegistry::getObject('view');
		$this->setEntity($fieldName);
		
		$tokens =  $view->entity();
		$modelname = $tokens[0];
		$propertyname = $tokens[1];

		if (isset($options['type']))
			$type = $options['type'];
		else
		{
			if ($fieldName == 'id')
				$type = "hidden";
			elseif (in_array($this->field(), array('psword', 'passwd', 'password')))
				$type = "password";
			else $type = "text";
		}
		
		$label = (isset($options['label']) ? $options['label'] : Inflector::humanize($propertyname));
		$id = $modelname.Inflector::camelize($propertyname);
		$html = '';

		$value = (isset($options['value']) ? $options['value'] : '');
		$style = (isset($options['style']) ? ',style:"'.$options['style'].'"' : '');
		$width = (isset($options['width']) ? ',width:"'.$options['width'].'"' : '');
		$vtype = (isset($options['vtype']) ? ',vtype:"'.$options['vtype'].'"' : '');
		$allowBlank = (isset($options['allowBlank']) ? ',allowBlank:'.($options['allowBlank'] ? 'true':'false') : '');
		$emptyText = (isset($options['emptyText']) ? ',emptyText:"'.$options['emptyText'].'"' : '');
		
		if ($type != "hidden")
			$html .= '
'; $html .= ''; if ($type != "hidden") $html .= '
'; return $html; } }

Usage:

// include the ExtJS Javascript and CSS classes in the HEAD of your layout, 
// then create the form as usual

echo $form->create(...);
echo $extjs->init();
echo $extjs->input('email', 
		array(
			'style'=>'width:200px;margin:8px',
			'vtype'=>'email',
			'allowBlank' => false
			));
...
echo $form->end('Submit');

This will then post the same form data structure that Cake normally does.

Caching expensive actions with Jake

In an earlier post I described using the Jake bridge to get CakePHP working with Joomla. Overall the bridge works like a champ, with one exception I’ve found: it seems that Jake does not support cached actions – if you try to cache an action, it no longer renders through the Jake component. This is probably a bug in Jake.

Fortunately Jake does support cached elements though, so you can do this workaround to get your expensive operations cached.

  1. If you haven’t already, create the writable directory app/tmp/cache/views.
  2. Suppose your desired action is controllername/expensiveaction(). Move the logic into the new (private) function controllername/_expensiveactionimp() and make it return a $somedata variable that contains all the data you need to output. E.g.,
    function expensiveaction()
    {
      if (isset($this->params['requested']))
        return $this->_expensiveactionimp();
      else
      {
        // do other stuff
      }
    }
    function _expensiveactionimp()
    {
      // slow, expensive operations
      $somedata = do_slow_stuff();
      return $somedata;
    }
    
  3. Move the entire contents of the corresponding view to a new element: app/views/elements/expensiveaction.ctp. In this element, just do
    $somedata = $this->requestAction('controllername/expensiveaction);
  4. Now, in the view expensiveaction.ctp, just do (with the appropriate cache interval)
  5. echo $this->element('expensiveaction', array('cache' => '1 hour'));

Enjoy.

Migrating Joomla 1.0.x to a new server

I didn’t want to do a new install; just wanted to keep everything as-is so I could set up a dev environment. This was going from Linux to Windows, vice versa is probably the same:

  1. Copy the following directories:
    1. administrator
    2. components
    3. editor
    4. images
    5. includes
    6. language
    7. mambots
    8. templates
    9. files in /
  2. Update configuration.php with the following:
    ...
    $mosConfig_absolute_path = 'C:/.../path-to-webroot'; 
    $mosConfig_debug= '1'; // useful if you want it
    $mosConfig_error_reporting = '1'; // useful if you want it
    $mosConfig_password = 'newpassword';  // db password, looks like this may be hashed though
    $mosConfig_user = 'new-db-username';
    ...
    

Hope this helps. Good luck!

Creating a new PHP project with VS.PHP

This has tripped me up a dozen times, and I keep having to relearn it. To make a new project from an existing codebase (the most common scenario), follow these steps:

  1. Add new project
  2. Under “PHP Projects”, click “new project in existing folder” and name it
  3. Browse to location where your PHP files are
  4. Under “ignore directories”, uncheck “.svn” if it’s there. Leave everything else checked. This is the opposite of what you’d expect, and it seems like a bug to me.
  5. Chances are, the VS solution file was created as My Documents/Visual Studio 2008/Projects/PROJECTNAME/PROJECTNAME.sln. You probably want to move that to a location along with your PHP files if they’re located somewhere else.

This may well be fixed in the current version of VS.PHP, these directions are for version 2.4.