“concrete5 cannot parse the PATH_INFO or ORIG_PATH_INFO information provided by your server.”
Thought I’d take a look into concrete5 to see what is was like, and it’s the first open source PHP project installer I’ve come across in ages that complained about anything other than filesystem permissions. PATH_INFO? Most other projects use different mechanisms/variables to do a similar job I assume…
Anyways, go to the concrete5 install directory and create a .htaccess file there with the following contents:
php_flag display_errors off AcceptPathInfo On
If you don’t suppress PHP errors it won’t work, which I read may be related to an Ajax callback failing because the response is full of errors (the installer isn’t written properly? I’ve no idea…)
I’ve also heard that some hosting providers (like GoDaddy) don’t play well with .htaccess files, which unfortunately if that’s the case you’ll have to get in touch with them!
VirtualBox Guest Additions with Shared Folders on Mac OS X
In order to access certain aspects of a virtual machine in VirtualBox, you will need to install Guest Additions (similar to VMWare Tools I guess)
There is a manual page for installing Guest Additions but not all of it is self-explanatory…
Install DKMS
This part is relatively straightforward.
sudo apt-get update sudo apt-get upgrade sudo apt-get install dkms
Where to find VBoxGuestAdditions.iso
Usefully Oracle don’t tell you in their guide, but it is available with the rest of the downloads at http://download.virtualbox.org/virtualbox/
So for example for version 4.1.6 the VBoxGuestAdditions_4.1.6.iso is located at http://download.virtualbox.org/virtualbox/4.1.6/VBoxGuestAdditions_4.1.6.iso
How to mount the image
Since I can’t remember the last time I had to mount something in *nix from the command-line, here’s a quick way.
sudo mkdir /dev/dvd sudo mount /dev/dvd1 /mnt/dvd/ cd /mnt/dvd
Then you should see VBoxLinuxAdditions, which you need to run as per the manual. If the above doesn’t work it might be because your DVD drive in VirtualBox is called something else, like dvd (instead of dvd1) which probably differs depending on which distro you’re using.
Then you need to run the installer.
sudo sh ./VBoxLinuxAdditions.run
Once that’s done you can restart.
sudo reboot now
Kernel header problems
I got some missing kernel header problems when trying to install Guest Additions, which if building the main Guest Additions module fails will be logged.
cat /var/log/vboxadd-install.log
If you see something like this…
Error! Your kernel headers for kernel 2.6.35-28-generic cannot be found at /lib/modules/2.6.35-28-generic/build or /lib/modules/2.6.35-28-generic/source.
You can use the --kernelsourcedir option to tell DKMS where it's located, or you could install the linux-headers-2.6.35-28-generic package.
So you can do just that!
sudo apt-get install linux-headers-2.6.35-28-generic sudo ./VBoxLinuxAdditions.run
Hopefully this should install now (although the XFree86 bit will fail, assuming you’re using the command-line) and you may need to restart the VM, although I’m not sure.
Mount the host folder
You can create the host folder in the VirtualBox Manager in the Shared Folders tab on the Settings for that VM. If you add it on the command-line it’ll appear under the machine folders anyways. If you want to type it though, here’s what you’d type into the Mac OS X terminal (note this is the only thing that you’d type into the host itself)
VBoxManage sharedfolder add "my-ubuntu-vm" \ --name "websites" --hostpath "/Users/andrew/pizza"
To mount the Shared Folder from within the guest, the instructions from Ubuntu (as my guest is Ubuntu, although I think this is a better way to mount it anyways) were very useful.
sharename="whatever.you.want.to.call.it"; sudo mkdir /mnt/$sharename \ sudo chmod 777 /mnt/$sharename \ sudo mount -t vboxsf -o uid=1000,gid=1000 $sharename /mnt/$sharename \ ln -s /mnt/$sharename $HOME/Desktop/$sharename
Just change the target to be wherever you want the Shared Folder to be mounted in the guest. Now in theory if you go to that path in the guest, it should be the same as the directory you shared from the host!
Using PHP late static binding to define static arrays as subsets for child classes
OK, the title might sound a little confusing, but the concept it relatively simple. Basically it’s using an array in a child class that contains some of the items that appear in the array in the parent class.
Which just means you have a list of all of the things in the parent, and a list of some of those things in every child. Like a list of options such as colours, types, etc.
Imagine that you have a class that represents all the cars you sell:
class Cars
To make sure that an enumerated database field matches up when you pick the colour of the car, you use class constants; this is so that when you set you use the same constant, as opposed to typing it in each time (which reduces error, and means you can change it in one place only)
class Car
{
const COLOUR_GREEN = 'green';
const COLOUR_RED = 'red';
const COLOUR_YELLOW = 'yellow';
const COLOUR_BLUE = 'blue';
If you want to find out what colours the cars are available in, you could use an array. Because you can’t declare constant arrays (because they aren’t scalar) you could use a variable; using a static variable will allow you to use it in static methods.
class Car
{
const COLOUR_GREEN = 'green';
const COLOUR_RED = 'red';
const COLOUR_YELLOW = 'yellow';
const COLOUR_BLUE = 'blue';
static array $colours = array(
COLOUR_GREEN,
COLOUR_RED,
COLOUR_YELLOW,
COLOUR_BLUE,
);
}
Then, if you want to make child classes of the cars class, to represent each type of car, you don’t need to redine the constants; all the types of cars can be those colours. However, each type of car might not be available in every colour; the colours are the same but which colours are available are different.
For example if you had trucks that were available in green, red and yellow, and vans that were available in red and blue.
class Truck extends Car
{
static array $colours = array(
COLOUR_GREEN,
COLOUR_RED,
COLOUR_YELLOW,
);
}
class Van extends Car
{
static array $colours = array(
COLOUR_RED,
COLOUR_BLUE,
);
}
This might look all well and dandy, but the problem comes when you check what is in self::$colours in a static method of the child class. Despite the values being different in the child class, it will still contain the values in the class where it was originally declared.
Therefore, if you ran the following method:
static method colours()
{
print_r(self::$colours);
}
You would get the following result in all 3 classes, even if you declared self::colours() in every class.
Array
(
[0] => green
[1] => red
[2] => yellow
[3] => blue
)
To make sure that PHP gets the values from the most recently declared (in the class hierarchy) version of that array, is to use the static keyword.
static method colours()
{
print_r(static::$colours);
}
Using the static keyword, you would only need to write the static colours() in the parent class, as it will still use the static variable in the child class if it is called from the child class, even if the method is declared in the parent class. Calling Car::colours() will tell you all of the colours that are available, Truck::colours() will tell you what colours trucks come in, and likewise with Van::colours()
Note that you do need PHP 5.3 to make this work.
p.s. I wouldn’t actually put colour constants in a car class! It was just the first example that I could think of that wasn’t what I actually used it for at work…
Zend Server lighttp not running (phpMyAdmin) but Apache is? How to start it manually
If for some reason you’ve powered on and while Apache seems to be running OK, lighttp isn’t (for example phpMyAdmin isn’t working on localhost:10081/phpmyadmin) then you will need to start it manually. This is probably caused by a dirty restart, such as a power failure. On Mac OS X run this command…
sudo /usr/local/zend/bin/lighttpdctl.sh start
For Windows, I’m afraid I will have to find that out!
Zend Framework 1.8+ Module/Library Autoloading
Given the problems I had for the 1st Zend Framework website I did, I figured the next time I started one from scratch I would document how to get the autoloading working, since almost nowhere has it documented correctly. I forgot then too, so 3rd time lucky…
The following code assumes the following:
- You have no model, controller or view directories at the root of application/ because they should all be within application/modules/modulename/
- The default module is located at application/modules/default/
- The default module is not namespaced, so the index controller is called IndexController, not Default_IndexController
The key things you need to add, excluding the directory structure that will be created for you by Zend Tool is the following entry in application.ini in application/configs/
resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
Then put the following code in the Application (not any of the Modules) Bootstrap.php in application/
protected function _initAutoloader()
{
$moduleAutoloader =
new Zend_Application_Module_Autoloader(array(
'namespace' => '',
'basePath' => APPLICATION_PATH.'/modules/default'
));
}
Why? No idea, as according to Zend you can do it all from setting the Module Resource in application.ini, although I have never gotten that to work with a variety of different configuration options…
If you need to register a namespace for the library you can add this to Bootstrap.php also
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('MyNamespace_');
Testing and timing RDS/MySQL scheduled downtime with PHP
Something I was asked at work recently was “if we do this to the server, how long will it be unavailable for?” and usually the answer would be easy… however in certain circumstances you may not know. One of these is Amazon RDS, whereby you don’t really know what happens when you reboot or change the configuration of an instance, it just sort-of happens and eventually becomes available again.
For Amazon RDS an example would be when you modify the DB Instance Class of your main instance, which will cause the server to be “modified” which will cause some downtime; of course a reboot will cause downtime also.
Therefore I needed to time how long the website would go down for, at what point connections to the database would fail, or running a query would fail, etc.
I wrote a PHP CLI script to record how long it will take (in seconds) for the database to recover for any given operation that will cause downtime. Start the script, and it will keep outputting ‘+’ to the command line. Start the operation, and eventually the ‘+’ will turn into ‘-’, and once they turn into ‘+’ again it means the downtime is over and the database(s) will be available again, and it will tell you how long it took.
The output will look something like this…
user@server:~$ php test_upgrade.php Starting... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + Database down for 262 seconds
The script is as follows…
<?php
error_reporting(0);
$host = 'myhost.us-east-1.rds.amazonaws.com';
$port = 3306;
$database = 'mydb';
$username = 'user';
$password = 'supersecretpassword';
$sql = "SELECT count(*) FROM users";
echo "Starting...\n";
$disconnectTime = 0;
$reconnectTime = 0;
$reconnected = null;
while ($reconnected !== true) {
$link = mysql_connect($host.':'.$port, $username, $password);
if (! $link) {
flagConnection(false);
$reconnected = false;
continue;
}
$db_selected = mysql_select_db($database, $link);
if (! $db_selected) {
flagConnection(false);
$reconnected = false;
continue;
}
$result = mysql_query($sql);
if (! $result) {
flagConnection(false);
$reconnected = false;
continue;
}
$row = mysql_fetch_row($result);
if (! $row) {
flagConnection(false);
$reconnected = false;
continue;
}
// If everything works, flag as connected
flagConnection(true);
// If was previously disconnected, exit the loop
if ($reconnected === false) {
$reconnected = true;
}
mysql_close($link);
}
$outageTime = $reconnectedTime - $disconnectedTime;
echo "\n\nDatabase down for $outageTime seconds\n";
function flagConnection($flag)
{
global $disconnectedTime;
global $reconnectedTime;
global $reconnected;
echo ($flag ? '+' : '-').' ';
$log[] = $flag;
if ($flag == false && is_null($reconnected)) {
$disconnectedTime = time();
}
if ($flag == true && $reconnected === false) {
$reconnectedTime = time();
}
sleep(1);
}
?>
Google Geocoding API with PHP
If you want to know where a particular address is by latitude and longitude, but only have the normal address details like street, city, zip, country, etc. then the Google Geocoding API should be able to help. By passing it an address string it will try to work out (just like Google Maps) whereabouts the address is, and return you a JSON or XML response with what it managed to figure out.
Below is a basic PHP example using cURL (based on an example from Stack Overflow by Jack W)
<pre>
<?php
function lookup($string){
$string = str_replace (" ", "+", urlencode($string));
$details_url = "http://maps.googleapis.com/maps/api/geocode/json?address=".$string."&sensor=false";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $details_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = json_decode(curl_exec($ch), true);
// If Status Code is ZERO_RESULTS, OVER_QUERY_LIMIT, REQUEST_DENIED or INVALID_REQUEST
if ($response['status'] != 'OK') {
return null;
}
print_r($response);
$geometry = $response['results'][0]['geometry'];
$longitude = $geometry['location']['lng'];
$latitude = $geometry['location']['lat'];
$array = array(
'latitude' => $geometry['location']['lng'],
'longitude' => $geometry['location']['lat'],
'location_type' => $geometry['location_type'],
);
return $array;
}
$city = 'San Francisco, USA';
$array = lookup($city);
print_r($array);
?>
</pre>
Register EC2 Instances to more than one Elastic Load Balancer
For whatever reason, you may need to use more than one Elastic Load Balancer with your cluster of EC2 Instances; using a temporary domain that requires SSL for example (because you can only use one SSL certificate per ELB) where you need to point more than one domain with different SSL certificates to the same pool of web servers.
However, when creating an ELB you’ll notice that you cannot select any EC2 Instances that have been already assigned to another ELB. You can do this via the ELB API tools though.
Elastic Load Balancer API Tools
You need to download these to a computer with Java 1.5 or higher installed. You then need to set an environmental variable for where Java is located, which looks something like below; you can type this into the terminal:
export JAVA_HOME=/usr/lib/jvm/java-6-sun-1.6.0.26/jre/ export AWS_ELB_HOME=/home/ubuntu/ElasticLoadBalancing-1.0.14.3
If it worked, go into the bin directory of the ELB API tools and run:
./elb-cmd
This should list the commands available. Then you need to create a credential file, which you can do by copying the template provided:
cp credential-file-path.template credential-file-path export AWS_CREDENTIAL_FILE=/path/to/credential-file-path
You need to put your super-secret Amazon credentials in here… Afterwards you should be able to do things like list your ELBs:
./elb-describe-lbs --headers
The output should look something like this (if you’ve got 2 load balancers)
LOAD_BALANCER one one.us-east-1.elb.amazonaws.com 2011-09-27... LOAD_BALANCER two two.us-east-1.elb.amazonaws.com 2011-08-20...
If this lists your ELBs then you’re almost there! Then you’ve got to make sure the EC2 API Tools are working with your super-duper-secret credentials. You will need to following bash variables set:
export EC2_KEYPAIR=/where/the/key/is export EC2_PRIVATE_KEY=/where/the/private/key/for/the/certificate/is export EC2_CERT=/where/the/certificate/is export JAVA_HOME=/where/is/the/java/jvm export AWS_CREDENTIAL_FILE=/where/you/put/the/credential-file-path export AWS_ELB_HOME=/where/you/put/the/elb-tools
You can either set these in something like .bash_profile or .bashrc or just execute them in your current bash session. Then, once all that’s working, you can register the EC2 Instances with the load balancer:
./elb-cmd elb-register-instances-with-lb \ load_balancer_name --headers --instances instance_1, instance_2, instance_3
The output of which should look something like:
INSTANCE_ID INSTANCE_ID INSTANCE_ID instance_one INSTANCE_ID instance_two INSTANCE_ID intance_three
You can then end up with more than one ELB pointing to the same pool of web servers, meaning that you can have different domains pointing to each ELB, with their own SSL certificates, pointing to exactly the same code.
Configuring the Elastic Load Balancer
Once the EC2 Instances are registered with the ELB, you will need to assign the Availability Zones for those Instances with the ELB. This is because whilst they would normally be setup in the wizard, because you added them manually it will assign a single default Availability Zone, and you will need to make sure the Zones match your Instances.
Once the Availability Zones are set you will have to wait until the Instances are registered, and then all things being well the ELB should report them as healthy.
Resources I found useful:
Use phpMyAdmin with a remote MySQL server
Been doing relatively proprietary work recently, so not much to share other than this little tip. If you want to use phpMyAdmin but for whatever reason the MySQL server you’re using isn’t local, you can change the host by editing line 104 in config.inc.php in the root of phpMyAdmin:
$cfg['Servers'][$i]['host'] = 'localhost';
… and optionally the port if required
$cfg['Servers'][$i]['port'] = '';
Deleting rows from a MySQL database based on multiple LEFT JOIN with foreign key constraints
Something that I hadn’t attempted to do before, probably because I was trying to delete something from a medium-sized JOIN query that I hadn’t written using a WHERE clause, is realise that unlike deleting with INNER JOIN you cannot delete using a LEFT JOIN where the clause may or may not exist in various target tables in a SELECT query.
(put an example of original query here)
Thus if WHERE y IS NULL is actually null because the join doesn’t match any records in the other table(s) you can’t delete on that clause with a single query (which is better explained on this blog)
The way I figured to do it is create a master list of keys used for the JOIN operation (the keys you’re using for ON or USING) and export it as a comma-delimited list; you can use a sub-query if you’re not deleting from the table where the keys exist as primary. Example: if you’re deleting a list of products which have never been ordered using a cheque, you can’t get the product keys using a sub-query if you’re deleting the products themselves in the same batch query.
(put an example of key query here)
Then, get the list and DELETE FROM each target table using IN and the list of keys you previously generated. This way each table will be deleting from a list of keys that may or may not have matched in the original SELECT query; whether they did match or not doesn’t matter since it’s using IN, it’ll work without a sub-query so you can run it on all tables, and MySQL won’t complain since you’re targeting each table individually one at a time.
(put an example of delete batch query here)
You may need to disable foreign key checking to do this as the queries would be run in succession, not as a single query, so the dependencies would temporarily break.
Categories
- Mum absolutely loves her new brooch by @zeliahorsley from @boticca http://t.co/z37HV5VA
- Building a snowman in this weather is mandatory! http://t.co/WnDHRFpz
- Finished Cycle with @cyclemeter, on a new route, time 1:30:05, 21.60 miles, see http://t.co/0pVeVeYz, average 14.38.
- RT @garrettgillas: Why Google Thinks SPYW is a Good Idea and You Probably Don’t http://t.co/at59JIK6
- It's days like this where I really, really hate commuting... exhausted
Recent Posts
- “concrete5 cannot parse the PATH_INFO or ORIG_PATH_INFO information provided by your server.”
- Enable hibernation on HP MicroServer for Windows Home Server v1
- VirtualBox Guest Additions with Shared Folders on Mac OS X
- Using PHP late static binding to define static arrays as subsets for child classes
- MySQL socket missing at /tmp/mysql.sock with Zend Server CE on Mac OS X




