I love Cockpit CMS

I've had a lot of fun playing with Cockpit CMS.
It's a "An API-driven CMS without forcing you to make compromises in how you implement your site."

Its a CMS without a front end. The front end is completely up to you. This tool takes care of all the back-end stuff. It provides a UI for building content types, uploading media, editing media and content, doing site backups and authentication. How the data is displayed is entierly up to you.

Built with a custom microframework called "Lime" which looks alot like slim2 and a storage system called "Mongo lite", it provides everything you need to build small sites that are a joy to work with.

The documentation includes a walk-through on how to build a simple blog.

Working with Bitfields in MySQL

Problem: You are working with an antique data model where someone thought is was a good idea to store true/false data as bits in an integer value.

Bitfields are a kind of composit column which stores many logical values in one physical column as an integer value. It allows you to store many yes/no options in a very small space. When looking at this data you'll see integers but what is really important is the bits that make up that number.

Lets say I want to store event level info in a log table.

CREATE TABLE eventlog(
level INT(11) NOT NULL,
msg varchar(32) NOT NULL
);

bit 1 (0001) = fatal error (int 1)
bit 2 (0010) = warning (int 2)
bit 3 (0100) = error (int  4)
and bit 4 (1000) = user error (int 8)

What if I have both a user error and a warning error? That's int 6.
Or all options? That's int 15.
Or all the level's with a warning logged? That's int 2,3,7 and 15

Querying or filtering on a single bit is hard. It's as difficult to work with as CSV string columns. If this data had been normalized properly, each part would have its own column in the database.

MySQL has a few built in functions for working with bitfield columns:
Check out EXPORT_SET and MAKE_SET

SELECT
msg,
EXPORT_SET(level,1,0,'',4) AS debugBits,
SUBSTRING(EXPORT_SET(level,1,0,'',4),1,1) AS hasFatal,
SUBSTRING(EXPORT_SET(level,1,0,'',4),2,1) AS hasWarning,
SUBSTRING(EXPORT_SET(level,1,0,'',4),3,1) AS hasError,
SUBSTRING(EXPORT_SET(level,1,0,'',4),4,1) AS hasUserError
FROM eventlog;

which results in:

msg debugBits hasFatal hasWarning hasError hasUserError
test1 0000 0 0 0 0
test2 1010 1 0 1 0
test3 0010 0 0 1 0

We're taking the bitfield column, turning the column into strings and pulling the string apart. Notice here that bit 1 is on the far right.
 

What happens if I want to add context to this data. That's what MAKE_SET is for.

SELECT
msg,
MAKE_SET(level,
'fatal',
'warning',
'error',
'userError') AS levelTextCsv
FROM warnings;

which will output your bitfield value as a single CSV column with text for each selected option.

Bitfields aren't ideal. Combining data into a single column is an anti-pattern in SQL. Should you encounter this in the wild, you'll know what to do.

 

Rename a MySQL database

 

Problem: You need to change the name of a mysql database without reloading it.

MySQL used to contain a "RENAME DATABASE" command but it would occasionally hose the database.

RENAME {DATABASE | SCHEMA} db_name TO new_db_name;

This statement was added in MySQL 5.1.7 but was found to be dangerous and was removed in MySQL 5.1.23. … Use of this statement could result in loss of database contents, which is why it was removed. Do not use RENAME DATABASE in earlier versions in which it is present.

So what should you do instead?

If all your tables are physically located on the same disk, you can use "create db" + "rename table" to move tables between databases without reloading them.

-- ensure the char set and collate match the existing database.
SHOW VARIABLES LIKE 'character_set_database';
SHOW VARIABLES LIKE 'collation_database';


CREATE DATABASE `database2` DEFAULT CHARACTER SET = `utf8` DEFAULT COLLATE = `utf8_general_ci`;
RENAME TABLE `database1`.`table1` TO `database2`.`table1`;
RENAME TABLE `database1`.`table2` TO `database2`.`table2`;
RENAME TABLE `database1`.`table3` TO `database2`.`table3`;

Reference: http://dev.mysql.com/doc/refman/5.7/en/rename-table.html
This answer is also posted on stackoverflow.

Make MySQL 5.7+ behave like MySQL 5.6

You've upgraded your environment to MySQL 5.7 and everything is broken.

MySQL 5.7 includes a number of changes to the sql mode which are talked about here: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-changes

The old defaults can be set via the sql_mode property on a per-query basis or server wide via the my.cnf file.

To apply the old defaults:

  • Open your my.cnf (usually found at /etc/mysql/my.cnf )
  • Add a line under [mysqld] section. sql_mode=NO_ZERO_IN_DATE,NO_ZERO_DATE,NO_ENGINE_SUBSTITUTION
  • Close your file and restart mysql.

 

Thanks to Ian and Logan from Austin PHP for this solution.

Working with Legacy PHP

I support a legacy application and have recently begun making modifications to this code base. Creating a dev environment for older php can be a beast. This wouldn't have been possible without vagrant. Here are some tricks I discovered while setting up my php 5.2 dev environment in 2016.

Did someone already do this?

I found https://github.com/tierra/wp-vagrant
In my case, I don't want the entire environment inside vagrant and had trouble with some of the configuration decisions of these boxes.
They were really specific to testing wordpress.

Configure Vagrant

Mine is based on bento/centos-5.11
It was the most popular centos 5.x box at the time.
This image doesn't have apache or php installed by default.

Edit the Vagrantfile and enabled the local networking.
This gives you a consistant ip address each time you start your dev environment.

config.vm.network "private_network", ip: "192.168.33.10"

Increase the memory alloted to vagrant box. Look for this near the end of a "standard" vagrant file.

  config.vm.provider "virtualbox" do |vb|
    # Display the VirtualBox GUI when booting the machine
    vb.gui = false  
    # Customize the amount of memory on the VM:
    vb.memory = "1024"
end

I added a line to start apache after the box finishes starting up. ( This is at the end of a "standard" vagrant file. )
In my setup. The apache config for my virtual host is a part of the applications code repository.
This caused problems because apache was failing to start because vagrant hadn't mounted my shared folder yet.

config.vm.provision "shell", inline: <<-SHELL

      sudo /etc/init.d/httpd start

  SHELL

Installing php 5.2 in 2016

Your options are find rpms or compile from source. I tried the 'compile from source' route and it didn't go so well.
There are a number of libraries that php depends on that have been updated and are no longer compatible.
hense the php52-backports project. I was able to compile but had trouble building an apache module.

It was much easier to find RPMS.
I used iworx-unsupported repo. It was referenced in many spots and was only missing one plugin I needed.

[iworx-unsupported]
name=IWorx Unsupported
baseurl=http://updates.interworx.com/iworx/RPMS/unsupported/php5/cos5x/$basearch/
gpgcheck=0
/etc/yum.repos.d/iworx-unsupported.repo (END) 

It does not have an xdebug module so I had to install that via the pecl repository.
yum install php.x86_64 php-cli php-soap php-devel php-mysql php-pdo php-mcrypt php-mysqli php-pear php-gd php-devel gcc gcc-c++ autoconf automake unzip zip

Can't mount folders in vagrant after yum update

Running yum update will probably break your box's ability to mount shared folders.
To fix; you'll need to rebuild virtualbox's guest additions.

sudo /etc/init.d/vboxadd setup

Installing old xdebug

Version 2.2.7 is the last version which supported php 5.2
If you use pecl to install and build the module, you'll get the latest release which doesn't support php 5.2.
We'll have to compile this module manually.
You will need to install gcc, gcc-c++, autoconf automake php-devel and php-pear.

mkdir /opt/xdebug
cd /opt/xdebug
wget –no-check-certificate https://xdebug.org/files/xdebug-2.2.7.tgz
tar -z -x -f ./xdebug-2.2.7.tgz
cd ./xdebug-2.2.7
phpize
./configure –enable-xdebug
make
make install

My xdebug config looks like this:

[xdebug]
zend_extension="/usr/lib64/php/modules/xdebug.so"
xdebug.remote_enable = 1

; default for vagrant
xdebug.remote_host = 192.168.33.1 

Since we configured a static address earlier, we can now use that address with xdebug.
I was so happy the first time phpStorm started a debug session with this app. Screaming and clapping.

Connecting to local MySQL

I'm used to using my local mysql instance for development. Having it virtual box with all the constrants of virtualbox is awkward.
I wanted to connect my virtual box guest to a mysql server running on the host.
If are ok with mysql running on all your ip addresses, then you can just use the same address you used for xdebug. Edit the /etc/my.cnf to allow connections from 0.0.0.0 and you're set. In my case, mysql only runs on localhost.
We can still connect it to the guest via a ssh proxy.

vagrant ssh — -R 3306:localhost:3306

As long as the command prompt is open, your guest will be able to use the proxy.

I think that covers all the gotchas encountered while trying to configure my dev environment for old php.
PHP 5.2 has been unsupported since Jan. 2011, but a dev environment is the first step to modernizing this app. From a breif test on php 7, I'll have plenty of work to do for year to come.