Chris Hope's LAMP Blog - The Electric Toolbox
Linux Apache MySQL and PHP articles by Chris Hope
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.
Posted March 31st, 2016 in Linux/Unix/BSD and OSX
Using the "ls" command to list directory contents from the command line with the -l flag will include the date and time down to the minute, but not show the seconds. This post shows how to display the seconds as well with bash on Linux and OSX.
Use one of the following, the second one effectively being a shorter version / synonym of the first one:
ls -l --time-style=full-iso ls --full-time
The output of either of the above will be this:
total 0 -rw-r--r-- 1 chris chris 0 2016-03-31 12:01:10.000000000 +1300 foo.txt
If you don't want the less than a second and timezone offset part, you can format the output yourself, e.g. like this:
ls -l --time-style=+"%Y-%m-%d %H:%M:%S"
The output of this is:
total 0 -rw-r--r-- 1 chris chris 0 2016-03-31 12:01:10 foo.txt
None of the above will work on OSX, but there's a flag available on OSX which isn't on Linux which makes it all a lot easier: -T which you need to use with -l, for example:
And example output:
total 0 -rw-r--r-- 1 chris staff 0 31 Mar 12:01:10 2016 foo.txt
The above examples were using:
Bash 4.2.37 on Debian 7.9 Wheezy
Bash 3.2.57 on OSX 10.10.5 Yosemite
Posted March 10th, 2016 in Linux/Unix/BSD
Top is a useful command line tool for showing processes running on Linux (and other operating systems) such as how much CPU and memory they've been using and how long they've been running, and also showing the system load, CPU and memory usage as a whole. But what if you only one to show output for one process or command?
Use the -p flag to specify the pid
If you know the pid number of the process, use the -p flag to specify it:
top -p [pid]
top -p 1234
Combine with pidof if you don't know the pid
pidof will return the PIDs for the process that matches the input, so you can do this:
top -p `pidof [process name]`
The only problem with this is that if there's more than one process matching the name then it won't work, because you either have to specify each pid with another -p flag or comma separate the values, and you'll get an error like this, when trying to do top for just nginx:
$ top -p `pidof nginx` top: unknown option '1' usage: top -hv | -bcHiSs -d delay -n limit -u|U user | -p pid[,pid] -w [cols]
You can either use pidof's -s flag to return just one pid:
top -p `pidof -s nginx`
which isn't ideal, because you're only get one of them, or combine it with some sed magic to convert spaces between the ids returned from pidof with commas:
top -p `pidof [process name] | sed 's/ /,/g'`
Replace [process name] with the process, e.g. with nginx as shown in the next example:
top -p `pidof nginx | sed 's/ /,/g'`
Combine with pgrep to match a name
Another alternative to combining top with pidof is to use pgrep. This can be useful if you need to match e.g. a PHP script which is running from the command line and which you could only match 'php' when running pidof and might return something different from what you want.
(Note that there is a -x flag for pidof which the man page says "Scripts too - this causes the program to also return process id's of shells running the named scripts" but it didn't seem to work when I tried it myself.)
If the script is called e.g. "myscript.php" you can do this:
top -p `pgrep -f myscript.php`
Again this will cause an error if it returns more than one pid. The output from pgrep will be have each pid on a new line, so we need to use tr to replace the newlines with commas and then sed to remove the final comma. If anyone has a tidier way of doing this, then please let me know in the comments.
top -p `pgrep -f myscript.php | tr '\n' , | sed s/,$//`
top -p `pgrep -f nginx | tr '\n' , | sed s/,$//`
And because pgrep does regular expression pattern matching, you can do all sorts of things with it, but note that there's a limit of 20 pids.
top: pid limit (20) exceeded
Oops, you can't pass any more than 20 pids to top.
You could combine the output of pidof or pgrep with "head -n 20"...
Posted February 29th, 2016 in Linux/Unix/BSD and Offsite Articles
I'm sure you've done it before: added a commit message with git but typed it in wrong and need to change it. If you haven't pushed the commit yet then it's as simple as 'git commit --amend -m "New commit message"'.
If you haven't yet pushed the commit, use this to edit it in a text editor:
git commit --amend
Use this to do the whole thing from the command line:
git commit --amend -m "New commit message"
The full answer / more answers
I need a quick reference link to a comprehensive answer myself, hence this quick post. Several useful answers and examples covering a variety of situations is here at Stack Overflow.
Posted February 25th, 2016 in Sendy
Sendy is a self-hosted email marketing tool; while hooking up a subscription form, I needed to work out what all the possible responses are to a user subscribing, depending on their current status in the Sendy database.
The version documented here is 2.0.7. The previous version had a bug in it which prevented the 'Already subscribed.' status from being returned as plain text and it would always return a full HTML page. If you are using an older version, you should upgrade.
Example API call using PHP
The following example calls the subscribe API function. Replace /path/to/sendy with the full domain and path to your Sendy install, and obviously the other fields too. The 'boolean' value in the data array is set to a text value of 'true' to return the response as plain text.
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, '/path/to/sendy/subscribe'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, array( 'name' => '<name here>', 'email' => '<email address here>', 'list' => '<list id here>, 'boolean' => 'true' )); $response = curl_exec($ch); curl_close($ch);
Possible responses, when double opt in is enabled
Note, you can also get other error messages such as 'Some fields are missing.' but these reponses assume all fields are completed and the email address is valid.
- User is already active in Sendy: API returns 'Already subscribed.'
- User is not yet in Sendy: an opt in email is sent and the API returns '1'
- User has not yet confirmed the double opt in: another opt in email is sent, and the API returns '1'
- User has previously unsubscribed from Sendy: the opt in email is NOT sent, the user is set back to subscribed, and the API returns '1'
- User has been marked as soft bounced: the opt in email is NOT sent, there is no status change, and the API returns 'Already subscribed.'
- User has been marked as hard bounced: the opt in email is NOT sent, there is no status change, and the API returns 'Already subscribed.'
- User has marked one of your email messages as spam: the opt in email is NOT sent, there is no status change, and the API returns 'Already subscribed.'
Posted February 23rd, 2016 in Applications
Save for Web in Adobe Photoshop CC 2015 was moved on the menus from File -> Save for Web to File -> Export -> Save for Web (Legacy).
Where did it go?
It moved from:
File -> Save for Web
File -> Export -> Save for Web (Legacy)
From the horse's mouth
Here's the official bog notice from Adobe about it: "Save for Web in Photoshop CC 2015".
It notes that "Save for Web will not be removed without replacing its capabilities in a new and improved workflow."
I'm not much of a menu user, and use the somewhat awkward Cmd+Option+Shift+C keyboard shortcut so had never even noticed the change. My wife, on the other hand, uses menus and not keyboard shortcuts, and that extra step through the menu makes the current workflow much more awkward.
Solution 1: use shortcut keys
The first solution to speed things up is to use the shortcut keys. Cmd+Option+Shift+C is the default, but you can always change the shortcuts under Edit -> Keyboard Shortcuts. My own personal preference is to try to avoid changing shortcut keys so that I get used to them in case I need to use someone else's computer for something.
Solution 2: install the "Export Helper" add on
Yep, save yourself navigating through the menus / using an awkward keyboard shortcut by installing an add on... mind you, once you have the panel activated you now have one-click saving.
Go to the Photoshop Export Helper page to install it.
You need to have Creative Cloud file sync on, and it will automatically download it. Restart Photoshop and it will be under Window -> Extensions. When you click it, the panel will appear, but you'll probably need to drag it onto another group of panels otherwise I found it tended to disappear or be hidden or something.
To make sure Creative Cloud's file sync is on, go to Creative Cloud, click the cog, select "Preferences", then "Creative Cloud" then "Files" and the sync function is there. The screenshots below illustrate how to get there on a Mac; sorry, I can't help with Windows.
Posted February 12th, 2016 in Email Servers
Getting the message id
Use "exim -bp" or "mailq" to see what's in the queue to get the message id; you'll need it when you want to view the header or body.
$ exim -bp 1m 321 1aU276-0001cf-DR
In the above example, 1aU276-0001cf-DR is the message id
Viewing the email header with exim
Run "exim -Mvh [message id]" to see the headers ("h" for header), e.g. using the id above:
$ exim -Mvh 1aU276-0001cf-DR
Viewing the email body with exim
Run "exim -Mvb [message id]" to see the headers ("b" for body), e.g. using the id above:
$ exim -Mvb 1aU276-0001cf-DR
Posted February 6th, 2016 in Linux/Unix/BSD
I needed a really cheap standalone virtual server to test some stuff, on the internet and not running behind a VDSL router at my office, and got the cheapest RamNode server for $13.50 for a whole year.
I honestly have no idea if RamNode are any good or not (my own websites are hosted using VPS servers at Linode), but for what I need this is perfect: it's more or less throw away money, and I get a server with a static IP address I can switch on, test some stuff and switch back off again as and when needed.
What am I testing?
I'm testing out the free Let's Encrypt secure certificates. These are domain validated certificates: validation is done by a certificate management agent on the web server, which receives requests from the LE servers to prove you manage the domain. I'll talk more about this in a future post, but suffice to say for the moment that I didn't want to run this on a production server (yet).
Get it here
Their cheapest one has 128MB of RAM, 12GB of storage and 500GB of bandwidth, running OpenVZ - for $15 for a year. You can get a 10% discount using the SSD10 coupon code. You can order it here and/or check out the other plans.
I am not affiliated with RamNode in any way, and the above link is not an affiliate link. I found out about them from the comments in this article at Ars Technica.
Posted February 5th, 2016 in Linux/Unix/BSD
If you need to use nslookup on a Debian server and you're getting an "nslookup: command not found" then use apt-get to install dnsutils.
You'll know if dnsutils & nslookup are not installed if you try a dns lookup and get this error:
$ nslookup www.example.com -bash: nslookup: command not found
Install the dnsutils package to resolve the error and lookup the domain:
$ apt-get install dnsutils
And now it works
$ nslookup www.example.com Server: 188.8.131.52 Address: 184.108.40.206#53 Non-authoritative answer: Name: www.example.com Address: 220.127.116.11
Posted December 17th, 2015 in Linux/Unix/BSD
I have some automated processes that receive updates via email attachments which are base64 encoded. The entire email is backed up into a text file, and very occasionally I need to check what was in an attachment. The command line base64 tool can help with this, either decoding a file or standard input.
Using base64 to decode a file
The -d or --decode flag tells base64 it's decoding data (on a Mac -d is a debugging flag, so it's -D and --decode instead). In the examples below, I've used --decode, but you can use -d or -D instead.
To decode the file at /tmp/encoded.txt do this:
base64 --decode /tmp/encoded.txt
And the decoded file will be written to standard output. If you wanted to write it to a file, you can redirect it like this, where it's written out to /tmp/decoded.txt
base64 --decode /tmp/encoded.txt > /tmp/decoded.txt
Using base64 to decode some text
If you run base64 --decode without a file, you can type text (or copy and paste it), hit return/enter, and then control+d / ctrl+d and it will be decoded.
So, for example, to decode VGhpcyBpcyBiYXNlNjQgZW5jb2RlZAo=, which is "This is base64 encoded" encoded as base64, do this:
base64 --decode VGhpcyBpcyBiYXNlNjQgZW5jb2RlZAo= [ctrl+d]
It will then be written to standard output. Again, you can redirect the output to a file:
base64 --decode > /tmp/decoded.txt VGhpcyBpcyBiYXNlNjQgZW5jb2RlZAo= [ctrl+d]
Using pbpaste on a Mac
If you have the encoded text in your clipboard, you can use pbpaste to pipe it through base64 instead of having to manually paste in the terminal. There are equivalent commands when using X (xclip) but I've never used these myself.
pbpaste | base64 --decode
Posted December 16th, 2015 in Linux/Unix/BSD
If it was nice and intuitive to install Java on Debian (and other Debian based distros such as Ubuntu), I wouldn't need to write this post because it would just be "apt-get install java". But no, I always forget what I need to install, hence this post...
Install openjdk-7-jre or openjdk-7-jre-headless
If you just want to install the runtime so you can run Java applications, install either openjdk-7-jre or openjdk-7-jre-headless. The first one will install a bunch of Gnome stuff if not already installed, so if you are doing this on a server without a GUI then install openjdk-7-jre-headless.
sudo apt-get install openjdk-7-jre
sudo apt-get install openjdk-7-jre-headless
Right, now maybe I'll remember this next time :)
This is correct for (at least) Debian 7 & 8, possibly older versions, probably future versions, and possibly other Debian based distributions.