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 years to come.

 

Send a file via POST with cURL and PHP

cURL is a great library. It can do just about anything that a normal web browser can do including send a file via a post request.

This makes it really easy to transmit files between computers. In my case, I was looking for an easy way to send images snapped by various webcam systems to a central server with php managing the images.

Here is a simple script to send a file with php/cURL via POST:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
	$target_url = 'http://127.0.0.1/accept.php';
        //This needs to be the full path to the file you want to send.
	$file_name_with_full_path = realpath('./sample.jpeg');
        /* curl will accept an array here too.
         * Many examples I found showed a url-encoded string instead.
         * Take note that the 'key' in the array will be the key that shows up in the
         * $_FILES array of the accept script. and the at sign '@' is required before the
         * file name.
         */
	$post = array('extra_info' => '123456','file_contents'=>'@'.$file_name_with_full_path);
 
        $ch = curl_init();
	curl_setopt($ch, CURLOPT_URL,$target_url);
	curl_setopt($ch, CURLOPT_POST,1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
	$result=curl_exec ($ch);
	curl_close ($ch);
	echo $result;
?>

And here is the corresponding script to accept the file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$uploaddir = realpath('./') . '/';
$uploadfile = $uploaddir . basename($_FILES['file_contents']['name']);
echo '<pre>';
	if (move_uploaded_file($_FILES['file_contents']['tmp_name'], $uploadfile)) {
	    echo "File is valid, and was successfully uploaded.\n";
	} else {
	    echo "Possible file upload attack!\n";
	}
	echo 'Here is some more debugging info:';
	print_r($_FILES);
	echo "\n<hr />\n";
	print_r($_POST);
print "</pr" . "e>\n";
?>

And that's it.
Navigate to the 'send' script and it will transmit the file sample.jpeg to the accept script.

Note that you can include other arguments in the post along with the file. This allows you to authenticate the upload. I'm using pre-shared strings to 'validate' that upload came from my send script.

This works with the command line version of php too.

 

UPDATE Oct. 2014 – 

If you're using PHP 5.5 or better, check out the recently added 'CurlFile' class which makes the whole process a lot easier.

 

References:
http://us3.php.net/manual/en/function.move-uploaded-file.php
http://us3.php.net/manual/en/features.file-upload.post-method.php
http://curl.haxx.se/libcurl/php/examples/multipartpost.html
http://forums.devshed.com/php-development-5/php-curl-send-a-file-533233.html

Quercus and App Engine – Reading from the data store.

Using brian’s scripts a base and google’s jdo documentation, I’ve got a working example of reading from the app engine data store with php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
import phptest.test;
import phptest.PMF;
 
$p = PMF::get();
$pm = $p->getPersistenceManager();
$q = $pm->newQuery("select from phptest.test");
$results = $q->execute();
//Returns a php array of resources. Foreach doesn't seem to work here. This seems to be an issue with Quercus.
$account = count($results);
for($a=0;$a < $account; $a++){
	echo $results[$a]->getId() . " - - " . $results[$a]->getFirstName() . '<br/>';
}
$pm->close();
?>

Its just that easy.

Deletes work the same way too. The JDO persistence manager has a method called ‘deletePersistentAll()’ which will truncate the table. To delete a specific item, select it and call ‘deletePersistent(obj)’ where the obj is your record object. See the comments below.

JDO updates your data automatically. Select the item. Change the data and when you call the persistence managers close method, the changes will be saved.

Need more info: Read the google docs.