CentOS 7 Apache with PHP 7.1 and FCGId

Right, installing PHP 7.1 is simple, just get the Webtatic repo and install it

# rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
# yum install -y mod_php71w php71w-cli php71w-common php71w-gd php71w-mbstring php71w-mcrypt php71w-mysqlnd php71w-xml php71w-opcache

If you want to use FCGId instead of mod_php install and configure FPM and mod_fcgid (make sure you remove mod_php71w from the previous command!)

# yum install -y php71w-fpm mod_fcgid
# chkconfig --levels 235 php-fpm on
# vi /etc/php-fpm.d/www.conf

and change the following

listen =
listen = /tmp/php5-fpm.sock

then we need to create some configuration and a wrapper script:

# vi /etc/httpd/conf.d/fcgid.conf

and add this to the end

<Directory /var/www/html/>
AddHandler fcgid-script .php
FCGIWrapper /etc/httpd/conf.d/wrapper .php
Options ExecCGI Indexes FollowSymLinks MultiViews
AllowOverride None
Require all granted

you can change the webroot directory to where you server your pages from if it’s different. Then create the wrapper:

# vi /etc/httpd/conf.d/wrapper

and add the following

export PHPRC
exec /usr/bin/php-cgi

Nearly there! Final step

# vi /etc/httpd/conf/httpd.conf

and look for the DirectoryIndex variable, then add your php index files

DirectoryIndex index.php index.html index.htm

Then update the permissions and fire it all up

# chmod 777 /etc/httpd/conf.d/wrapper
# systemctl start php-fpm.service
# systemctl restart httpd.service


PHPMailer NTLM (MS Exchange) SMTP authentication

PHPmailer does not work with NTLM authentication and insists on using mhash() which is deprecated – so you need to edit the file in /extras called ntlm_sasl_client.php

Find the code that checks if mhash() is installed and replace the 3 mhashes with hash instead:

|| !function_exists($function = "mhash")
) {
$extensions = array(
"mcrypt_encrypt" => "mcrypt",
"mhash" => "mhash"

Then replace these three lines:

$unicode = $this->ASCIIToUnicode($password);
$md4 = mhash(MHASH_MD4, $unicode);
$padded = $md4 . str_repeat(chr(0), 21 - strlen($md4));

With the following:

$unicode = iconv('UTF-8', 'UTF-16LE', $password);
$padded = pack('H*', hash('md4', $unicode));

And the library now works. When sending you will need to define a couple of extra bits:

$mail->SMTPSecure = 'ntlm';
$mail->Realm = "yourdomain.com";
$mail->Workstation = "WORKSTATION1";

…obviously replacing the domain and workstation name with your own values.

Postfix ban failed logins script

Fail2ban hasn’t been working for me, I still have people running brute force attacks on my Postfix server, so I though I’d rig up something myself.

This consists of a bash script that identifies multiple failures and bans them, run on cron every 10 minutes. It checks for both smtp and pop/imap login failures.

# postfix ban failed login ips
# get all failed ip addresses into files
cat /var/log/maillog | grep "authentication failed" | grep -Eo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" > ~admin/mail_fail_smtp
cat /var/log/maillog | grep "auth failed" | grep -Eo "rip=([0-9]{1,3}[\.]){3}[0-9]{1,3}" > ~admin/mail_fail_imap
find ~admin/mail_fail_imap -type f -exec sed -i 's/rip=//g' {} \;
# only get over 5 fails (change the limit= part to change)
sort ~admin/mail_fail_imap | uniq -cd | awk -v limit=5 '$1 > limit{print $2}' > ~admin/mail_fail_imap_over5
sort ~admin/mail_fail_smtp | uniq -cd | awk -v limit=5 '$1 > limit{print $2}' > ~admin/mail_fail_smtp_over5
# read through files and add IP to hosts.deny if not there already
while read p; do
if grep $p /etc/hosts.deny; then
echo $p " already added"
echo ALL: $p >> /etc/hosts.deny
done < ~admin/mail_fail_smtp_over5
while read p; do
if grep $p /etc/hosts.deny; then
echo $p " already added"
echo ALL: $p >> /etc/hosts.deny
done < ~admin/mail_fail_imap_over5
# clean up
rm -f ~admin/mail_fail_smtp
rm -f ~admin/mail_fail_imap
rm -f ~admin/mail_fail_smtp_over5
rm -f ~admin/mail_fail_imap_over5

Then added to crontab:

*/10 * * * * /home/admin/postfix_ban_ips.sh > /dev/null

And just in case the localhost fails and is unintentionally blocked (this is quicker than filtering it out above):

echo "ALL:" >> /etc/hosts.allow

Convert HTML table to CSV

Just a quick one – I needed a script to convert a table to a csv, so this is what I came up with. See the annotations for notes:

//html table is in variable $report
$report = str_replace(array("\n", "\r"), "", $report); //remove existing line breaks
$report = str_replace('"', '\"', $report); //escape existing quote marks
$csv_lines = explode('</tr>', $report); //explode by end of table row
$csv_report = ''; //define output
  foreach ($csv_lines as $this_line) { //each row
  $csv_cells = explode('</td>', $this_line); //explode by end of table cell
  $csv_newcells = array(); //define new cells
    foreach ($csv_cells as $this_cell) { //each cell
    $this_cell = strip_tags($this_cell); //remove any html tags
    $this_cell = html_entity_decode($this_cell); //remove any html characters
    $this_cell = trim($this_cell); //trim any whitespace
      if (!is_numeric($this_cell)) $this_cell = '"'.$this_cell.'"'; //encapsulate in quotes if it is not a number
    $csv_newcells[] = $this_cell; //add it to the new cell array
    } //foreach cell
  $csv_report .= implode(',', $csv_newcells)."\r\n"; add the new cell line to the output
  } //foreach line
echo $csv_report;

Linode Xen to KVM upgrade breaks quotas

On a Linode Virtualmin CentOS 6 the upgrade from Xen to KVM breaks quotas with the following error:

repquota: Cannot stat() mounted device /dev/root: No such file or directory

The issue is that the symbolic link /dev/root is linking to /dev/xvda which has been replaced by /dev/sda so the symlink just needs to be replaced:

# rm /dev/root
# ln -s /dev/sda /dev/root

Then pop into Virtualmin (Webmin, System, Disk Quotas) and turn the quotas back on.

Fix nss-softokn rpm/yum issue in CentOS 6

The recent update to nss-softokn breaks rpm/yum updates in CentOS 6.

To restore functionality run these commands:

For 64-bit:

# wget http://mirror.centos.org/centos/6/updates/x86_64/Packages/nss-softokn-freebl-3.14.3-19.el6_6.x86_64.rpm
# rpm2cpio nss-softokn-freebl-3.14.3-19.el6_6.x86_64.rpm | cpio -idmv
# cd lib64
# cp libfreeblpriv3.* /lib64
# yum update

For 32-bit:

# wget http://mirror.centos.org/centos/6/updates/i386/Packages/nss-softokn-freebl-3.14.3-19.el6_6.i686.rpm
# rpm2cpio nss-softokn-freebl-3.14.3-19.el6_6.i686.rpm | cpio -idmv
# cd lib
# cp libfreeblpriv3.* /lib
# yum update

Backing up your phone with MyBackup and Dropbox

MyBackup Pro from Rerware can be a very useful app to back up your phone – or transfer data between phones.

I set it up to backup my Android phone on a nightly basis, but more often than not it fails to connect to their server and cannot upload the backup.

I paid for the Pro version and I have 100MB of their online storage, but if I lose my phone and it has failed to backup online then it is suddenly completely pointless as a backup program.

So my solution is to take their servers out of the equation – backup locally and then sync that backup to my Dropbox account. This has the added benefit of allowing me much more space for my backups than 100MB (sorry Rerware, I’d pay more for your storage space if I could actually use it consistently).

The Dropbox app is already installed and linked to my phone, but it doesn’t support syncing. There is an app called Dropsync that does exactly that – the free version is limited to files under 5MB and one synced folder, but that should be enough for most of your needs unless you are backing up app install files and larger videos.

Dropsync is available on Google Play here: https://play.google.com/store/apps/details?id=com.ttxapps.dropsync&hl=en

Install the app – it will use the official Dropbox app info to link up if that’s installed otherwise you will need to log in the first time to link it to your Dropbox.

Just set up a sync with your local folder as: /mnt/sdcard/rerware/MyBackup …and create a new MyBackup folder in your Dropbox to sync into (don’t sync into the same folder as other things or it will start download random files to your phone).

If you have the pro version you may also want to sync the folder DCIM (again into a separate folder) and I sync my WhatsApp folder as well – and exclude the pattern **/Thumbs.db to prevent errors in the logs.

My Dropsync settings: Enable Autosync checked, Autosync interval 12 hours (hopefully it is autosyncing so I don’t want to waste battery), Retry Delay 30 minutes, Instant Upload checked, Battery > 10%, Internet Connection Both WiFi and Mobile, Notifications both turned off.

Then set up your MyBackup backups to save locally and hey presto – local backups that actually work and are synced online!

Cover your Paypal fees

I just thought I’d share a formula I worked out a few years ago when a client asked me to make sure his Paypal website payments were covering the Paypal fees – so that he got the full amount he was asking for.

In the UK, Paypal standard fees are 3.4% plus 20p. So if we invoke the magic of algebra, where x is the total and y is the fee, we start with this:

x = (x+y)-(0.034*(x+y))-0.20

I won’t bother taking you through the workings out, but essentially it ends up like this:

y = (17x+100)/483

So if you take your original total (say £100), multiply it by 17 (£1700), then add 100 (£1800), then divide by 483 – you get the fee: £3.73 (rounded up).

To double-check that: £103.73 (total plus fee) times 0.034 plus 0.20 equals… £3.73 (rounded up) – so Paypal will take £3.73 off your £103.73 leaving you with the original figure.

Add custom fonts to WordPress TinyMCE editor with @font-face

The list of fonts in the WordPress visual editor is quite short. There are plugins available to increase it, but I wanted to add my own custom font to the select dropdown.

There’s no plugin hook for this, so it needs a little lateral thinking. Firstly, generate your webfont @font-face in the normal way – I use http://www.fontsquirrel.com/fontface/generator or http://www.font2web.com

Then add the css to your site stylesheet as normal, e.g.

@font-face {
font-family: 'CustomFont';
src: url('fonts/customfont-webfont.eot');
src: local('CustomFont'),
url('fonts/customfont-webfont.eot?iefix') format('eot'),
url('fonts/customfont-webfont.woff') format('woff'),
url('fonts/customfont-webfont.ttf') format('truetype'),
url('fonts/customfont-webfont.svg#webfontnTz28sxq') format('svg');
font-weight: normal;
font-style: normal;

There is a plugin hook that adds a custom stylesheet (adding the code content_css: "stylesheet.css",), so we can use that to inject our own code by closing the quote marks first without entering a stylesheet (or you can if you want so that you can use the font in the editor) and then adding what we need, so add this into your theme’s functions.php:

function plugin_mce_addfont($mce_css) {
if (! empty($mce_css)) $mce_css .= ',';
$mce_css .= '",theme_advanced_fonts:"Custom Font=CustomFont,arial,helvetica,sans-serif';
return $mce_css;
add_filter('mce_css', 'plugin_mce_addfont');

So the first thing we do is close the double quotes and then leave off the final double quote in our code. This will only give you the one choice of font, however (with a browser backup to Arial etc. in case it doesn’t work).  The full list of fonts you originally had is in the file wp-includes/js/tinymce/themes/advanced/editor-template.js so we need to tack them on the end so that we can use all of them:

function plugin_mce_addfont($mce_css) {
if (! empty($mce_css)) $mce_css .= ',';
$mce_css .= '",theme_advanced_fonts:"Custom Font=CustomFont,arial,helvetica,sans-serif;Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';
return $mce_css;
add_filter('mce_css', 'plugin_mce_addfont');