[php] archive category

Multi-Site Solr for Drupal 6 Search on Tomcat 6 / CentOS 6

ApacheSolr for Drupal 6 improves on the out-of-the-box search experience for Drupal users. The easiest way to get Solr running on your Drupal web site is to use the hosted service provided by Acquia; it is way easier than running your own Solr. You simply point your queries to their Solr server and you’re done.

For various reasons, you might want to run your own Solr web service on your own machine. In this article, I will walk you through setting up a working Solr installation using Tomcat 6 on CentOS 6. The end result of this walkthrough will be two separate Solr indexes (via two separate Solr web apps) for two different web sites running on a single Tomcat. I will assume that you are using Acquia’s Drupal (which ships with SolrPHPClient).

Warning: This article assumes all services are on a single machine (suitable for a small organization). Running Solr on a separate machine is possible but raises security implications that are outside the scope of this article.

These are the tasks that we will work on:

  1. Set-up Solr
  2. Set-up Tomcat
  3. Tweak CentOS security thinger (SELinux)
  4. Configure Acquia Drupal

Prerequisites

The prerequisites are:

  • CentOS 6 Web Server w/ PHP 5.3, MySQL 5, Tomcat 6, Java 6 (all services running w/ no problemos)
  • Acquia Drupal 6 installed
  • Familiarity with Drupal (basic skills – enabling modules, setting permissions on nodes, etc)
  • Familiarity with Java & Tomcat (basic skills)
  • Familiarity working with Linux in a terminal and vi (intermediate skills)

This is my system (a web server set-up with Anaconda):

# uname -a
Linux templeton.localdomain 2.6.32-71.29.1.el6.i686 #1 SMP Mon Jun 27 18:07:00 BST 2011 i686 i686 i386 GNU/Linux
# cat /etc/redhat-release
CentOS Linux release 6.0 (Final)
# yum list installed | grep mysql-server
mysql-server.i686       5.1.52-1.el6_0.1  @updates
# yum list installed | grep php
php.i686                5.3.2-6.el6_0.1   @updates                              
php-cli.i686            5.3.2-6.el6_0.1   @updates                              
php-common.i686         5.3.2-6.el6_0.1   @updates                              
php-gd.i686             5.3.2-6.el6_0.1   @updates                              
php-mysql.i686          5.3.2-6.el6_0.1   @updates                              
php-pdo.i686            5.3.2-6.el6_0.1   @updates                              
php-pear.noarch         1:1.9.0-2.el6     @anaconda-centos-201106051823.i386/6.0
php-xml.i686            5.3.2-6.el6_0.1   @updates
# java -version
java version "1.6.0_17"
OpenJDK Runtime Environment (IcedTea6 1.7.5) (rhel-1.31.b17.el6_0-i386)
OpenJDK Client VM (build 14.0-b16, mixed mode)
# yum list installed | grep tomcat6
tomcat6.noarch          6.0.24-24.el6_0   @updates                              
tomcat6-el-2.1-api.noarch
tomcat6-jsp-2.1-api.noarch
tomcat6-lib.noarch      6.0.24-24.el6_0   @updates                              
tomcat6-servlet-2.5-api.noarch
# /sbin/service tomcat6 status
tomcat6 (pid 1790) is running...                           [  OK  ]
# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /selinux
Current mode:                   enforcing
Mode from config file:          enforcing
Policy version:                 24
Policy from config file:        targeted

Notice the hashmark (#) as my terminal prompt. It denotes that I am executing all these commands as root (use ‘su -‘). You can also prefix the following commands with ‘sudo’.

Download Solr

Obtain a copy of the Solr tarball from a nearby mirror:

http://www.apache.org/dyn/closer.cgi/lucene/solr/

Select Solr 1.4.1 or the latest recommended Solr:

ie. http://apache.sunsite.ualberta.ca//lucene/solr/1.4.1/

I’m using the 54M GZipped Tarball and downloading it using wget:

# wget http://apache.sunsite.ualberta.ca//lucene/solr/1.4.1/apache-solr-1.4.1.tgz
--2011-09-02 02:06:05--  http://apache.sunsite.ualberta.ca//lucene/solr/1.4.1/apache-solr-1.4.1.tgz
Resolving apache.sunsite.ualberta.ca... 129.128.5.190
Connecting to apache.sunsite.ualberta.ca|129.128.5.190|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 56374837 (54M) [application/x-tar]
Saving to: “apache-solr-1.4.1.tgz”

100%[=============================================>] 56,374,837   261K/s   in 6m 20s  

2011-09-02 02:12:42 (145 KB/s) - “apache-solr-1.4.1.tgz” saved [56374837/56374837]

# tar zxvf apache-solr-1.4.1.tgz
apache-solr-1.4.1/client/
...
# pwd
/root

Copy the Solr package somewhere reasonable like in the /opt folder:

# mkdir -p /opt/solr
# cp -r -p /root/apache-solr-1.4.1 /opt/solr

Link it (the Solr WAR file) to the Tomcat library directory:

# ln -s /opt/solr/apache-solr-1.4.1/dist/apache-solr-1.4.1.war /usr/share/tomcat6/lib/solr.war

In the future, when you upgrade your software, install the Solr upgrade and update the symlink.

Create Solr directories

You need to choose where your Solr indexes will be kept. I put them into the /var directory and that’s where I’m assuming that you will put yours:

# mkdir -p /var/solr
# cp -r -p /opt/solr/apache-solr-1.4.1/example/solr/ /var/solr/
# mv /var/solr/solr /var/solr/example.com
# ls -l /var/solr/example.com/
total 12
drwxr-xr-x. 2 root root 4096 Sep  2 02:44 bin
drwxr-xr-x. 3 root root 4096 Sep  2 02:44 conf
-rw-r--r--. 1 root root 2259 Sep  2 02:44 README.txt

Each domain has its own Solr indexes located in ‘data‘ and its own configuration files in ‘conf‘. There are two optional directories: ‘bin‘ (for replication scripts) and ‘lib‘ (for plugins). Unless your other apps use them, chances are they will be missing.

Install Drupal ApacheSolr plugin protwords, schema and solrconfig

You should already have Acquia Drupal 6 running or Drupal 6 with the ApacheSolr plugin installed. You can copy the ‘protwords.txt’, ‘schema.xml’, and ‘solrconfig.xml’ files from the plugin directory in your respective distribution rather than downloading it, but adjust the paths accordingly.

If you don’t already have the ApacheSolr plugin, get it from the Drupal web site.

http://drupal.org/project/apachesolr

Choose the latest Tarball and use wget to download it to your server, then copy the ApacheSolr configuration files (and backup originals using ‘b’ flag):

# wget http://ftp.drupal.org/files/projects/apachesolr-6.x-1.5.tar.gz
# tar zxvf apachesolr-6.x-1.5.tar.gz
...
# echo 'If ur root cp may give u a scary msg next cmd! Ignore it! Y to overwrite!'
If ur root cp may give u a scary msg next cmd! Ignore it! Y to overwrite!
#
# cp -b -p -f apachesolr/protwords.txt /var/solr/example.com/conf
# cp -b -p -f apachesolr/schema.xml /var/solr/example.com/conf
# cp -b -p -f apachesolr/solrconfig.xml /var/solr/example.com/conf
#
# echo 'Fix group so tomcat can use this!'
Fix group so tomcat can use this!
#
# chown -R root:tomcat /var/solr/example.com
# chmod -R 775 /var/solr/

Warning! If you are not using the Acquia distribution and instead installed the ApacheSolr plugin from the main Drupal web site then you should check that you have a copy of the SolrPhpClient (version r22 – see module README for the gory details). The Acquia distribution includes the correct SolrPhpClient (so you might want to use that instead?).

Make the two Solr instances for the two domains

This walkthrough will create two domains, but you can create more. Using the example.com folder as a prototype, just recursively copy it twice to make two domains (use ‘p’ switch to ‘preserve’ the file permissions and settings):

# cp -r -p /var/solr/example.com /var/solr/www1.kelvinwong.ca
# cp -r -p /var/solr/example.com /var/solr/www2.kelvinwong.ca

If the future, to add a new domain, copy the example.com folder you just made and customize it. This will also work for additional domains that you want to support.

Configure Tomcat 6

It’s All About Context: The Context element represents a web application run within a particular Tomcat virtual host. Each web application is based on a Web Application Archive (WAR) file or a corresponding unpacked directory. The web application used to process each web request is determined by matching the request to the path of each Context. You may define as many Context elements as you wish, but each Context MUST have a unique path. More on Context

Contexts are no longer put into Tomcat’s server.xml file since that file is read only at server start-up. Instead Contexts are placed into a folder hierarchy under CATALINA_BASE (on CentOS 6 it is /etc/tomcat6). Create and configure the following files:

# touch /etc/tomcat6/Catalina/localhost/www1.kelvinwong.ca.xml
# touch /etc/tomcat6/Catalina/localhost/www2.kelvinwong.ca.xml
# chown tomcat:root /etc/tomcat6/Catalina/localhost/{www1.kelvinwong.ca.xml,www2.kelvinwong.ca.xml}
# chmod 664 /etc/tomcat6/Catalina/localhost/{www1.kelvinwong.ca.xml,www2.kelvinwong.ca.xml}

Tomcat will use these files to find the WAR and deploy the application using the settings in the Context. Note: Contexts can be overridden (they often are) and there are more than a few in Tomcat. Review Tomcat’s documentation if they give you any trouble.

Make sure your Context fragments have .xml suffixes!

Place the following into /etc/tomcat6/Catalina/localhost/www1.kelvinwong.ca.xml

# vi /etc/tomcat6/Catalina/localhost/www1.kelvinwong.ca.xml
<?xml version="1.0" encoding="utf-8"?>
<Context docBase="/usr/share/tomcat6/lib/solr.war" debug="0" crossContext="true" >
   <Environment name="solr/home" type="java.lang.String" value="/var/solr/www1.kelvinwong.ca" override="true" />
</Context>

The Context fragment is simply telling Tomcat where to find the Context root (document base). It is an absolute path to its web app archive (WAR) file. CrossContext allows Solr to get a request dispatcher from ServletContext.getContext() for access to other web apps on the virtual host. The Environment tag defines the ‘solr/home‘ setting and allows it to be overridden. That’s all you need.

Change the other fragment:

# vi /etc/tomcat6/Catalina/localhost/www2.kelvinwong.ca.xml

Change the paths:

<?xml version="1.0" encoding="utf-8"?>
<Context docBase="/usr/share/tomcat6/lib/solr.war" debug="0" crossContext="true" >
   <Environment name="solr/home" type="java.lang.String" value="/var/solr/www2.kelvinwong.ca" override="true" />
</Context>

Bind Tomcat to Local Port

By default, Tomcat listens on port 8080. The default iptables ruleset in CentOS 6 does not allow remote connections to port 8080. For our purposes this is fine since we want our Drupal sites to connect locally on port 8080. Local good, remote bad.

You can also tell Tomcat to bind to localhost and not any of the other network adapters. Open Tomcat’s server.xml file:

# vi /etc/tomcat6/server.xml

Change Tomcat’s binding address to the localhost address (127.0.0.1) in the Connector tag:

69
70
71
72
73
74
    <Connector port="8080" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" 
               URIEncoding="UTF-8"
               maxHttpHeaderSize="65535"
               address="127.0.0.1" />

Solr is a web service that takes many requests from Drupal using the HTTP GET method, similar to you typing into your browser’s web address bar. These requests routinely get very long; you can increase the GET request character limit by increasing the maxHttpHeaderSize attribute (from 8k to 64k as shown). To handle non-English characters, you should also set the request encoding to UTF-8. The Connector as-shown does both.

Restart Tomcat to reload the server.xml file:

# /sbin/service tomcat6 restart
Stopping tomcat6:                                          [  OK  ]
Starting tomcat6:                                          [  OK  ]

View Solr Admin (optional)

You should now be able to view the Solr administration page if you open a local web browser on the server. If you don’t have a desktop on the server (as should be the case), you can use a text-browser like elinks.

View http://localhost:8080/www1.kelvinwong.ca/admin:

# elinks http://localhost:8080/www1.kelvinwong.ca/admin

You should see the Solr administration page in your browser.

SELinux

“Apache Solr: Your site was unable to contact the Apache Solr server,” reports Drupal; SELinux chuckles.

SELinux is enabled by default on CentOS 6, so you will likely have it running and it will not appreciate Apache trying to talk to Tomcat/Solr on port 8080 (check /var/log/audit/audit.log):

type=AVC msg=audit(1315100262.891:17629): avc:  denied  { name_connect } for  pid=2064 comm="httpd" dest=8080 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:http_cache_port_t:s0 tclass=tcp_socket

type=SYSCALL msg=audit(1315100262.891:17629): arch=40000003 syscall=102 success=no exit=-13 a0=3 a1=bfbe6590 a2=b70426f4 a3=11 items=0 ppid=2060 pid=2064 auid=500 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)

You can either turn off SELinux (not recommended) or fix the attributes so that SELinux allows Apache to talk to Tomcat. The handy tool sealert gives helpful advice:

# sealert -a /var/log/audit/audit.log | less

Summary:

SELinux is preventing the http daemon from connecting to itself or the relay ports

Detailed Description:

SELinux has denied the http daemon from connecting to itself or the relay ports. An httpd script is trying to make a network connection to an http/ftp port. If you did not setup httpd to make network connections, this could signal an intrusion attempt.

Allowing Access:

If you want httpd to connect to httpd/ftp ports you need to turn on the
httpd_can_network_relay boolean: "setsebool -P httpd_can_network_relay=1"

Fix Command:

setsebool -P httpd_can_network_relay=1

Additional Information:

Source Context                unconfined_u:system_r:httpd_t:s0
Target Context                system_u:object_r:http_cache_port_t:s0
Target Objects                None [ tcp_socket ]
Source                        httpd
Source Path                   /usr/sbin/httpd
Port                          8080
Host                          <Unknown>
Source RPM Packages           httpd-2.2.15-5.el6.centos
Target RPM Packages           
Policy RPM                    selinux-policy-3.7.19-54.el6_0.5
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Plugin Name                   httpd_can_network_relay
Host Name                     templeton.localdomainPlatform                      Linux templeton.localdomain                              2.6.32-71.29.1.el6.i686 #1 SMP Mon Jun 27 18:07:00
                              BST 2011 i686 i686
Alert Count                   14First Seen                    Sat Sep  3 18:25:40 2011Last Seen                     Sat Sep  3 18:37:42 2011Local ID                      4b66d238-ddf7-4b74-bbe5-3fb54be5b3e4Line Numbers                  178, 179, 180, 181, 182, 183, 184, 185, 192, 193,
                              194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
                              204, 205, 206, 207, 208, 209, 210, 211

Once upon a time and a very good time it was there was a moocow coming down along the road and this moocow that was coming down along the road met a nicens little boy named baby tuckoo[1]

The quick fix is to set the network relay flag (‘P’ flag makes the change persistent across reboots):

# setsebool -P httpd_can_network_relay=1
# getsebool httpd_can_network_relay
httpd_can_network_relay --> on

You don’t need sealert to use setsebool but it is a useful utility to debug errors with SELinux. If you don’t have sealert installed, it is a simple thing to install it since it is part of the setroubleshoot package:

# yum install setroubleshoot

Configure Drupal to use Solr

Turning now to your Drupal installation…

Enable the Solr Search service module…

Configure the Apache Solr Search module by visiting http://www1.kelvinwong.ca/?q=admin/settings/apachesolr

Solr host name
localhost
Solr port
8080
Solr path
/www1.kelvinwong.ca

The Solr path is the name of your Context fragment minus the xml suffix (ie. /etc/tomcat6/Catalina/localhost/www1.kelvinwong.ca.xml)

The cron job indexes 50 nodes at a time by default. When indexed, you can then search for nodes by keyword.

Save the settings. You should see:

  • The configuration options have been saved.
  • Apache Solr: Your site has contacted the Apache Solr server.
  • Apache Solr PHP Client Library: Correct version “Revision: 22”.

Try a search

You can re-index the site by force or let cron do it gradually. Either way it take a while for Solr to process the data.

http://www1.kelvinwong.ca/?q=admin/settings/apachesolr/index

Once you have indexed your site and adjusted the permissions on the search form (so anonymous users can use the search form), visit it:

http://www1.kelvinwong.ca/?q=search/apachesolr_search

Intentionally misspell something and let Solr give you hints!

What about the other one??? www2?

Ah, yes…the other one is set-up in a similar manner, just use the following configuration in Drupal:

Solr host name
localhost
Solr port
8080
Solr path
/www2.kelvinwong.ca

Tags: , , , , , , , , , , , , , ,

Speed up PHP with APC on Ubuntu 10.04LTS

Ubuntu 10.04 LTS makes it quite simple to set up a basic LAMP server using tasksel; however, the default PHP set up does not include APC, the Alternative PHP Cache, which speeds up many PHP applications like Drupal. In the past, setting up APC involved using PECL or installing from source, but with Ubuntu Lucid, the process has been simplified using apt-get.

First, let me identify my demo system. It is running Ubuntu 10.04 LTS Lucid and has been patched to the latest version:

$ uname -a
Linux demo 2.6.32-24-generic #43-Ubuntu SMP Thu Sep 16 14:17:33 UTC 2010 i686 GNU/Linux
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 10.04.2 LTS
Release:	10.04
Codename:	lucid
$ sudo apache2ctl status | grep "Server Version"
Server Version: Apache/2.2.14 (Ubuntu) PHP/5.3.2-1ubuntu4.7 with Suhosin-Patch
$ apt-cache show php-apc | grep Version
Version: 3.1.3p1-2

Ubuntu has added a Debian package into universe that allows APC to be added to any system quite easily:

$ sudo apt-get install php-apc
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  php5-gd
The following NEW packages will be installed:
  php-apc
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0B/77.2kB of archives.
After this operation, 217kB of additional disk space will be used.
Selecting previously deselected package php-apc.
(Reading database ... 28911 files and directories currently installed.)
Unpacking php-apc (from .../php-apc_3.1.3p1-2_i386.deb) ...
Processing triggers for libapache2-mod-php5 ...
 * Reloading web server config apache2
   ...done.
Setting up php-apc (3.1.3p1-2) ...

Note: You must restart the web server to begin using APC

$ sudo apache2ctl graceful

Out of the box (er…package), APC has some sane defaults. If you are “a serious user,” you will want to change your configuration yourself. Seriously, that is what the documentation says:

serious users should consider tuning the following parameters…

To tweak your very serious APC installation, you can change the settings manually (using vim):

$ sudo vim /etc/php5/conf.d/apc.ini

The APC configuration file is seriously barren; it is little more than an extension include directive. You can add extra keys after reading the APC’s online documentation related to settings.

Finally, there is a small php script that provides more information on the operation of the APC module. Copy it to your web root and decompress it. You should change the default username and password used to protect the script by changing the username and password variables directly in the PHP code:

$ sudo cp /usr/share/doc/php-apc/apc.php.gz /var/www
$ sudo gzip -d /var/www/apc.php.gz
$ sudo vim /var/www/apc.php

Change credentials near line 41:

41
42
defaults('ADMIN_USERNAME','apc'); // Admin Username
defaults('ADMIN_PASSWORD','password'); // Admin Password - CHANGE THIS TO ENABLE!!!

Now, view your APC page (assuming your web server is at 192.168.0.6):

http://192.168.0.6/apc.php

Tags: , , , , , , ,

Install PHP 5.3.3 on Mac OS Leopard 10.5.8

My attempt at building and installing PHP 5.3.3 crashed and burned with the following error while building the MySQLi extension:

/bin/sh /Users/kelvin/phpsource/php-5.3.3/libtool --silent --preserve-dup-deps --mode=compile gcc  -Iext/mysqli/ -I/Users/kelvin/phpsource/php-5.3.3/ext/mysqli/ -DPHP_ATOM_INC -I/Users/kelvin/phpsource/php-5.3.3/include -I/Users/kelvin/phpsource/php-5.3.3/main -I/Users/kelvin/phpsource/php-5.3.3 -I/Users/kelvin/phpsource/php-5.3.3/ext/date/lib -I/Users/kelvin/phpsource/php-5.3.3/ext/ereg/regex -I/usr/local/php5/include/libxml2 -I/usr/local/php5/include -I/opt/local/include -I/usr/local/php5/include/freetype2 -I/Users/kelvin/phpsource/php-5.3.3/ext/mbstring/oniguruma -I/Users/kelvin/phpsource/php-5.3.3/ext/mbstring/libmbfl -I/Users/kelvin/phpsource/php-5.3.3/ext/mbstring/libmbfl/mbfl -I/usr/local/mysql/include/mysql -I/Users/kelvin/phpsource/php-5.3.3/ext/sqlite3/libsqlite -I/usr/local/pgsql/include -I/Users/kelvin/phpsource/php-5.3.3/TSRM -I/Users/kelvin/phpsource/php-5.3.3/Zend  -no-cpp-precomp  -I/usr/local/php5/include -g -O2 -fvisibility=hidden  -c /Users/kelvin/phpsource/php-5.3.3/ext/mysqli/mysqli.c -o ext/mysqli/mysqli.lo 
 In file included from /Users/kelvin/phpsource/php-5.3.3/ext/mysqli/php_mysqli_structs.h:57,
                  from /Users/kelvin/phpsource/php-5.3.3/ext/mysqli/mysqli.c:33:
 /usr/local/mysql/include/mysql/my_global.h:895: error: duplicate ‘unsigned’
 /usr/local/mysql/include/mysql/my_global.h:895: warning: useless type name in empty declaration
 make: *** [ext/mysqli/mysqli.lo] Error 1
Trinity:~ kelvin$

According to the PHP bug tracker, the problem is a bug that affects Snow Leopard and FreeBSD as well. The fix is pretty simple, either you can build PHP from the head of the trunk from Subversion, or you can replace php-5.3.3/ext/mysqli/php_mysqli_structs.h with this patched version or you can just open one file (php-5.3.3/ext/mysqli/php_mysqli_structs.h) in your text editor and fix it yourself:

Trinity:~ kelvin$ sudo vim /Users/kelvin/phpsource/php-5.3.3/ext/mysqli/php_mysqli_structs.h

Go to line 59 and insert the following:

59
60
61
#if defined(ulong) && !defined(HAVE_ULONG)
#define HAVE_ULONG
#endif

The patched section of the file will then read as follows:

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/*
  The libmysql headers (a PITA) also define it and there will be an warning.
  Undef it and later we might need to define it again.
*/
#ifdef HAVE_MBRLEN
#undef HAVE_MBRLEN
#define WE_HAD_MBRLEN
#endif
#ifdef HAVE_MBSTATE_T
#undef HAVE_MBSTATE_T
#define WE_HAD_MBSTATE_T
#endif
 
#if defined(ulong) && !defined(HAVE_ULONG)
#define HAVE_ULONG
#endif
 
#include <my_global.h>
 
#if !defined(HAVE_MBRLEN) && defined(WE_HAD_MBRLEN)
#define HAVE_MBRLEN 1
#endif
 
#if !defined(HAVE_MBSTATE_T) && defined(WE_HAD_MBSTATE_T)
#define HAVE_MBSTATE_T 1
#endif

The rest of the build and install was uneventful after patching php_mysqli_structs.h.

Tags: , ,

Funniest release notes ever? Thank Chaos Tools for Drupal

From the Chaos Tools release notes for version 1.6 for Drupal 6:

The 1.5 release was botched: only some of the changes listed on the release notes were actually included. This release (1.6) includes all changes that were supposed to be in 1.5.

See for yourself and feel your confidence in the codebase rise with each word.

Tags: , , , ,

Installing Fileinfo on CentOS with PHP 5.2.13

I ran into some trouble installing the Fileinfo extension for PHP on CentOS. I tried installing the extension using yum and all went well until I saw these errors:

PHP Warning:  PHP Startup: fileinfo: Unable to initialize module
Module compiled with module API=20050922, debug=0, thread-safety=0
PHP    compiled with module API=20060613, debug=0, thread-safety=0
These options need to match

Like I said, I installed the extension using yum, so I checked out what I had installed:

$ yum list installed | grep "php-pecl-Fileinfo"
php-pecl-Fileinfo.x86_64               1.0.4-3.el5.centos              installed

Oh crap, I always forget to pull these things from the Atomicorp repository because my php is from there.

$ yum list installed | grep "php.x86_64"
php.x86_64                             5.2.13-1.el5.art                installed

Well, the bad news is that the Fileinfo extension is not available on the Atomicorp repo. Hmm. Ok, so my next step is to remove the thing and install it with PECL.

$ sudo yum erase php-pecl-Fileinfo.x86_64
...
Running Transaction
  Erasing        : php-pecl-Fileinfo                                                                                         1/1 
warning: /etc/php.d/Fileinfo.ini saved as /etc/php.d/Fileinfo.ini.rpmsave

Removed:
  php-pecl-Fileinfo.x86_64 0:1.0.4-3.el5.centos                                                                                  

Complete!
$ sudo rm /etc/php.d/Fileinfo.ini.rpmsave
$

I didn’t need that config file, because I never got it to work!

Install Fileinfo with PECL

Before anything else, here is the system I’m using:

$ cat /etc/redhat-release 
CentOS release 5.4 (Final)
$ php -v
PHP 5.2.13 (cli) (built: Mar  2 2010 18:08:48) 
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2010 Zend Technologies
$ pecl -V
PEAR Version: 1.9.0
PHP Version: 5.2.13
Zend Engine Version: 2.2.0
Running on: Linux system.local 2.6.18-028stab064.7 #1 SMP Wed Aug 26 13:11:07 MSD 2009 x86_64

If the PHP extension that I’m after is not in the yum repo then I usually just install it with PECL. It is fairly painless.

$ sudo pecl install fileinfo
audit_log_user_command(): Connection refused
WARNING: "pear/Fileinfo" is deprecated in favor of "channel://php-src/ext/fileinfo/in php sources"
downloading Fileinfo-1.0.4.tgz ...
Starting to download Fileinfo-1.0.4.tgz (5,835 bytes)
.....done: 5,835 bytes
3 source files, building
running: phpize

...lotsa crap...

build process completed successfully
Installing '/usr/lib64/php/modules/fileinfo.so'
install ok: channel://pear.php.net/Fileinfo-1.0.4
$

The PECL warning is trying to let you know that Fileinfo is bundled with PHP 5.3 and you don’t need to install if you are running PHP 5.3, but I’m running 5.2 so that warning is not for me. Okay, now we turn on the extension by putting “extension=fileinfo.so” somewhere in the /etc/php.ini file.

$ sudo vim /etc/php.ini
$

And make the change…

640
extension=fileinfo.so

Now restart apache…

$ sudo /sbin/service httpd restart
audit_log_user_command(): Connection refused
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]
$

Okay, let’s find out if it is in the phpinfo…

$ php -r "phpinfo();" | grep "fileinfo"
fileinfo
fileinfo support => enabled

Yay!!!

Tags: ,

Install PHP 5.2.12 on Mac OS 10.5.8 Leopard

PHP 5.2.12 has a bug that will stop your installation:

/bin/sh /Users/kelvin/phpsource/php-5.2.12/libtool --silent --preserve-dup-deps --mode=compile gcc  ...includes redacted...  -no-cpp-precomp  -I/usr/local/php5/include -g -O2  -c /Users/kelvin/phpsource/php-5.2.12/ext/standard/dns.c -o ext/standard/dns.lo 
In file included from /usr/include/arpa/nameser.h:59,
                 from /Users/kelvin/phpsource/php-5.2.12/ext/standard/dns.c:62:
/usr/include/arpa/nameser8_compat.h:304: error: conflicting types for ‘HEADER’
/usr/include/arpa/nameser_compat.h:99: error: previous declaration of ‘HEADER’ was here
make: *** [ext/standard/dns.lo] Error 1
Trinity:~ kelvin$ 

Two header files (nameser8_compat.h & nameser_compat.h) both try to define a struct named HEADER. No can do. According to the PHP bug tracker, “NEVER ever include nameser_compat.h, it’s included in various ways in different OSes by nameser.h if needed

Doh!

So how do we go about fixing this? The easiest thing to do is to install the older PHP 5.2.11 or the HEAD from the 5.2 branch. If you are adventurous or obsessive-compulsive you can also replace these two files with the patched copies:

  1. ~/php-5.2.12/configure.innotes
  2. ~/php-5.2.12/ext/standard/dns.cnotes

Tags: , , ,

Install libmcrypt and php-mcrypt on CentOS 5.3 without losing too much hair

I had to install mcrypt on a new virtual private server running CentOS 5.3 and Plesk 9.2. We didn’t want to do compile it, so we used yum to install it. The libmcrypt library is used to provide cryptographic functions and we are planning to use them in our php scripts. Let’s try to install it…

[root@nechi etc]# cat /etc/redhat-release
CentOS release 5.3 (Final)
[root@nechi etc]# uname -a
Linux nechi.local 2.6.18-028stab064.7 #1 SMP Wed Aug 26 13:11:07 MSD 2009 x86_64 x86_64 x86_64 GNU/Linux
[root@nechi etc]# php -v
PHP 5.2.11 (cli) (built: Oct 7 2009 08:45:24)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
[root@nechi etc]# yum repolist
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* atomic: www5.atomicorp.com
* base: mirror.nic.uoregon.edu
* updates: mirror.chpc.utah.edu
* addons: centos.mirror.nac.net
* extras: mirror.stanford.edu
plesk | 951 B 00:00
atomic | 951 B 00:00
base | 2.1 kB 00:00
updates | 1.9 kB 00:00
addons | 951 B 00:00
extras | 1.1 kB 00:00
repo id repo name status
addons CentOS-5 - Addons enabled : 0
atomic CentOS / Red Hat Enterprise Linux 5 - at enabled : 709
base CentOS-5 - Base enabled : 3,348
extras CentOS-5 - Extras enabled : 290
plesk Plesk Server Administrator enabled : 193
updates CentOS-5 - Updates enabled : 363
repolist: 4,903
[root@nechi etc]#

The easiest way to do this is to use the php-mcrypt rpm package. That package has some dependencies. Earlier, I had installed libmcrypt so I figured I could just install the php-related rpm and I’d be done:

[root@nechi etc]# yum install php-mcrypt
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* atomic: www5.atomicorp.com
* base: mirror.nic.uoregon.edu
* updates: mirror.chpc.utah.edu
* addons: centos.mirror.nac.net
* extras: mirror.stanford.edu
Excluding Packages from Plesk Server Administrator
Finished
Setting up Install Process
Parsing package install arguments
Resolving Dependencies
--> Running transaction check
---> Package php-mcrypt.x86_64 0:5.2.11-2.el5.art set to be updated
--> Processing Dependency: libltdl.so.3()(64bit) for package: php-mcrypt
---> Package php-mcrypt.i386 0:5.2.11-2.el5.art set to be updated
--> Processing Dependency: libltdl.so.3 for package: php-mcrypt
--> Processing Dependency: libc.so.6(GLIBC_2.4) for package: php-mcrypt
--> Processing Dependency: libc.so.6 for package: php-mcrypt
--> Processing Dependency: libmcrypt.so.4 for package: php-mcrypt
--> Processing Dependency: libc.so.6(GLIBC_2.1.3) for package: php-mcrypt
--> Processing Dependency: libc.so.6(GLIBC_2.0) for package: php-mcrypt
--> Running transaction check
---> Package libtool-ltdl.i386 0:1.5.22-6.1 set to be updated
---> Package php-mcrypt.i386 0:5.2.11-2.el5.art set to be updated
--> Processing Dependency: libmcrypt.so.4 for package: php-mcrypt
---> Package glibc.i686 0:2.5-42 set to be updated
---> Package libtool-ltdl.x86_64 0:1.5.22-6.1 set to be updated
--> Finished Dependency Resolution
php-mcrypt-5.2.11-2.el5.art.i386 from atomic has depsolving problems
--> Missing Dependency: libmcrypt.so.4 is needed by package php-mcrypt-5.2.11-2.el5.art.i386 (atomic)
Error: Missing Dependency: libmcrypt.so.4 is needed by package php-mcrypt-5.2.11-2.el5.art.i386 (atomic)
[root@nechi etc]#

Oh great, it’s 1am on a Saturday night and my new OS hates me (digression: this speaks volumes).

[root@nechi etc]# yum list installed | grep mcrypt
libmcrypt.x86_64 2.5.8-4.el5.centos installed
[root@nechi etc]# ldconfig -p | grep libmcrypt.so.4
libmcrypt.so.4 (libc6,x86-64) => /usr/lib64/libmcrypt.so.4
[root@nechi etc]# find / -name libmcrypt.so.4
/usr/lib64/libmcrypt.so.4
[root@nechi etc]# ls -la /usr/lib64/libmcrypt.so.4
lrwxrwxrwx 1 root root 18 Dec 6 00:25 /usr/lib64/libmcrypt.so.4 -> libmcrypt.so.4.4.8
[root@nechi etc]# yum install libmcrypt-devel
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* atomic: www5.atomicorp.com
* base: mirror.nic.uoregon.edu
* updates: mirror.chpc.utah.edu
* addons: centos.mirror.nac.net
* extras: mirror.stanford.edu
Excluding Packages from Plesk Server Administrator
Finished
Setting up Install Process
Parsing package install arguments
Resolving Dependencies
--> Running transaction check
---> Package libmcrypt-devel.x86_64 0:2.5.8-4.el5.centos set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================================================================================================
Package Arch Version Repository Size
=========================================================================================================================================
Installing:
libmcrypt-devel x86_64 2.5.8-4.el5.centos extras 10 k

Transaction Summary
=========================================================================================================================================
Install 1 Package(s)
Update 0 Package(s)
Remove 0 Package(s)

Total download size: 10 k
Is this ok [y/N]: y
Downloading Packages:
libmcrypt-devel-2.5.8-4.el5.centos.x86_64.rpm | 10 kB 00:00
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
Installing : libmcrypt-devel [1/1]

Installed: libmcrypt-devel.x86_64 0:2.5.8-4.el5.centos
Complete!
[root@nechi etc]# yum install php-mcrypt

So can you guess what happened next? The library was found the next time I tried to install it, right? Of course not. It still couldn’t find the stupid library. So Google and I had a talk and it turns out that you need to be really specific about your package (a good general rule in most situations) if you have a 64-bit machine.

[root@nechi etc]# yum install php-mcrypt.x86_64
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
* atomic: www5.atomicorp.com
* base: mirror.nic.uoregon.edu
* updates: mirror.chpc.utah.edu
* addons: centos.mirror.nac.net
* extras: mirror.stanford.edu
Excluding Packages from Plesk Server Administrator
Finished
Setting up Install Process
Parsing package install arguments
Resolving Dependencies
--> Running transaction check
---> Package php-mcrypt.x86_64 0:5.2.11-2.el5.art set to be updated
--> Processing Dependency: libltdl.so.3()(64bit) for package: php-mcrypt
--> Running transaction check
---> Package libtool-ltdl.x86_64 0:1.5.22-6.1 set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

=========================================================================================================================================
Package Arch Version Repository Size
=========================================================================================================================================
Installing:
php-mcrypt x86_64 5.2.11-2.el5.art atomic 27 k
Installing for dependencies:
libtool-ltdl x86_64 1.5.22-6.1 base 37 k

Transaction Summary
=========================================================================================================================================
Install 2 Package(s)
Update 0 Package(s)
Remove 0 Package(s)

Total download size: 64 k
Is this ok [y/N]: y
Downloading Packages:
(1/2): php-mcrypt-5.2.11-2.el5.art.x86_64.rpm | 27 kB 00:00
(2/2): libtool-ltdl-1.5.22-6.1.x86_64.rpm | 37 kB 00:00
-----------------------------------------------------------------------------------------------------------------------------------------
Total 76 kB/s | 64 kB 00:00
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
Installing : libtool-ltdl [1/2]
Installing : php-mcrypt [2/2]

Installed: php-mcrypt.x86_64 0:5.2.11-2.el5.art
Dependency Installed: libtool-ltdl.x86_64 0:1.5.22-6.1
Complete!
[root@nechi etc]#

OMFG. Hey, did I mention that it is a Saturday night?

[root@nechi etc]# php -r "echo phpinfo();" | grep "^mcrypt"
mcrypt
mcrypt support => enabled
mcrypt.algorithms_dir => no value => no value
mcrypt.modes_dir => no value => no value
[root@nechi etc]#

Tags: , ,

PHP makes me cry

4am: editing crufty code. lots of logic mixed up in the html old school style. Across the room a pile of three HP servers that need OSes catcalling: “I think I need a rebooty…”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// TODO: Clean this input
//$tpar= $_GET[parent];
$tpar= intval($_GET['parent']);
// TODO: Why are we putting a date into the server array???
$SERVER['$today']= date('y-m-d');
// TODO: Why are we storing a negative integer value as a string???
$colname_res_fillContent = "-1";
if (isset($_GET['parent'])) {
// TODO: Check this input
//$colname_res_fillContent = (get_magic_quotes_gpc()) ? $_GET['parent'] : addslashes($_GET['parent']);
  $colname_res_fillContent = intval($_GET['parent']);
}
// TODO: Why are we storing a negative integer value as a string again???
$today_res_fillContent = "-1";
if (isset($SERVER['$today'])) {
    //
    // TODO: didn't we set this??? why are we doing this??? why not set the date here???
    //
  $today_res_fillContent = (get_magic_quotes_gpc()) ? $SERVER['$today'] : addslashes($SERVER['$today']);
}

Tags: , , ,

The White House Server! W00t!

So President Obama has finally moved whitehouse.gov over to Drupal. Launching Live HTTP Headers tells us the following (emphasis added):

HTTP/1.x 200 OK
Last-Modified: Sat, 07 Nov 2009 05:10:20 GMT
Etag: "b878176b01d8ede48b51ca5b4ede04cf"
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 8956
Cache-Control: must-revalidate, max-age=0
Expires: Sat, 07 Nov 2009 07:01:03 GMT
Date: Sat, 07 Nov 2009 07:01:03 GMT
Connection: keep-alive
Server: White House
P3P: CP="NON DSP COR ADM DEV IVA OTPi OUR LEG"

Downloading me some of that right now!

Tags: , , , ,

Keep your WordPress up to date!

One of my clients got hacked last week. They had been running a copy of WordPress 2.5 (WP) that was installed in May of 2008 and never updated. Although WordPress 2.5.1 was released 25 April 2008 and included an important security fix, the Client software was never upgraded.

So how do you keep your WP install up to date?

Since WP 2.7, you can upgrade from the dashboard. This is by far the easiest way to stay up-to-date, but there have been some problems reported when running on some hosts so find the right host.

You can also do a manual upgrade of the software. WordPress has a mailing list and an RSS feed which all WP admins should subscribe to.

Pay someone to keep it all up to date.

And lastly, if you don’t want to have to be bothered with all this, then don’t run your own blogging software. Run a hosted solution.

Tags: ,