Chris Hope's LAMP Blog - The Electric ToolboxChris 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.

Copy OS X Yosemite installer to prevent multiple downloadsCopy OS X Yosemite installer to prevent multiple downloads

Posted October 17th, 2014 in OSX

Apple's OS X Yosemite upgrade is available today from the App Store for free, and weighs in at about 5.1GB. After downloading it via the App Store it's possible to make a copy of the installer so you don't need to download it again for each Mac you want to run it on.

Note, do this before installing the update

After downloading the update, the App Store saves the installer to the Applications directory and starts it, as shown in the screenshot below.

Do not click "Continue" until you have copied the installer. The reason? It gets deleted after the update has finished running.

os x yosemite installer

How to copy the installer

When the screen above appears, go and find the installer and copy it before clicking "Continue".

You can navigate to the installer in Finder from the menu selecting "Go" then "Applications" or by using the Cmd+Shift+A Finder shortcut keyboard combo.

Scroll down until you find "Install OS X Yosemite" and then copy it to some other location, such as a USB stick or external hard drive.

Now go back to the installer and click the continue button.

Run the installer on a second, third, fourth, etc... machine

You can now use the same application to install Mac OS X Yosemite on another machine. This afternoon I installed it onto my MacBookPro via the App Store, copied it to an external hard drive and then installed onto my MacMini from the external hard drive.

Is this legal?

Aside from the fact the upgrade is free, a single copy of Yosemite can be installed on each Apple-branded computer that you own or control. So yes, it's legal.

Why bother?

If you have super fast bandwidth and/or low or no data caps then maybe you don't want to bother going to the fuss of copying the installer, but if your bandwidth isn't so fast or you have a low data cap and/or bandwidth is expensive, then you might want to avoid having to download this 5.1GB update more than once.

MySQL queries to get the local part and domain from an email addressMySQL queries to get the local part and domain from an email address

Posted October 16th, 2014 in MySql

This post shows how to extract the local part and domain name from an email address using MySQL. The local part is the part before the @, for example "chris" in chris@example.com.

Get the local part of the email address

Let's assume the email address column is called "email" and is in the "users" table, and that all email addresses in the database are valid with an @ in them.

SELECT SUBSTRING(email, 1, LOCATE('@', email) - 1) AS localpart FROM users;

This gets the first part of the email address up to the @ symbol, so the resulting data for "chris@example.com" would look like this:

+-------------+
| localpart   |
+-------------+
| chris       |
+-------------+
1 row in set (0.00 sec)

Get the domain part of the email address

SELECT SUBSTRING(email, LOCATE('@', email) + 1) AS domain FROM users;

This gets everything after the @ symbol, so the resulting data for "chris@example.com" would look like this:

+-------------+
| domain      |
+-------------+
| example.com |
+-------------+
1 row in set (0.00 sec)

Getting both at the same time

There's no reason why you shouldn't put both into the same query:

SELECT SUBSTRING(email, 1, LOCATE('@', email) - 1) AS localpart,
       SUBSTRING(email, LOCATE('@', email) + 1) AS domain
FROM   users

And the resulting data:

+-----------+-------------+
| localpart | domain      |
+-----------+-------------+
| chris     | example.com |
+-----------+-------------+
1 row in set (0.00 sec)

Debian releases and namesDebian releases and names

Posted October 13th, 2014 in Linux/Unix/BSD (Updated October 14th, 2014)

Debian releases are named after characters from Toy Story and are frequently referred to with the name rather than the version. This post is for my own quick reference for the version-to-name of each Debian release.

Debian version names

I've added the Toy Story character name into each row as well, because sometimes they're not completely obvious. For example, even though I've seen all the movies, it took looking up the name behind "Squeeze" to know it was the alien toys who first appeared in Toy Story 2.

Version Code name Release date Toy Story character
1.1 Buzz 1996-06-17 Buzz Lightyear
1.2 Rex 1996-12-12 Rex (the T-Rex)
1.3 Bo 1997-06-05 Bo Peep
2.0 Hamm 1998-07-24 Hamm (the pig)
2.1 Slink 1999-03-09 Slinky Dog
2.2 Potato 2000-08-15 Mr Potato Head
3.0 Woody 2002-07-19 Woody the cowboy
3.1 Sarge 2005-06-06 Sarge from the Bucket O' Soldiers
4.0 Etch 2007-04-08 Etch, the Etch-A-Sketch
5.0 Lenny 2009-02-14 Lenny, the binoculars
6.0 Squeeze 2011-02-06 Squeeze toy aliens
7 Wheezy 2013-05-04 Wheezy the penguin
8 Jessie not yet released Jessie the cowgirl
  Sid "unstable" The next door neighbour

Debian always has at least three releases in active maintenance: stable (currently Wheezy), testing (currently Jessie) and unstable, which is permanently named Sid after the boy next door in Toy Story 1 who liked to destroy toys.

Updating bash for shellshock on Debian 5 LennyUpdating bash for shellshock on Debian 5 Lenny

Posted September 30th, 2014 in Linux/Unix/BSD

If you are running Debian 5 Lenny and upgrading the distro to Debian 6 or 7 is not an option, you will need to compile bash from source, applying patches in order to secure your server against the bash shellshock vulnerability.

Patching bash on Debian 5 Lenny

Follow the instructions on this page under the "Patching older and unsupported systems" section. The page is kept up to date as new vulnerabilities are found, and shows the tests you need to run.

You will need to continue to monitor the page and apply updates as and when they become available by manually patching and compiling from source each time.

Note that the compiler may stall on "checking for working mktime..." for some time, but it will continue and finish compiling eventually.

An alternative option is to remove bash from your install and use another shell instead, obviously first making sure any shell scripts you have running will continue to function.

Warning: Skipping the data of table mysql.eventWarning: Skipping the data of table mysql.event

Posted September 29th, 2014 in MySql (Updated September 30th, 2014)

The events table was introduced to MySQL in 5.1.6 and when upgrading you will start to see the warning "Warning: Skipping the data of table mysql.event" when using mysqldump. This is not an error as such, but more to make it clear to you that something has changed.

How to include the event table with mysqldump

Use the --events flag when using mysqldump to include the events table:

mysqldump -u[username] -p --events mysql > mysql.sql

This will then suppress the warning message from the output.

How to exclude the event table with mysqldump

Use the --ignore-table flag when using mysqldump to exclude the events table like so:

mysqldump -u[username] -p --ignore-table=mysql.event mysql > mysql.sql

This will then suppress the warning message from the output.

Output when using -T / --tab flag

This is an update the day after originally writing this post. Using the above flags suppresses output when doing a straight SQL dump to file. When using the -T / --tab flag to write the data out to tabbed data files, you will still get this output when dumping events:

--
-- Dumping events for database 'mysql'
--

and this when attempting to ignore the table (which is the original message addressed by this post):

-- Warning: Skipping the data of table mysql.event. Specify the --events option explicitly.

This happens for me on two different servers which run MySQL 5.1.73. If anyone has any suggestions about how to suppress this output, while allowing other errors/warnings to be displayed, it would be greatly appreciated to prevent output from being emailed from automated backup processes.

Signature verification error when running apt-get update on Debian 6Signature verification error when running apt-get update on Debian 6

Posted September 28th, 2014 in Linux/Unix/BSD

When updating a Debian 6 server for the bash shellshock bug, I got a signature verification error message when running apt-get update. This post shows how to fix it; it may also solve the issue for other versions of Debian, but this post was specifically written when updating Debian 6 Squeeze.

Error message

After running "sudo apt-get update" this was the error message:

W: A error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://ftp.nz.debian.org squeeze-updates Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 8B48AD6246925553

W: Failed to fetch http://ftp.nz.debian.org/debian/dists/squeeze-updates/Release  

W: Some index files failed to download, they have been ignored, or old ones used instead.

The fix

Run this to fix it:

sudo apt-get install debian-archive-keyring

Updating bash for shellshock on Debian 6 SqueezeUpdating bash for shellshock on Debian 6 Squeeze

Posted September 28th, 2014 in Linux/Unix/BSD (Updated September 30th, 2014)

An update has been made for the bash shellshock bug on Debian 6 Squeeze but it isn't available unless you update your apt sources to include the LTS repository.

Add the LTS repository

If you haven't already, add this to /etc/apt/sources.list:

deb http://http.debian.net/debian/ squeeze-lts main contrib non-free
deb-src http://http.debian.net/debian/ squeeze-lts main contrib non-free

Then run

sudo apt-get update
sudo apt-get upgrade

Check for vulnerabilities

The current checks I have found to ensure bash is not affected are as follows:

This test this will echo "vulnerable" if vulnerable:

env 'x=() { :;}; echo vulnerable' 'BASH_FUNC_x()=() { :;}; echo vulnerable' bash -c "echo test"

This test will create a file at /tmp/echo and echo the date if vulnerable:

cd /tmp; rm -f /tmp/echo; env 'x=() { (a)=>\' bash -c "echo date"; cat /tmp/echo

This one will output "CVE-2014-7186 vulnerable, redir_stack" and possibly a segmentation fault if vulnerable:

bash -c 'true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF' || echo "CVE-2014-7186 vulnerable, redir_stack"

A gotcha with PHP's PDO::FETCH_CLASSA gotcha with PHP's PDO::FETCH_CLASS

Posted September 26th, 2014 in PHP

PHP's PDO has a nifty way of fetching database records into an object, but there's a slight gotcha when also using a constructor which initializes the class properties.

tl;dr

Data is populated before the constructor is called. To populate data after the constructor use PDO::FETCH_PROPS_LATE i.e.:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'className');

Longer answer

PDO's setFetchMode() allows you to specify the way data is retrieved, e.g. as an associative array, indexed array, etc or into an object.

In the following examples:
- $pdo is a connected PDO database object
- $sql is the query to run, with ? placeholders
- $data is an array of data for those placeholders
- $class is the name of the class to fetch the data into

Run a query using PDO and then fetch the result into an object like this:

$stmt = $pdo->prepare($sql);
$stmt->execute($data);
$stmt->setFetchMode(PDO::FETCH_CLASS, $class);
$object = $stmt->fetch();

This is really useful if you are implementing some sort of data object with a bunch of functions attached to it; the object returned is populated from the database and you can then call those functions.

The gotcha

In the above example, the data is populated into the object first, and then the constructor is called (if there is one). If the constructor does some sort of initialization, then values from the database may be overwritten with the same values every time.

Using the following trivial example, no matter what the value of "id" is in the database, the object will always set it to 1 after the record is loaded:

class foo {
    public $id;
    function __construct()
    {
        $this->id = 1;
    }
}

Again, this is a trivial example which you probably wouldn't do, but it illustrates the point. You might have a data object that sets default values in the constructor, which clobbers the values loaded from the database after they are set into the object.

The solution

This may not be an issue for you, and you may indeed want the constructor to run after the data is populated into the object. But if you don't, simply add PDO::FETCH_PROPS_LATE when calling setFetchMode() and the constructor will be called first:

$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, 'foo');

Done! I hope this was useful :)

Remove extension from a filename with PHPRemove extension from a filename with PHP

Posted September 24th, 2014 in PHP

If you've got a filename that you need to remove the extension from with PHP, there are a number of ways to do it. Here's three ways, with some benchmarking.

Using pathinfo

The pathinfo() function returns an array containing the directory name, basename, extension and filename. Alternatively, you can pass it one of the PATHINFO_ constants and just return that part of the full filename:

$filename = 'filename.html';
$without_extension = pathinfo($filename, PATHINFO_FILENAME);

If the filename contains a full path, then only the filename without the extension is returned.

Using basename

If the extension is known and is the same for the all the filenames, you can pass the second optional parameter to basename() to tell it to strip that extension from the filename:

$filename = 'filename.html';
$without_extension = basename($filename, '.html');

If the filename contains a full path, then only the filename without the extension is returned.

Using substr and strrpos

$filename = 'filename.html';
$without_extension = substr($filename, 0, strrpos($filename, "."));

If the filename contains a full path, then the full path and filename without the extension is returned. You could basename() it as well to get rid of the path if needed (e.g. basename(substr($filename, 0, strrpos($filename, ".")))) although it's slower than using pathinfo.

Benchmarking

Running each of these in a loop 10,000,000 times on my Mac with PHP 5.4:

pathinfo: 10.13 seconds
basename: 7.87 seconds
substr/strrpos: 6.05 seconds
basename(substr/strrpos): 11.98 seconds

If the filename doesn't contain the full path or it doesn't matter if it does, then the substr/strrpos option appears to be the fastest.

If the filename does contain a path and you don't want the path but do know what the extension you want to remove is, then basename appears to be the fastest.

If the filename contains a path, you don't want the path and you don't know what the extension is, then use the pathinfo() option.

Conclusion

There will be plenty of other ways to do this, and some may be faster. In a lot of cases, the speed probably doesn't really matter that much (the 10 seconds to run pathinfo was 10 million times, after all); the purpose of this post was to show a few ways to remove the extension from the filename with PHP.

PhpStorm 8 and the backspace/delete keyPhpStorm 8 and the backspace/delete key

Posted September 22nd, 2014 in Applications and PHP

PhpStorm is an IDE for PHP and version 8 was released a few days ago. The update included a "backspace smart indent" option, which I personally find quite annoying.

What's the problem?

Take some example code like this:

for( ... ) {
    if( ... ) {
    }
}

If the insertion point is just after the closing curly bracket that's part of the if condition, hitting return creates a new line and puts the insertion point in the correct indented place, as it did in the previous versions.

Hitting delete (on a Mac) / backspace (on Windows) then deletes that entire blank line and moves the insertion point back to just after that closing curly bracket. This is the bit I find annoying.

This logically makes sense and I'm sure I can get used to it in time, but it was driving me nuts because I'm so used to the delete key taking me back one indentation point.

The solution

Go to PhpStorm's preferences, and in the IDE Settings section go to Editor -> Smart Keys.

Uncheck "Backspace smart indent" and then click the "OK" button.

Done.

Alrernatively, learn to use it the new way :)