Chris Hope's LAMP Blog - The Electric Toolbox
Linux Apache MySQL and PHP articles by Chris Hope
This is Chris Hope's blog for Linux, Apache, MySQL and PHP (known as LAMP) and Javascript/jQuery. I started this website several years ago with articles about web programming, Linux and Windows tips and tricks, howtos etc.
The ten most recent articles can be found below in their entirety. Navigating the sections in the right navigation (under Categories) will bring up all the other posts, and you can also use the search box at the top of the page to find what you might be looking for.
Sites built in PHP can find good linux hosting across all the major web hosting providers.
Sending a header using the PHP SOAP client
Posted February 2nd, 2012 in PHP
I've recently been interfacing with a SOAP API on a .NET server and also creating an API in PHP, and both require sending a specific SOAP header for authentication. This post shows how to send a SOAP header using the PHP SOAP client which is built into PHP.
Sending an authentication header with PHP SOAP
In the case of the SOAP server I have been developing, the server requires a header to be sent which contains the API key. The header name is APIKey and the value the key itself. In the example below the namespace used for the API call is "ExampleNamespace".
To initiate the SOAP client and set the header using PHP do the following, where $wsdl is the URL of the WSDL file for the SOAP request:
$client = new SoapClient($wsdl);
$header = new SoapHeader('ExampleNamespace', 'APIKey', $apiKey);
$client->__setSoapHeaders($header);
Now you can make requests to the SOAP server and the header will be sent each time.
PHP $_SERVER variables - CLI via SSH vs cron
Posted January 31st, 2012 in PHP
I have a number of batch processes that run using PHP as the command interpreter, and discovered after making a change to one of them the other day that the variables available to PHP in the $_SERVER superglobal are different depending on whether it's run via an SSH session or cron. This post shows the difference on Debian 6. The values available are probably the same on other distros.
$_SERVER using the CLI via SSH
Using the PHP command line interpeter (CLI) the following was displayed when running print_r($_SERVER), showing which variables are available:
Array
(
[TERM] => xterm-color
[SHELL] => /bin/bash
[SSH_CLIENT] => A.B.C.D 58867 22
[SSH_TTY] => /dev/pts/0
[USER] => chris
[MAIL] => /var/mail/chris
[PATH] => /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
[PWD] => /tmp
[LANG] => en_NZ.UTF-8
[SHLVL] => 1
[HOME] => /home/chris
[LOGNAME] => chris
[SSH_CONNECTION] => A.B.C.D 58867 A.B.C.D 22
[_] => /usr/bin/php
[OLDPWD] => /home/chris
[PHP_SELF] => 1.php
[SCRIPT_NAME] => 1.php
[SCRIPT_FILENAME] => 1.php
[PATH_TRANSLATED] => 1.php
[DOCUMENT_ROOT] =>
[REQUEST_TIME] => 1327976915
[argv] => Array
(
[0] => 1.php
)
[argc] => 1
)
Note that I've substituted the actual IP addresses with A.B.C.D in the example above.
$_SERVER using the CLI via cron
Running a PHP script under cron yields less variables in the $_SERVER array. My example script doing print_r($_SERVER) output this:
Array
(
[HOME] => /home/chris
[LOGNAME] => chris
[PATH] => /usr/bin:/bin
[LANG] => en_NZ.UTF-8
[SHELL] => /bin/sh
[PWD] => /home/chris
[PHP_SELF] => /tmp/1.php
[SCRIPT_NAME] => /tmp/1.php
[SCRIPT_FILENAME] => /tmp/1.php
[PATH_TRANSLATED] => /tmp/1.php
[DOCUMENT_ROOT] =>
[REQUEST_TIME] => 1327976941
[argv] => Array
(
[0] => /tmp/1.php
)
[argc] => 1
)
Reason for posting this
As I mentioned at the start of this post, I run a lot of batch processes via cron using PHP. Sometimes I need to use $_SERVER variables and as I discovered they're not all available under cron, so testing via the command line won't necessarily yield the same response as when using cron.
I've posted this as a quick reference should I need to use $_SERVER variables in the future using cron so I can see what's available. With the issue I was having the other day, it was the [USER] variable being present from the command line using SSH which isn't present when using cron.
"Error opening terminal xterm-color" on Mac OSX Terminal
Posted January 27th, 2012 in Linux/Unix/BSD and OSX
If you are connecting to a remote server from the Mac OS X terminal and get the message "Error opening terminal: xterm-color" when doing certain operations on the remote server, then you either change your terminal's declaration setting or add a TERM declaration to the bash profile on the server at the other end to prevent the error message from happening. There may be other ways to solve it at the server end but this post shows a quick and easy fix.
Other operating systems and apps
This may also affect users on other operating systems using SSH to connect to a remote server, but I use a Mac and that's where I had the issue. If you're using something else then the setting the TERM section at the end of this post should probably help.
Change the terminal emulation declaration
Open up Terminal's preferences and click "Settings" then "Advanced".
This is shown in the screenshot below:

The section highlighted with the red box is where you can set the terminal declaration. Open up the drop down box and change it to xterm and when you log in to the remote server it won't show the error about xterm-color.
Setting TERM on the remote server
You can instead change the TERM declaration on the remote server.
Do this on the command line like so:
TERM=xterm
This will take effect immediately for all future commands executed. When you log out and back in again it will revert to the TERM setting your SSH client application had sent the last time. To make the change permanent add the above line to your .bash_profile or .bashrc on the remote server.
Free inactive memory on Mac with FreeMemory
Posted January 19th, 2012 in OSX
I've posted in the past about using the "purge" command line utility on Mac OSX to free up inactive memory but a recent update appears to have broken the tool from working. An alternative is to use the FreeMemory app from the App Store to do the same thing, but more easily.
Issue with purge
I don't know if this affects many people or just me, because searching for the errors I get when using the purge command only comes up with a few results. Here's the error I get:
[ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPAddressSpace.c:608> Unable to open user client for address space 13583, error 0xe00002bd. [ERROR] <CPDevice.c:4013> Unable to get all available address spaces. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:4252> Unable to update device instances (including replacements) for "osx:Mac OS X 10.6" (0x103357740), error kCPUnknownError. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPDevice.c:3752> Unable to create new counter client. [ERROR] <CPOSX.c:1172> Unable to get user client so as to poke the kernel. Unable to purge disk buffers, error #-2.
It doens't matter if I run the command as myself or using sudo, I get the same error.
FreeMemory app
When I was browsing the App Store for free stuff, I found the FreeMemory app. It adds memory free status text to the notification area of the menu bar which, when clicked, shows usage details (free, inactive, active, wired, used, total) and has an option to free up memory. When clicked, it does just that and then tells you how much memory has been freed. Just what I wanted!
Here's a screenshot:

A note about VMWare Fusion
I use VMWare Fusion and one thing that really annoys me with the most recent version running on Snow Leopard is the operaing system's refusal to release the memory it consumes. I can start up a big virtual machine, shut it down and quite VMWare and the memory remains active.
I'm pretty sure the command line purge tool would free up that "active" memory (that isn't active) but unfortunately FreeMemory doesn't. It's a pain because it can make my system run slowly and the only way to actually free the memory now is to reboot.
Get the FreeMemory app
Either search the App Store for "freememory" or go here for more details.
Running Calendar v4 theme goes live
Posted January 17th, 2012 in Case Studies
One of the websites I own is the New Zealand Running Calendar. I launched the 4th version of its template / theme yesterday and document the changes here with a couple of screenshots from the new version and the previous version, and talk about some of the changes.
Homepage screenshots
The first two screenshots below are of the homepage. All pages that are not in the inline popup effectively look like this with the full header at the top of the page and with advertising in the right side.
The differences between the v3 and v4 theme are to make the navigation more defined and more button / tab like; add social sharing links to the left of the main content area; and move the subscription buttons from above the advertising on the right side to the top right of the header area.
Version 3 Homepage:

Version 4 Homepage:

Popup with event information screenshots
The event page appears in an inline colorbox popup when clicking an event in the calendar lists. This means the user can easily look at an event's information, close the popup and then look at another event in the list without having to go backwards and forwards between pages. (Although see my note below about mobile / touch devices).
This behaviour is the same in both the v3 and v4 templates, but the widh of the popup has been increased slightly to include the social sharing buttons which again are offset to the left of the main content body.
Version 3 inline popup:

Version 4 inline popup:

Header area
The header image has been created in a way that no matter how wide the browser window is it will repeat seamlessly. The same technique was used in both versions of the theme but it was remade for version 4 with more of the runners' bodies shown.
Originally I reduced the height of the header area from 120px to 100px and less of the runners' bodies were showing, but it looked far too cramped at the top of the page so I returned it back to 120px.
The logo originally ran onto multiple lines, but I remade that as well so it would be a single line, allowing the navigation to run the full width of the template.
Navigation
The tabbed navigation is now database driven so I can modify it at any time. The underlying engine will be used to drive both this NZ website and an Australian version of the same website and they won't necessarily always have the same navigation, so it's important I can easily change what's in the nav without having to update hard coded links in a template. This is the same for the footer navigation.
There are no images used in the navigation at all; border-radius and rgba background colours are used for browsers that support them, and CSS3Pie is used for Internet Explorer < 9 which do not.
Social sharing buttons
I've added social sharing icons to the left of the main content area. It's fixed positioned with CSS just under the header area, and uses Javascript to scroll to 5px from the top of the page as the header scrolls off the page.
The icons are positioned with a left margin of -75px and don't affect the layout / centering of the main content. If the browser window is wide enough (it is for 90% of the visitors to the website) they'll see it, if it's not then they won't. For example, using an iPad you won't see the social icons at all.
When the event page appears in an inline Colorbox popup the social icons also show, but again have a margin left of -75px so if the window isn't big enough they won't show.
No colorbox for touch devices
On an iPad in version 3 the popup would fill the whole screen and it wasn't easy to close the window. The site isn't optimized in any way whatsoever for mobile devices but smaller devices will have the same issue, assuming people can be bothered browsing such small content on a small device.
I decided mobile devices shouldn't use colorbox at all to solve this usability issue of not being able to easily close it. The easiest way to do this was to use Modernizer with just touch device detection and not show colorbox for touch enabled devices.
I know this isn't perfect because touch devices can be big (and we'll see more of them in time e.g. Windows 8), but for now it's a good enough way to detect mobile devices as far as I am concerned and I can change it in time. In any case, it doesn't break the site if it doesn't work correctly: event links will simply load as a new page instead of in the inline popup.
Assign additional users in Google Webmaster Central
Posted January 16th, 2012 in Miscellaneous Postings
I needed to assign an additional verfied owner in Google Webmaster Central for a website today and forgot how to do it because it's not in a very obvious place. This post will help me remember next time if I forget again, and hopefully will help some other people too if you have the same problem.
Assign additional verified owners
It's possible for multiple people to take ownership of a domain in Google Webmaster Central by adding an HTML file, meta tag or DNS entry, but you can also assign ownership / verified ownership in the interface if you are already a verified owner.
When you've logged in to webmaster central the home page shows a list of domains you have ownership of. An example of one of the entries in my own account is in the following screenshot:

Click the "Manage Site" control and a menu will appear which is shown in the screenshot above. Select the "Add or remove" owners option to do just that.
It's fairly obvious what to do on the next page as shown in the screenshot below. Click the "Add Owner" button to add a new verified owner, and you can remove one by clicking "Unverify".

Restore the admin toolbar when logged into WordPress
Posted January 12th, 2012 in PHP
I don't use WordPress myself, but one of website partners does for their blog. We recently both upgraded from WordPress 2.7 to 3.3 and changed the layout of the website and either as a result of the upgrade or the theme change, lost the admin toolbar that appears at the top of the page when logged in as as admin.
Restore the admin toolbar when logged into WordPress
This is the toolbar I'm talking about:
After the upgrade and changes to the template, when logged into the admin there was a blank space at the top of the page where the toolbar would normally have been previously.
To fix the problem, locate the footer.php file (it will be at wordpress/wp-content/themes/THEME-NAME/footer.php) and add the following before the closing </body> tag:
<?php wp_footer(); ?>
This should solve the problem, it did for me.
Get message body and attachments using PHP IMAP
Posted January 11th, 2012 in PHP
The last post looked at how to get a message structure using the PHP IMAP functions into an easier to use flat array. This post looks at how to loop through that array to easily get all the message parts and attachments.
PHP code to flatten the IMAP structure
The function in the previous post is called flattenParts. Refer to that post for more details, but to save time if you don't wish to read that post as well here's another copy of the same function:
function flattenParts($messageParts, $flattenedParts = array(), $prefix = '', $index = 1, $fullPrefix = true) {
foreach($messageParts as $part) {
$flattenedParts[$prefix.$index] = $part;
if(isset($part->parts)) {
if($part->type == 2) {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix.$index.'.', 0, false);
}
elseif($fullPrefix) {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix.$index.'.');
}
else {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix);
}
unset($flattenedParts[$prefix.$index]->parts);
}
$index++;
}
return $flattenedParts;
}
Functions for getting the content and filename for a part
The looping function below relies on another couple of functions which get the message or attachment content and the filename when it's an attachment. These are as follows:
function getPart($connection, $messageNumber, $partNumber, $encoding) {
$data = imap_fetchbody($connection, $messageNumber, $partNumber);
switch($encoding) {
case 0: return $data; // 7BIT
case 1: return $data; // 8BIT
case 2: return $data; // BINARY
case 3: return base64_decode($data); // BASE64
case 4: return quoted_printable_decode($data); // QUOTED_PRINTABLE
case 5: return $data; // OTHER
}
}
function getFilenameFromPart($part) {
$filename = '';
if($part->ifdparameters) {
foreach($part->dparameters as $object) {
if(strtolower($object->attribute) == 'filename') {
$filename = $object->value;
}
}
}
if(!$filename && $part->ifparameters) {
foreach($part->parameters as $object) {
if(strtolower($object->attribute) == 'name') {
$filename = $object->value;
}
}
}
return $filename;
}
Looping through the message parts
And finally, here's the code to connect to the IMAP server, download the first message and then loop through it to get the various message parts. Modify this code to suit your own circumstances. You can get the second, third, etc message by changing the $messageNumber variable.
$connection = imap_open($server, $login, $password);
$messageNumber = 1;
$structure = imap_fetchstructure($connection, $messageNumber);
$flattenedParts = flattenParts($structure->parts);
foreach($flattenedParts as $partNumber => $part) {
switch($part->type) {
case 0:
// the HTML or plain text part of the email
$message = getPart($connection, $messageNumber, $partNumber, $part->encoding);
// now do something with the message, e.g. render it
break;
case 1:
// multi-part headers, can ignore
break;
case 2:
// attached message headers, can ignore
break;
case 3: // application
case 4: // audio
case 5: // image
case 6: // video
case 7: // other
$filename = getFilenameFromPart($part);
if($filename) {
// it's an attachment
$attachment = getPart($connection, $messageNumber, $partNumber, $part->encoding);
// now do something with the attachment, e.g. save it somewhere
}
else {
// don't know what it is
}
break;
}
}
Dealing with inline attachments
Images can be attached inline in the HTML and there's a special way they are embedded. As with regular attachments, these are just another "part" in the email. I'll look at how to deal with these tomorrow.
Fetch message parts into a flat array with PHP IMAP
Posted January 10th, 2012 in PHP
The PHP IMAP functions imap_fetchstructure and imap_fetchbody are used to work out the structure of an email and get the message body and attachments, but they can be fiddly to use because the message parts can be nested. This post has a function which effectively flattens the message parts into a new array, indexed by the part number which can be directly passed to imap_fetchbody.
Earlier post for extracting email attachments with PHP IMAP
I've written about extracting attachments from an email with PHP before, but that post didn't do any recursion into the sub parts of the email so it missed attachments, especially from emails sent using Apple's mail program (and therefore probably from iOS devices like iPhones and iPads).
The new functions in this post solve this issue and make it a lot easier to find the content in the email by providing a flatter array structure than that provided by the native imap_fetchstructure function.
Message structure
The structure of an email message is generally something like this, with part numbers:
1 - Multipart/alternative headers
1.1 - Plain text message
1.2 - HTML version of message
2 - Inline attachment, etc
In Apple Mail it's like this instead:
1 - Plain text message
2 - Multipart/alternative headers
2.1 - HTML version of the message
2.2 - Inline attachment, etc
If the message has been forwarded, then it will look like this:
1 - Multipart/alternative headers
1.1 - Plain text message
1.2 - HTML version of message
2 - Message/RFC822
2.0 - Attached message header
2.1 - Plain text message
2.2 - HTML version of message
2.3 - Inline attachment, etc
Apple Mail does it differently again, and it's more complicated. I won't bother showing it here.
Example from imap_fetchstructure from Gmail
The following is the result of doing print_r on a message structure that was sent from one Gmail account to another, with an inline image in the email:
stdClass Object
(
[type] => 1
[encoding] => 0
[ifsubtype] => 1
[subtype] => RELATED
[ifdescription] => 0
[ifid] => 0
[bytes] => 6672
[ifdisposition] => 0
[ifdparameters] => 0
[ifparameters] => 1
[parameters] => Array
(
[0] => stdClass Object
(
[attribute] => BOUNDARY
[value] => 14dae9340fe98f008e04b5e7b187
)
)
[parts] => Array
(
[0] => stdClass Object
(
[type] => 1
[encoding] => 0
[ifsubtype] => 1
[subtype] => ALTERNATIVE
[ifdescription] => 0
[ifid] => 0
[bytes] => 915
[ifdisposition] => 0
[ifdparameters] => 0
[ifparameters] => 1
[parameters] => Array
(
[0] => stdClass Object
(
[attribute] => BOUNDARY
[value] => 14dae9340fe98f008b04b5e7b186
)
)
[parts] => Array
(
[0] => stdClass Object
(
[type] => 0
[encoding] => 0
[ifsubtype] => 1
[subtype] => PLAIN
[ifdescription] => 0
[ifid] => 0
[lines] => 14
[bytes] => 190
[ifdisposition] => 0
[ifdparameters] => 0
[ifparameters] => 1
[parameters] => Array
(
[0] => stdClass Object
(
[attribute] => CHARSET
[value] => ISO-8859-1
)
)
)
[1] => stdClass Object
(
[type] => 0
[encoding] => 0
[ifsubtype] => 1
[subtype] => HTML
[ifdescription] => 0
[ifid] => 0
[lines] => 5
[bytes] => 528
[ifdisposition] => 0
[ifdparameters] => 0
[ifparameters] => 1
[parameters] => Array
(
[0] => stdClass Object
(
[attribute] => CHARSET
[value] => ISO-8859-1
)
)
)
)
)
[1] => stdClass Object
(
[type] => 5
[encoding] => 3
[ifsubtype] => 1
[subtype] => PNG
[ifdescription] => 0
[ifid] => 1
[id] =>
Flattened version of the above email
Using my function provided below, this is a "flattened" version of the above email structure, which as you can see is a lot easier to loop through.
Array
(
[1] => stdClass Object
(
[type] => 1
[encoding] => 0
[ifsubtype] => 1
[subtype] => ALTERNATIVE
[ifdescription] => 0
[ifid] => 0
[bytes] => 915
[ifdisposition] => 0
[ifdparameters] => 0
[ifparameters] => 1
[parameters] => Array
(
[0] => stdClass Object
(
[attribute] => BOUNDARY
[value] => 14dae9340fe98f008b04b5e7b186
)
)
)
[1.1] => stdClass Object
(
[type] => 0
[encoding] => 0
[ifsubtype] => 1
[subtype] => PLAIN
[ifdescription] => 0
[ifid] => 0
[lines] => 14
[bytes] => 190
[ifdisposition] => 0
[ifdparameters] => 0
[ifparameters] => 1
[parameters] => Array
(
[0] => stdClass Object
(
[attribute] => CHARSET
[value] => ISO-8859-1
)
)
)
[1.2] => stdClass Object
(
[type] => 0
[encoding] => 0
[ifsubtype] => 1
[subtype] => HTML
[ifdescription] => 0
[ifid] => 0
[lines] => 5
[bytes] => 528
[ifdisposition] => 0
[ifdparameters] => 0
[ifparameters] => 1
[parameters] => Array
(
[0] => stdClass Object
(
[attribute] => CHARSET
[value] => ISO-8859-1
)
)
)
[2] => stdClass Object
(
[type] => 5
[encoding] => 3
[ifsubtype] => 1
[subtype] => PNG
[ifdescription] => 0
[ifid] => 1
[id] =>
PHP code to flatten the IMAP structure
This is a recursive function which creates an array indexed by the part number (1, 1.1, 1.2 etc) and follows the IMAP RFC rules. I've tested it on both a regular email sent from Gmail and from Apple Mail, and also tested it on a forwarded email in Apple Mail (where the original message was forwarded as an attachment).
function flattenParts($messageParts, $flattenedParts = array(), $prefix = '', $index = 1, $fullPrefix = true) {
foreach($messageParts as $part) {
$flattenedParts[$prefix.$index] = $part;
if(isset($part->parts)) {
if($part->type == 2) {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix.$index.'.', 0, false);
}
elseif($fullPrefix) {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix.$index.'.');
}
else {
$flattenedParts = flattenParts($part->parts, $flattenedParts, $prefix);
}
unset($flattenedParts[$prefix.$index]->parts);
}
$index++;
}
return $flattenedParts;
}
To call the function, first connect to the IMAP server and download the message structure for the message (the 1 in the imap_fetchstructure call below) and then run the function, e.g.:
$connection = imap_open($server, $login, $password); $structure = imap_fetchstructure($connection, 1); $flattenedParts = flattenParts($structure->parts);
Looping through the parts to extract the messages and attachments
The next post shows how to loop through the parts from the flattened array above and work out which ones are the plain text and html message parts and which ones are attachments. The following post will look at how to work out which are inline images rendered in the HTML content.
How to use static variables in a PHP function
Posted January 9th, 2012 in PHP (Updated January 24th, 2012)
There may be times when a static variable is needed in a PHP function; static variables maintain their value between function calls and are tidier than using a global variable because they cannot be modified outside of the function. (If the function is contained within a class, you may be better using a private or protected class variable instead of a static variable inside the function).
PHP code example
The PHP code example below shows a function which uses a static variable. When the function is first called it won't have a value set so it's initialized with the = 0 bit and then incremented on each subsequent call. Note that it doesn't need to be an integer; any type should work just fine.
The echo $index line is to show the example working.
function foo() {
static $index = 0;
$index++;
echo "$index\n";
}
Calling foo() multiple times like so:
foo(); foo(); foo();
would echo this:
1 2 3
