CodeIgniter redirect: white page

The problem with CodeIgniter redirect

I’ve wasted two hours with this issue (CodeIgniter redirect leading to a white page) so I thought I’d write a post about in case someone has the same problem. I’m currently writing a software using CodeIgniter. When you login, if the login validation succeeds, you are redirected to the home page, otherwise an error is shown and you stay on the login page. Here’s how my login controller looks like:

class Login extends CI_Controller {

	function index() {
		$this->load->view('login', $this->data);
	}

	function process() {
		$this->load->library('form_validation');
		
		[...]
		
		if ($this->form_validation->run() == FALSE) {
			$this->load->view('login', $this->data);
		}
		else {
			// Go to private area
			redirect('home', 'refresh');
		}
	}
}

I am usually coding on a Mac using either MAMP or native PHP/MySQL and sometimes on a Windows machine. With all 3 combinations, it did work fine. But the server on which the software will be hosted is a Debian machine. So I after I was done with some parts of the software I uploaded it to the server. The login screen was displayed just fine but after logging in, I just go a white page a.k.a PHP white screen of death.

The first thing I did was to check my PHP error log file. Nothing there. Then I checked the CodeIgniter application log file. Nothing there either. The source code of the page in the browser was completely empty. So I thought that I just didn’t see an error message because the log levels weren’t set properly. First I changed the log level in php.ini:

error_reporting = E_ALL | E_STRICT

And restarted the apache web server. This didn’t help. Still no log file entry related to my problem.

Then I increased the log level in CodeIgniter (in /application/config/config.php):

$config['log_threshold'] = 4;

This didn’t help either. I could see that everything was fine in the log file.

I also tried forcing the display of error message by adding this in my controller (and finally also in index.php) but it didn’t work either:

error_reporting(E_ALL | E_WARNING | E_NOTICE);
ini_set('display_errors', TRUE);

Without a clue, I added error_log commands before every line in my controller. I could then see in the PHP error line that everything up to the redirect was working fine. So the redirect function was my problem.

The first check was to see whether the url helper was properly loaded. In /application/config/autoload.php:

$autoload['helper'] = array('url', 'form');

So it’s fine. Actually you can see it in the CodeIgniter application log file:

DEBUG - 2013-08-03 22:52:47 --> Loader Class Initialized
DEBUG - 2013-08-03 22:52:47 --> Helper loaded: url_helper
DEBUG - 2013-08-03 22:52:47 --> Helper loaded: form_helper
DEBUG - 2013-08-03 22:52:47 --> Database Driver Class Initialized
DEBUG - 2013-08-03 22:52:47 --> Session Class Initialized
DEBUG - 2013-08-03 22:52:47 --> Helper loaded: string_helper
DEBUG - 2013-08-03 22:52:47 --> Session routines successfully run
DEBUG - 2013-08-03 22:52:47 --> Controller Class Initialized

So the CodeIgniter redirect function was available (anyway I didn’t get a message it was missing, so it couldn’t have been the problem). So I checked the documentation regarding the CodeIgniter redirect function:

Note: In order for this function to work it must be used before anything is outputted to the browser since it utilizes server headers.

So I checked the code for some echo commands which might be executed before the CodeIgniter redirect. I also looked for spaces or line breaks before my opening <?php tags. But found nothing. Anyway, if this was the problem I should see somewhere something like this:

Cannot modify header information - headers already sent

The solution

Then I noticed the following in the CodeIgniter redirect documentation:

The optional second parameter allows you to choose between the “location” method (default) or the “refresh” method. Location is faster, but on Windows servers it can sometimes be a problem.

I actually didn’t really know why I was using refresh. I had just reused some code found somewhere. Since I do not plan to run my software on Windows servers, I though I’d just try removing the refresh so that I use location and see whether the problems still occurs:

redirect('home');

And there was my page ! The difference between location and refresh in CodeIgniter redirect is just that refresh does the following:

header("Refresh:0;url=".$uri);

and location:

header("Location: ".$uri, TRUE, $http_response_code);

Where the default value of $http_response_code is 302.

So I still do not know what the actual problem with refresh was and why it only occurred on our Linux server and on none of the Mac and Windows machines I use. But the CodeIgniter redirect issue is solved now and I’ve already moved on to the next issue.

PHPUnit on Mac OS X: install failed

You might get the following error while installing PHPUnit on a Mac:

$ pear install pear.phpunit.de/PHPUnit
Attempting to discover channel "pear.phpunit.de"...
downloading channel.xml ...
Starting to download channel.xml (804 bytes)
....done: 804 bytes
Auto-discovered channel "pear.phpunit.de", alias "pear.phpunit.de", adding to registry
unknown channel "pear.phpunit.de" in "pear.phpunit.de/PHPUnit"
invalid package name/package file "pear.phpunit.de/PHPUnit"
install failed

This basically means that just like me, you either do not read manuals or just copy & paste from the manual without reading the parts between code/commands. What you should have read is:

commands (which you may have to run as root)

Yes, it’s that simple, just use sudo:

$ sudo pear install pear.phpunit.de/PHPUnit
Attempting to discover channel "pear.phpunit.de"...
downloading channel.xml ...
Starting to download channel.xml (804 bytes)
....done: 804 bytes
Auto-discovered channel "pear.phpunit.de", alias "phpunit", adding to registry
Attempting to discover channel "pear.symfony.com"...
downloading channel.xml ...
Starting to download channel.xml (811 bytes)
...done: 811 bytes
Auto-discovered channel "pear.symfony.com", alias "symfony2", adding to registry
Did not download optional dependencies: phpunit/PHP_Invoker, use --alldeps to download automatically
phpunit/PHPUnit can optionally use package "phpunit/PHP_Invoker" (version >= 1.1.0, version <= 1.1.99)
phpunit/PHP_CodeCoverage can optionally use PHP extension "xdebug" (version >= 2.0.5)
downloading PHPUnit-3.7.21.tgz ...
Starting to download PHPUnit-3.7.21.tgz (118,818 bytes)
...done: 118,818 bytes
downloading File_Iterator-1.3.3.tgz ...
Starting to download File_Iterator-1.3.3.tgz (5,152 bytes)
...done: 5,152 bytes
downloading Text_Template-1.1.4.tgz ...
Starting to download Text_Template-1.1.4.tgz (3,701 bytes)
...done: 3,701 bytes
downloading PHP_CodeCoverage-1.2.11.tgz ...
Starting to download PHP_CodeCoverage-1.2.11.tgz (159,849 bytes)
...done: 159,849 bytes
downloading PHP_Timer-1.0.4.tgz ...
Starting to download PHP_Timer-1.0.4.tgz (3,694 bytes)
...done: 3,694 bytes
downloading PHPUnit_MockObject-1.2.3.tgz ...
Starting to download PHPUnit_MockObject-1.2.3.tgz (20,390 bytes)
...done: 20,390 bytes
downloading Yaml-2.3.0.tgz ...
Starting to download Yaml-2.3.0.tgz (39,791 bytes)
...done: 39,791 bytes
downloading PHP_TokenStream-1.1.5.tgz ...
Starting to download PHP_TokenStream-1.1.5.tgz (9,859 bytes)
...done: 9,859 bytes
install ok: channel://pear.phpunit.de/File_Iterator-1.3.3
install ok: channel://pear.phpunit.de/Text_Template-1.1.4
install ok: channel://pear.phpunit.de/PHP_Timer-1.0.4
install ok: channel://pear.symfony.com/Yaml-2.3.0
install ok: channel://pear.phpunit.de/PHP_TokenStream-1.1.5
install ok: channel://pear.phpunit.de/PHP_CodeCoverage-1.2.11
install ok: channel://pear.phpunit.de/PHPUnit_MockObject-1.2.3
install ok: channel://pear.phpunit.de/PHPUnit-3.7.21

Do I feel ashamed, it took me more than 2 minutes to realized what I had missed ? Definitely. But I just make my stupidity public in case others might face the same problem…

Install PEAR on Mac OS X Mountain Lion (10.8)

For some reason, PEAR is not installed on Mountain Lion. But fortunately. an installation PHP Archive is available to install it. It’s located in /usr/lib/php. It is thus very easy to install it using:

sudo php /usr/lib/php/install-pear-nozlib.phar

Enter the password and it gets installed in a second !

You can check the installation by running pear version:

$ pear version
PEAR Version: 1.9.4
PHP Version: 5.3.15
Zend Engine Version: 2.3.0
Running on: Darwin NEWMACBOOKPRO.local 12.4.0 Darwin Kernel Version 12.4.0: Wed May  1 17:57:12 PDT 2013; root:xnu-2050.24.15~1/RELEASE_X86_64 x86_64

Of course an alternative is to install MAMP or XAMPP which come with PEAR installed.

Eclipse: No entries available when choosing PHP file for debugging

I have Eclipse Juno installed. I created a PHP project for a new application I’m working on (you’ll hear more about this project in the next weeks), imported the code. Then I wanted to debug it. But run into a few problems…

First I couldn’t create a “PHP Web Application” debug configuration because of the following error:

 No tab group defined for launch configuration type org.eclipse.php.debug.core.launching.webPageLaunch

After spending some time on Google I found out it is because Eclipse Juno comes with an older version of PDT and I needed to install 3.1.1 or newer. Some how it also took me a while to find out that the right update site was http://download.eclipse.org/tools/pdt/updates/3.2/release/. Well everybody is allowed to have a slow brain once in a while…

While installing got another error with some missing dependencies… The PDT Core Unit Tests was missing bundle org.eclipse.dltk.core.tests 0.0.0. The package name ending with 0.0.0 doesn’t seem right but it was solved by just installing PDT and not the Unit Tests package. I wasn’t really planning to use this package but it’s always nice to know I couldn’t even if I wanted to :-).

Then I checked the debug configuration again. Now I was able to create a PHP Web Application debug configuration but when I clicked on Browse to select the file to debug, I just got a disabled UI saying that no files were available. Searching in Google confirmed that I’m not the only one with the problem but I didn’t find a documented solution except some hints that it might mean that I didn’t have a PHP project. But I actually did have one (had the nice PHP icon next to my project name in the project explorer). Since googling wasn’t looking very promising, I started looking all context menu entries when right clicking on the project. And I found a menu entry:

Configure > Add PHP Support...

Well it actually didn’t make much sense to me. Why would I need to add PHP support to a PHP project. If anything should already have PHP support, it should be a PHP project. But I didn’t have any other lead so I just did it. It updated the project file. And there it was, I was then able to select a PHP file to debug !!

Summary:

  • Update the PDT installation in Eclipse to the newest one
  • Only install the PDT package and not the PDT Core Unit Tests package
  • Add PHP support to your PHP project

PHP Localization

When you’re setting up the multi language site, at some point in time, you need to decide which option you will use for static text on the site.

There are a few options available when working with PHP:

When dealing with localization and internationalization, you many need all or some of the following features:

  1. storing and retrieving of strings by locale
  2. message formatting functions including support for variables and placement holders
  3. support for singular, plural and other
  4. support for sorting according to different locales
  5. support for different date, time and currency formats
  6. tools for extraction from source code
  7. tools for having the application translated and for loading the translations
  8. a possibility to add new languages without changing the application
  9. a fallback mechanism i.e. load the de_DE translation in case the de_AT translation is not available.

gettext

gettext™ is the GNU library for internationalization and translation. It is also natively supported by PHP. gettext is quite widely used (most notably in WordPress). It is easy to use and quite powerful. It focuses on the storage, retrieval and formatting of messages.

So that gettext can be used in PHP, it must have been built with the –with-gettext option or have to make sure the gettext extension is enabled in php.ini and loaded as a shared/dynamic library.

Windows users should see the following:

extension=php_gettext.dll

Unix/Linux users:

extension=gettext.so

You can check whether your PHP installation supports gettext with the following code:

<?php

if (function_exists("gettext")) {
    echo "gettext installed";
}
else {
    echo "gettext not installed";
}
?>

gettext supports the concept of translation domains. A domain is defining a translation scope which allows to have different translations for the same key in different libraries. Let’s say you use two different libraries which both show the string “I am going to %s” in English. In one library, the placeholder contains an action. In the other one the name of a country. If you now translate the first one let’s say in German, you’ll get “Ich werde %s”. In the second case, “Ich fahre nach %s”. So you need not to mix the two and allows each library to get it’s translation. This is done through domains. Each library will define it’s own domain and will not see the translation of other domains.

A domain also defines a root path for the translations. It is defined like this:

bindtextdomain("mytextdomainname", "mytextdomainlocaleroot");

After that you can also set a default text domain (it defines the text domain used when no text domain is specified):

textdomain("mytextdomainname");

A common choice for the text domain name is the name of the software, library or plugin.

Under the translation root path, you’ll the following directory structure:

/translation_root_path
    /en_US
        /LC_MESSAGES
            messages.po
            messages.mo
    /de_DE
        /LC_MESSAGES
            messages.po
            messages.mo

The messages.po file is a text file containing all translated entries. The messages.mo file is a compiled binary file read by gettext. Getting a messages.mo file involves the following steps:

  1. Extract all strings to be translated from the source code using xgettext. This will create a messages.po file
  2. Translate all string in messages.po
  3. Compile messages.po to messages.mo using msgfmt

The input for xgettext is a bunch of source code files:

xgettext *.php

Your can also use the following options:

  • -n to have the location of the string (which line of which file) written as a comment
  • -j to merge with an existing file
  • -o to specify an output file

You can also merge two .po files like this:

msgmerge old.po new.po --output-file=messages.po

This will merge new.po into old.po and create messages.po. It’s basically similar to:

msgmerge old.po new.po > messages.po

You can also run it in update mode:

msgmerge -U messages.po new.po

This will merge new.po into an existing messages.po. So basically when you make changes, you’ll create a new .po file and merge it with the existing one:

xgettext -o new.po *.php
msgmerge -U messages.po new.po
rm new.po

Translation and messages.po files can be updated and managed using poedit. Poedit is a free GUI tool for computer aided translation of documentation and user interfaces. It’s basically a UI frontend for the tools of GNU gettext used to edit .po files. It provides functionality for managing translation projects with a minimalistic UI. Not yet finished translations are specially marked so that it’s easy to see them, translation catalogs can be imported and unknown translations can be automatically taken over from the catalog.

Once the messages.po file is translated, you can compile it like this:

msgfmt messages.po

This generates the messages.mo file which can then be copied to the appropriate directory as shown above.

To set the language which is then used to load the appropriate messages.mo file, use the following code:

$language = "en_US";
putenv("LANG=" . $language); 
setlocale(LC_ALL, $language);

Now you can use the following to get a translated text:

echo _("Hello World!");

_(…) is a shortcut for gettext(…). Since you’ll be writing many such calls, you’ll soon be glad to have this shortcut :-).

The gettext function returns the translated string from the current text domain (set using the textdomain function). If you need a translation from another domain than the default domain (which is often the case when you work on plugins for an application, where the default text domain is the one of the application and you do not want to change it in a plugin), use dgettext instead:

echo dgettext("mytextdomainname", "mystring");

There are also versions of these two methods which can handle singular/plural: ngettext and dngettext. Here an example with ngettext:

echo ngettext("an apple", "a few apples", $no_of_apples);

ngettext will check whether the third parameter is one (in which case it will consider the first string) or more than one (in which case it will consider the second string). Here another example actually writing the number of apples:

printf(ngettext("%d window", "%d windows", $no_of_apples), $no_of_apples);

Note that gettext .mo files are cached so if you modify a messages.mo file you might notice that the changes are not active. They will only become active after you restart the web server. A few workaround are also described here.

The big advantage of the gettext approach is that you can use gettext without defining any translation at first and then define the translations. Since the strings used as keys are the text in the default language, you will always have a text displayed even if the corresponding translation does not exist yet. The downside is that you basically mix the text for the default language and code which some might find unclean.

Also gettext doesn’t address the conversion of date, time and currencies. It also doesn’t address the language specific sorting of localized entries.

You can find more info on gettext on the gettext GNU project page.

Note that WordPress uses gettext for translation and defines a few additional helper functions:

__('some message') // returns the translation for 'some message'
_e('some message') // echoes the translation for 'some message'
_n('some singular message', 'some plural message', $count ) // returns either the translation for 'some singular message' or 'some plural message' depending on the value of $count

Associative Arrays

This technique basically involves having PHP files containing a big associative array which keys are referenced in the code and values contain the translation in a given language. Based on the language selected in the application, you will load one array or the other one.

Defining such an array is as easy as:

$lang = array(
	"HELLO_WORLD" => "Hallo Welt !",
)

for the German version and the following for the French version:

$lang = array(
	"HELLO_WORLD" => "Bonjour monde !",
)

In you code, you’d load the appropriate translation like this:

<?php
if(isset($_REQUEST['lang'])) {
	//Explicitely set as URL parameter
	$lang = $_REQUEST['lang']; //read it from the URL parameters
	$_SESSION['lang'] = $lang; //save it in the session
	setcookie('lang', $lang, time() + (3600 * 24 * 20)); //set a cookie for 20 days
}
else if(isset($_SESSION['lang'])) {
	//Fallback: read it from the session information
	$lang = $_SESSION['lang'];
}
else if(isset($_COOKIE['lang'])) {
	//Fallback: read it from the cookie
	$lang = $_COOKIE['lang'];
}
else {
	//Fallback: English is the default
	$lang = 'en';
}

//The files are named lang.LANGUAGE.php i.e. lang.en.php
//Assumption: language files are stored in the langs subdirectory
$lang_ile = 'langs/lang.'.$lang.'.php';
if (!file_exists($lang_file)) {
	//Fallback: if no translation is available for this language, use English
	$lang_file = 'langs/lang.en.php';
}

//Load the selected translation
include_once $lang_file;
?>

Now you’ve loaded the file, you can access the translated string like this:

<?php
	echo $lang['HELLO_WORLD'];
?>

Now this works file if you have no parameter in the translation. Let’s say you want to write “I’ve seen Henri” but implement it so that if $person contains Alex instead of Henri, you can just do something like “I’ve seen $person”. Of course just doing it this way will not work:

<?php
	echo $lang['I_HAVE_SEEN'].' '.$person;
?>

Since in German, it would say: “Ich habe gesehen Henri” instead of “Ich habe Henri gesehen”. So you need to be able to define place holders. You can handle this using such a function:

function translate() {
	global $lang;
	$parameters = func_get_args();
	$parameters[0] = $lang[$parameters[0]];
	return call_user_func_array('sprintf', $parameters);
}

Here a short line by line explanation of the code of the function:

  1. we will use the $lang variable defined outside of the function.
  2. func_get_args returns all parameters of the containing function.
  3. we replace the code used as first parameter by the format string defined in the translation array.
  4. we call sprint with the entries of the array as parameter and return the results.

And you can use this function like this:

echo translate('I_HAVE_SEEN', 'Henri');

Disadvantages of this method:

  • It doesn’t support plural forms i.e. one child vs. two children
  • There is no default. If the translation doesn’t contain the string, you have a problem
  • It only takes care of storing and reading the translation, nothing else

PHP internationalization extension

Intl is the PHP internationalization extension and was introduced in PHP 5.3. It is basically a wrapper for the ICU (International Components for Unicode) library.. It focuses on collation and formatting of dates, times, numbers and currencies.

Translation2

Translation2 is a class to manage internationalization and translations in applications. The main advantages of Translation2 are:

  • It supports different containers for the translations e.g. in a database, using gettext, using XML.
  • It’s very flexible and supports decorators which can provide additional functionality e.g. caching, converting, fallbacks…
  • It supports fallback languages which is not always easy with the other solutions.
  • It has an administration class which makes it easy to manage translations.

More will be added to this post soon…

PHP: Displaying the Alexa ranking of a web site

Alexa is a subsidiary of Amazon. They gather data about web sites and offer web traffic metrics. What’s called the Alexa Rank is basically the position of a web site compared to all websites.

There is no real public API provided to get information from Alexa. But there’s a URL where you can get an XML response for a given URL. The response will then contain some useful information (the rank among others).

The URL goes like this:

http://data.alexa.com/data?cli=10&url=<THE_URL_TO_CHECK>

Here an example from the command line:

$ curl "http://data.alexa.com/data?cli=10&url=http://benohead.com"
<?xml version="1.0" encoding="UTF-8"?>

<ALEXA VER="0.9" URL="benohead.com/" HOME="0" AID="=">
<DMOZ>
<SITE BASE="benohead.com/" TITLE="Benohead's Software Blog" DESC="A blog about software related topics: Linux, Mac OS X, Java, HL7, DICOM, WordPress, web design, databases...">
<CATS/>
</SITE>
</DMOZ>
<SD>
<POPULARITY URL="benohead.com/" TEXT="2428475" SOURCE="panel"/>
<REACH RANK="2070623"/>
<RANK DELTA="-19485883"/>
<COUNTRY CODE="US" NAME="United States" RANK="1914521"/>
</SD>
</ALEXA>

If you go to alexa.com and search for benohead.com, you’ll see that 2428475 is the Alexa Rank of this page. So we just need to extract this info using PHP:

First get the data from the URL for a given domain:

$data = file_get_contents("http://xml.alexa.com/data?cli=10&url=".$domain);

Now the data you got was a XML message. So you’ll some XML library to fully interpret it. But since we’re only really interested in the rank, we can just match the string using preg_match:

if (preg_match('/\<popularity url\="(.*?)" text\="([0-9]+)" source="(.*?)"\/\>/si', $data, $matches)) 
{ 
   $rank = $matches[2]; 
}

If you are also interested in the number of links, you will need to add dat=snbamz to the URL call:

$data = file_get_contents("http://xml.alexa.com/data?cli=10&dat=snbamz&url=".$domain);

This will return something like this:

<?xml version="1.0" encoding="UTF-8"?>

<ALEXA VER="0.9" URL="benohead.com/" HOME="0" AID="=">
<RLS PREFIX="http://" more="0">
</RLS>
<SD TITLE="A" FLAGS="DMOZ" HOST="benohead.com">
<CLAIMED DATE="2012-06-26T16:26:04Z"/>
<COUNTRY CODE="US"/>
<ALEXAPRO TIER="intro"/>
<LINKSIN NUM="11"/>
</SD>
<DMOZ>
<SITE BASE="benohead.com/" TITLE="Benohead's Software Blog" DESC="A blog about software related topics: Linux, Mac OS X, Java, HL7, DICOM, WordPress, web design, databases...">
<CATS/>
</SITE>
</DMOZ>
<SD>
<POPULARITY URL="benohead.com/" TEXT="2428475" SOURCE="panel"/>
<REACH RANK="2070623"/>
<RANK DELTA="-19485883"/>
<COUNTRY CODE="US" NAME="United States" RANK="1914521"/>
</SD>
</ALEXA>

The LINKSIN NUM part contains the number of incoming links. So you can fetch it like this:

if (preg_match('/\<linksin num\="([0-9]+)"\/\>/si', $data, $matches))
{
   $nooflinks = $matches[1];
}

Putting it all together:

<?php
$domain = 'benohead.com';
echo 'Domain:'.$domain.'<br>';
$data = file_get_contents('http://data.alexa.com/data?cli=10&dat=snbamz&url='.$domain);
if (preg_match('/\<popularity url\="(.*?)" text\="([0-9]+)" source="(.*?)"\/\>/si', $data, $matches))
{
    $rank = $matches[2];
}
if (preg_match('/\<linksin num\="([0-9]+)"\/\>/si', $data, $matches))
{
   $nooflinks = $matches[1];
}
echo 'Alexa Rank:'.number_format($rank).'<br>';
echo 'Number of links:'.number_format($nooflinks);
?>

Check username availability using jQuery and PHP

I’m working on a new website. I currently only have a screen where the new users can register. Since I want to make it as easy as possible for a new user to register (partly to avoid having them give up in the first few minutes), I need to take care of the username issue:
When you register somewhere, you have to enter a few things about yourself and though I’m sticking to only username, email address and password it’s still a pain to fill it all in, click submit and get the message that the username is not free.
It’s much easier on the new user, if you immediately give him feedback whether the username he has chosen is still free. And it’s much better, if he doesn’t have to click X times on the “check availability” button.

So basically what I need is a form with a username text field. And whenever the user types in something, I want to give some visual feedback (like changing the color of the text field border) whether this username is available or not.

First I need a form element (in the body):

<form method="post" action="register.php">
	<label for="username">Username</label>
	<input type="text" maxlength="30" name="username" id="username">
	<input type="submit" value="submit">
</form>

Of course such a form with only a username makes no sense, but it’s good enough to explain what I’m doing…

Next, we need to do some jQuery magic (in the head section):

<script src="jquery-1.8.0.min.js"></script>
<script>
$(document).ready(function(){
	$('#username').keyup(check_username);
});

function check_username(){
	var username = $('#username').val();
	if(username == '' || username.length < 6){
		$('#username').removeClass("available").removeClass("notavailable");
	}
	else {
		jQuery.ajax({
			type: 'POST',
			url: 'check_username.php',
			data: 'username='+ username,
			cache: false,
			success: function(response){
				if(response == 1){
					$('#username').removeClass("available").addClass("notavailable");
				}
				else {
					$('#username').removeClass("notavailable").addClass("available");
				}
			}
		});
	}
}
</script>

A few comments on this part:

  • I use keyup to install my function because I want the check to happen as the user types. If it creates too much network traffic for your taste or it’s good enough for you to only check the availability when the user leaves this text field, you could use change() or blur().
  • Since in my case the username needs to have at least 6 characters I do not check usernames with less than 6 characters.

As you see I use some CSS classes to change the appearance of the text field based on the availability of the username, here the CSS part:

.notavailable {
    border: 3px #C33 solid !important;
}
.available {
    border: 3px #090 solid !important;
}

Instead of changing the border color, you could also change the background color or show a tick or cross sign…

Now let’s have a look at the last piece: the PHP part on the server, check_username.php (which is called using Ajax):

<?php
$username= mysql_real_escape_string($_REQUEST["username"]);
$con = mysql_connect("xxxxxx","xxxxxx","xxxxxx");
if (!$con)
{
	echo 0;
}
else {
	mysql_select_db("xxxxxx", $con);
	$result = mysql_query("SELECT * FROM users WHERE username='" . $username . "'");
	$num = mysql_num_rows($result);
echo $num; //it will always return 1 or 0 since we do not allow multiple users with the same user name.
}
mysql_close();

That’s it ! And this is how it looks like:
Green border when the user name is available
Red border when the user name is not available

WordPress: Twenty eleven – fix the sidebar on the iPhone

When I visited my blog on my iPhone, I first couldn’t see the sidebar and thought it was missing. There was an empty space where the sidebar was supposed to be but no sidebar was displayed. But today, for some reason I ended up scrolling to the bottom of the screen and saw that my scrollbar was actually displayed below the main content area and not on the side.

In order to fix it, I first searched for a reason for this in the stylesheet of my parent theme (twenty eleven). There I found the following:

/* =Responsive Structure
----------------------------------------------- */

@media (max-width: 800px) {
	/* Simplify the basic layout */
	#main #content {
		margin: 0 7.6%;
		width: auto;
	}
...
	#main #secondary {
		float: none;
		margin: 0 7.6%;
		width: auto;
	}
...
}

This is the reason why I was having this strange layout on the iPhone. It basically defines an alternative style for displayed of no more than 800 pixel in width (like my iPhone).

In order to fix it, I just had to add the following to the stylesheet of my child theme (style.css):

@media (max-width: 800px) {
	#page {
		min-width: 500px;
	}
	#main #content {
		margin: 0 23.8% 0 1%;
		width: 76.2%
	}
	#main #secondary {
		float: right;
		margin: 0 1% 0 1%;
		width: 18.8%;
	}
}

And the sidebar is again a sidebar and not a “below bar” anymore !

WordPress: Create a child theme for twentyeleven with sidebars on posts and posts sorted by modified date

In order to create our child theme, we first need to create a directory for your theme:

# cd /var/www/vhosts/benohead.com/httpdocs/wp-content/themes
# mkdir twentyelevenbenohead
# chown www-data:www-data twentyelevenbenohead

Replace the first path above by the path to your themes directory under wordpress, twentyelevenbenohead by the name you want to give to your theme and www-data by the user and group the other subdirectories in the themes directory (basically it’s the username and group name for apache).

The you need to create a style.css file like for all themes:

# cd twentyelevenbenohead
# vi style.css

And type in the following (press “i” before typing to go in insert mode):

/*
Theme Name: Twenty Eleven Child for Benohead
Theme URI: http://benohead.com/wordpress-create-a-child-theme-for-twentyeleven-with
Description: Child theme for the Twenty Eleven with  sidebars on posts and posts sorted by modified date
Author: Henri Benoit
Template: twentyeleven
Version: 0.1
*/

/* We must first include the original css from the parent theme */
@import url("../twentyeleven/style.css");

To save in vi, type ESC to stop the inserting mode, the press ZZ (or :wq) in order to save the file and exit.

This file basically defines your new theme as a child theme for twentyeleven and imports the styles from twentyeleven.

Now let’s add some functionality to our theme. First let’s start with the sidebar for posts. The way single posts are displayed is controlled by the file single.php. So we need to first get a copy of this single.php and edit it:

# cp ../twentyeleven/single.php .
# vi single.php

Now just add:

<?php get_sidebar(); ?>

before the following line:

<?php get_footer(); ?>

Now we have our sidebar in posts. But we still need to fix the way our post is displayed. In twentyeleven, there is a div class called singular. Its purpose is to remove the margin on singular articles. In our case, we just made our posts not singular by adding a sidebar. This singular class is added in the function twentyeleven_body_classes which is added as hook in functions.php using:

add_filter( 'body_class', 'twentyeleven_body_classes' );

Since the function twentyeleven_body_classes is defined without checking for it’s existence and the function definitions of the parent theme are loaded after those of the child theme, we cannot just override the function. So we need to unregister the function once the theme is fully loaded. This can be done in functions.php (which is a new file for our child theme):

# vi functions.php

There add the following:

<?php

add_action( 'after_setup_theme', 'remove_twentyeleven_body_classes' );

function remove_twentyeleven_body_classes() {
remove_filter( 'body_class', 'twentyeleven_body_classes' );
}

?>

Now, our sidebars also look good. Let’s now display the modified date (instead of the original publish date) in the posts and let’s sort them accordingly. First we’ll override the corresponding function in functions.php (add it before “?>”):

if ( ! function_exists( 'twentyeleven_posted_on' ) ) :
/**
* Prints HTML with meta information for the current post-date/time and author.
* Create your own twentyeleven_posted_on to override in a child theme
*
* @since Twenty Eleven 1.0
*/
function twentyeleven_posted_on() {
printf( __( '<span class="sep">Posted on </span><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s" pubdate>%4$s</time></a><span class="by-author"> <span class="sep
"> by </span> <span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span>', 'twentyeleven' ),
esc_url( get_permalink() ),
esc_attr( get_the_modified_time() ),
esc_attr( get_the_modified_date( 'c' ) ),
esc_html( get_the_modified_date() ),
esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
esc_attr( sprintf( __( 'View all posts by %s', 'twentyeleven' ), get_the_author() ) ),
get_the_author()
);
}
endif;

This is basically a copy of the function in twentyeleven but where get_the_modified_time is called instead of get_the_time and get_the_modified_date is called instead of get_the_date.

Now the modified date is used for the posts instead of the publish date. But the posts are still sorted using the default sorting (publish date). In order to fix it, we need to import (i.e. copy) another file from twentyeleven and modify it:

# cp ../twentyeleven/index.php .
# vi index.php

Add this:

<?php query_posts($query_string . '&orderby=modified&order=desc'); ?>

before this line:

<?php if ( have_posts() ) : ?>

Now the posts will also be sorted properly. The only thing you should do now is to change the owner of all the files we’ve created (this will all work without doing it but it does look cleaner):

# chown www-data:www-data *

Now you can go to your WordPress dashboard, Appearances and see you new child theme. In the preview, you will see that the navigation links in the single post view (“Previous” and “Next”) do not look so good in some browser e.g. in Safari, the arrow after “Next” is displayed on a new line. So you might decide to remove this navigation part from this view by deleting these lines in single.php (using vi, you can press “dd” to delete one line, or “5dd” to delete 5 lines from and including the line where the cursor is):

<nav id="nav-single">
<h3 class="assistive-text"><?php _e( 'Post navigation', 'twentyeleven' ); ?></h3>
<span class="nav-previous"><?php previous_post_link( '%link', __( '<span class="meta-nav">&larr;</span> Previous', 'twentyeleven' ) ); ?></span>
<span class="nav-next"><?php next_post_link( '%link', __( 'Next <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?></span>
</nav><!-- #nav-single -->

Now that’s it, if you’ve followed these instructions, you basically have more or less the same theme I’m using on this blog !

WordPress: ALERT – script tried to increase memory_limit to 268435456 bytes which is above the allowed value

Today I found the following in /var/log/user.log:

xxx xx xx:xx:xx xxxxxx suhosin[21100]: ALERT – script tried to increase memory_limit to 268435456 bytes which is above the allowed value (attacker ‘xxx.xxx.xxx.xxx’, file ‘/var/www/vhosts/xxxxxx/httpdocs/wp-admin/admin.php’, line 109)

Line 109 in admin.php contains the following:

@ini_set( ‘memory_limit’, apply_filters( ‘admin_memory_limit’, WP_MAX_MEMORY_LIMIT ) );

I am the “attacker” (it’s my IP address shown in the alert). The error seems to occur regularly when I’m open the Dashboard.

My memory limit in PHP is set to 128MB:

# grep memory_limit /etc/php5/apache2/php.ini
memory_limit = 128M

The memory limit set by WordPress (WP_MAX_MEMORY_LIMIT) is define in wp-includes/default-constants.php:

# grep -R WP_MAX_MEMORY_LIMIT *

wp-includes/default-constants.php: define( ‘WP_MAX_MEMORY_LIMIT’, ‘256M’ );


And it is too high since the limit set in PHP is only half this.

Since default-constants.php, only sets WP_MAX_MEMORY_LIMIT is not set in wp-config.php:

        if ( ! defined( ‘WP_MAX_MEMORY_LIMIT’ ) ) {
                define( ‘WP_MAX_MEMORY_LIMIT’, ‘128M’ );
        }

You can just add the following to your wp-config.php:

define(‘WP_MAX_MEMORY_LIMIT’, ‘128M’);


And now I do not see this error message in user.log when opening the Dashboard.

If you cannot see your Dashboard anymore, it probably means the value you’ve set for WP_MAX_MEMORY_LIMIT is too low (this happened when I first set it to 32M).

Note: Of course you could also increase the PHP limit to 256M instead of 128M. But I didn’t want to do it since we have many things running with PHP and I wanted to use the fix with the least impact on our server.