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.

Where are Vudu To Go downloaded movies stored on my Mac?Where are Vudu To Go downloaded movies stored on my Mac?

Posted April 19th, 2015 in Applications

The Vudu To Go app allows you to download movies you have purchased from Vudu* and stores them on your computer to watch using the app. But where are the files stored?

Location of Vudu To Go files on a Mac

The files are stored at /Users/<username>/Library/Preferences/com.vudu.air.Downloader\Local Store

When browsing for that location in Finder, click the "Go" file menu option and hold down the option key to show the "Library" option.

Then locate "Preferences"

Then "com.vudu.air.Downloader"

The "Local Store"

Under the local store you will find folders named with numbers. The media files are there.

Copying the files to another computer

It is possible to copy them to another computer in the same location. I attempted to copy the entire com.vudu.air.Downloader folder but it kept crashing on the other computer.

So I deleted it and ran the app again, started downloading the movie, shut down the app, copied the movie directory over and it worked fine. You probably don't need to go through the "start download and stop the app" step and can probably just copy the movie directory over, just probably don't mess with the files in the root level of that folder.

Can you control where they are saved?

No, but it might be possible to symlink the directory location to somewhere else, e.g. an external hard drive, but I haven't tried this myself.

Can you download rented movies too?

* I noted at the start that Vudu 2 Go lets you download movies you purchased with Vudu, but possibly it can let you download the ones you've rented to. I'm not sure about this, either way.

Tools for setting up and testing secure certificatesTools for setting up and testing secure certificates

Posted April 18th, 2015 in Linux/Unix/BSD

This is a quick reference page for some tools for configuring web server settings and testing secure certificates.

Mozilla SSL Configuration Generator

This tool provides you with SSL configurations for Apache, Nginx, HAProxy & AWS Elb, depending on the server version and openssl version.

To find out your openssl version, do this:

openssl version

To find out your Apache version, do this (depending on distro it'll be apache2 or httpd, and you may need to prefix it with /usr/sbin):

apache2 -v
httpd -v

To find out your Nginx version, do this (again you might need to prefix with /usr/sbin):

nginx -v

Qualys SSL Labs SSL Server Test

This tool tests your secure certificate and gives it a grade. On a couple of older servers, I was able to improve the grade from an "F" to a "B" simply by using the Mozilla SSL configuration generator above. We should be able to get them to an "A" by fixing the intermediate certificate when we renew.

[Update] I bought a new certificate for a site using RapidSSL, the Mozilla configuration generator and with up to date Nginx & openssl on Debian 7 Wheezy and got an A+ with the testing tool.

Screen: cannot open your terminal '/dev/pts/0'Screen: cannot open your terminal '/dev/pts/0'

Posted April 17th, 2015 in Linux/Unix/BSD

If you are logged in as a user using "su" or "sudo su" and attempt to use screen, you'll get the error message "Cannot open your terminal '/dev/pts/0' - please check". This post shows how to fix this.

Solution 1

Log out of the terminal/SSH session and log back in as the user you want to run screen as instead of using su.

Solution 2

script /dev/null


This worked for me on Debian 7.8 Wheezy.

MySQL: order a string column as an integerMySQL: order a string column as an integer

Posted April 16th, 2015 in MySql

If you order a string column that contains only numeric values with MySQL, it will order them as string values, e.g.: 1, 10, 100, 2, 3, 31, 32, 4, etc. If you want to order them as if they were an integer, cast them in the order by clause.


SELECT * FROM <table> ORDER BY CAST(<column> AS unsigned)


Normally you'd store numeric values in a numeric column in the database, but sometimes this isn't possible. For example, the postmeta table in WordPress has a meta_value column which is a string and in which you might store only numeric values for a particular meta_key field.

When the values are strings, they are sorted as strings, so 1, 2, 3, 4, 10, 31, 32, 100 would be sorted as 1, 10, 100, 2, 3, 31, 32, 4 as shown in the example in the first paragraph.

Casting the value as "unsigned" or "signed" in the sort part of the query will instead sort the value as an integer and give the desired result, assuming all the values are indeed numeric.

Speed impact?

I haven't measure this myself, but there will be an obvious impact in speed, especially if the resultset is large. However, it may be fairly minimal and depending on what you are using this query for, it may not matter.

A couple of WordPress examples

Using WordPress as an example, here's a query on the wp_postmeta table finding records with a meta_key of _ct_text_552c8612842c1, which was created using CustomPress, and then ordering them numerically:

SELECT * FROM wp_postmeta
WHERE pm.meta_key = '_ct_text_552c8612842c1'
ORDER BY CAST(pm.meta_value as unsigned)

In my case, I needed to join this to all posts of type 'forum', and here's another example:

SELECT p.ID, pm.meta_value
FROM wp_posts p
INNER JOIN wp_postmeta pm ON pm.post_id = p.ID
WHERE p.post_type = 'forum'
AND p.post_status = 'publish'
AND pm.meta_key = '_ct_text_552c8612842c1'
AND pm.meta_value != ''
ORDER BY CAST(pm.meta_value as unsigned)

That's all for now, I hope you found this useful!

Cast a Javascript variable as an integerCast a Javascript variable as an integer

Posted March 11th, 2015 in Javascript

If you attempt to add a numeric value to a string in Javascript, you'll end up with a string. If you get what appears to be a numeric value from a select option with Javascript, it's a string. To use a number that is cast as a string in Javascript as a number, first cast it to an integer with parseInt().

Use parseInt() to cast a string as an integer with Javascript

To ensure the value is an integer that you can do addition, subtraction, etc to, do this:

var x = parseInt(y);

If the number may have leading zeroes, pass the radix parameter to ensure the value is cast as base 10, otherwise it may be cast as an octal (or other) value:

var x = parseInt(y, 10);

As an example, if you're reading a value from a select with id "myselect" and need it to be a number, do this:

var ele = document.getElementById('myselect');
var x = parseInt(ele.options[ele.selectedIndex].value);

Change the passphrase for an SSH RSA key fileChange the passphrase for an SSH RSA key file

Posted March 6th, 2015 in Linux/Unix/BSD

Use the ssh-keygen command with the -p flag to change or remove the passphrase for an SSH RSA private key file.

Change or remove the passphrase

Run ssh-keygen with -p only will prompt you for the location of the keyfile (defaulting to ~/.ssh/id_rsa) the old passphrase and the new passphrase:

ssh-keygen -p

You will be prompted for the location of the file, which you can specify or hit <enter> to leave as the default:

Enter file in which the key is (/home/chris/.ssh/id_rsa):

Now enter the old passphrase, the new one and confirm it:

Enter old passphrase:
Enter new passphrase (empty for no passphrase): 
Enter same passphrase again:  Your identification has been saved with the new passphrase.

To remove the existing passphrase, simply hit <enter> at the steps where you enter the new one and then confirm it.

Other command line flags

You can also specify the path to the file when first calling ssh-keygen:

ssh-keygen -p -f /path/to/file

And even supply the old pass phrase and new ones of the command line, although I wouldn't recommend it unless you clear the bash session history afterwards:

ssh-keygen -p -f /path/to/file -P old_passphrase -N new_passphrase

To remove the passphrase without having to hit <enter> twice in the prompts, but have to type in the existing one so it's not visible on the command line:

ssh-keygen -p -N ""

You can of course optionally add the -f flag to this one too.

MySQL error can't open file - errno: 24MySQL error can't open file - errno: 24

Posted March 3rd, 2015 in MySql

After some maintenance was done to the virtual host server that one of my virtual servers was running on that required a host reboot, my websites weren't running due to the MySQL error "[ERROR] /usr/sbin/mysqld: Can't open file: './databasename/tablename.frm' (errno: 24)"


In my case, the issue was due to too many files being open. Increasing the open_files_limit setting and restarting MySQL fixed the issue. It's quite possible this error message will also occur for other reasons (e.g. file corruption), but in my case it was the file limit issue.

Longer answer

After working out it was not an issue with the web server (Nginx) or PHP, I checked the MySQL error log, which was full of messages like this (where "databasename" was the name of the database, and "tablename" was the name of the table):

[ERROR] /usr/sbin/mysqld: Can't open file: './databasename/tablename.frm' (errno: 24)

I was able to log into the MySQL command line and run a query against a database, and got the same sort of error message:

ERROR 1016 (HY000): Can't open file: './databasename/tablename.frm' (errno: 24)

After some Googling around, I found that the issue might be due to the open files limit setting not being high enough. You can check what the current setting is with this query, and result:

mysql> SHOW VARIABLES LIKE 'open_files_limit';
| Variable_name    | Value |
| open_files_limit | 1024  |
1 row in set (0.00 sec)

And then see how many files are currently open:

mysql> SHOW GLOBAL STATUS LIKE 'Open_files';
| Variable_name | Value |
| Open_files    | 712   |
1 row in set (0.01 sec)

Judging from the above result, I did actually have a high enough open files limit, but it was worth attempting to change the setting to see if it fixed the problem, seeing as the number of open files wasn't too far off the limit. I also found myself unable to subsequently open up a MySQL command prompt again.

Increasing the open_files_limit setting

The open_files_limit setting cannot be changed from the MySQL command line; it needs to be done in the configuration file and then MySQL restarted. Add the following line to the your my.cnf file:

open_files_limit = <your limit here>

Then restart MySQL.

In my case, it wouldn't shut down so after about 30 minutes I rebooted the server (it was reporting issues with open files again). When it came back up, the problem was gone, so increasing the open files limit solved my problem.

This is the error message in the log file when I was attempting to shut down MySQL, which confirms it was an issue with the file limit:

[ERROR] Error in accept: Too many open files

Grepping the error log now, I can see this particular message came up a number of times in the three hours the issue occurred for.

You can't set the open_files_limit dynamically

Note that you can't set open_files_limit dynamically from the MySQL command line; you have to change it in the configuration and restart.

If you run this:

mysql> SET GLOBAL open_files_limit = <your limit here>;

You will get this error message:

ERROR 1238 (HY000): Variable 'open_files_limit' is a read only variable

Add Feedly to Google Chrome's RSS Subscription ExtensionAdd Feedly to Google Chrome's RSS Subscription Extension

Posted February 21st, 2015 in Applications

If you have the RSS Subscription Extension (by Google) installed in Google Chrome, you can add additional services to the "subscribe to this feed using" drop down box. This post shows how to do this for Feedly.

Open up Chrome's preferences

Go to Chrome -> Preferences on a Mac, or hamburger/menu button -> Settings on Mac and other operating systems and click on the extensions option. Alternatively just type "chrome://extensions/" into the omnibar.

Chrome's menu, with settings option highlighted:

chrome's menu

Extensions option highlighted: 

select extensions

Adding Feedly as an option

Now scroll down your installed extensions until you find the RSS Subscription Extension (by Google) and click the "options" option:

find the rss extension

You'll see the ones that are installed, you can edit and remove existing ones and add a new one by clicking the "add" button, which is highlighted in the following screenshot:

adding a new subscription option

Now finally enter the description and URL:

adding feedly

You can make the description whatever you want it to be (but calling it "Feedly" makes sense), and put as the URL.

Now when clicking the RSS button in the omnibar, you'll be able to add it to Feedly. If you tick the "always use my default reader when subscribing to feeds" option, then whenever you click the RSS button you'll go straight into Feedly.

How to tell if Debian install is vulnerable to the GHOST exploitHow to tell if Debian install is vulnerable to the GHOST exploit

Posted January 29th, 2015 in Linux/Unix/BSD

The CVE-2015-0235 "GHOST" exploit exposes a buffer overflow in glibc gethostbyname. This post shows how you can tell if your Debian Squeeze or Lenny install is affected and how to patch it.

The CVE-2015-0235 exploit

Track the exploit and updates to Debian here at the Debian security tracker.

Squeeze / Debian 6 & Wheezy / Debian 7 are affected until updates are applied. There are security updates in place already, so you just need to update/upgrade your distro.

When eglibc is at version 2.11.3-4+deb6u4 or higher on Squeeze or 2.11.13-38+deb7u7 or higher on Wheezy, then you are OK and the exploit is patched. Note that you are looking for the "deb6u4" and "deb7u7" part. So the next version for Squeeze would be deb6u5, deb6u6 and so on.

How can I tell if my server is affected?

Run this from the command line:

ldd --version

Look at the first line for the eglibc version; the following example is from an unpatched Debian Squeeze server:

ldd (Debian EGLIBC 2.11.3-4+deb6u1) 2.11.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
Written by Roland McGrath and Ulrich Drepper.

Note that the version is 2.11.3-4+deb6u1, so it's affected.

How to update

Of course you'll regularly update your Debian servers so know how to do this already ;)

apt-get update
apt-get upgrade

You'll need to reboot your server after doing the updates, because of the reliance various services and applications have on glibc / eglibc.

What about Debian Lenny?

There do not appear to be any plans to patch Lenny, so you're out of luck for an easy update. There's some instructions here at serverfault about how to do a source patch to do it yourself.

Delete messages from the exim mail queueDelete messages from the exim mail queue

Posted November 12th, 2014 in Email Servers

This post shows how to delete a single message from the exim mail queue and also how to remove all of them using the exim command line tools.

Delete a single message from the exim mail queue

Use mailq / exim -bp to show the mail queue, e.g.:

$ mailq
 0m   528 1XoIxD-0001rc-8J 

And then run exim -Mrm [message id] to delete the specific message:

exim -Mrm 1XoIxD-0001rc-8J

If the message is successfully deleted, you'll see this:

Message 1XoIxD-0001rc-8J has been removed

If exim is currently processing the message, you'll see this and it won't be deleted:

Message 1XoIxD-0001rc-8J is locked

You either need to wait and try again later, or get the id of the process which is currently processing the message, kill it, and then run the command again (e.g. "ps ax 1XoIxD-0001rc-8J" and then "kill -9 [process id/s]). It's probably not recommended that you kill the process.

Delete all messages in the exim mail queue

Running "exiqgrep -i" returns all the message ids for queued emails; pipe that through "exim -Mrm" and all the messages will be deleted, with the same caveat as above: if exim is currently processing a message, that one will not be deleted so you need to try again later.

exiqgrep -i | xargs exim -Mrm

And the result, if one could be removed and another one couldn't:

Message 1XoJ1U-0001sC-ME has been removed
Message 1XoJ1i-0001sQ-UJ is locked