PHP, OpenSSL and MySQL

Oh boy, oh boy have I had a hellish few days…

I’ve been trying to get OpenSSL working in PHP 5.2.3 so that I could use file_get_contents() to access secure pages (over https) and it’s been a real pain.

Of course it worked fine on the development environment but when it came to the staging and live environments a nightmare ensued… First trying to compile OpenSSL into PHP resulted in a segmentation fault when we tried to run PHP’s unit test script but after our sysadmin played with it for a bit we managed to get the unit test to run with the following errors:


=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
Bug #16069 (ICONV transliteration failure) [ext/iconv/tests/bug16069.phpt]
iconv stream filter [ext/iconv/tests/iconv_stream_filter.phpt]
openssl_csr_new() tests [ext/openssl/tests/004.phpt]
Bug #28382 (openssl_x509_parse extensions support) [ext/openssl/tests/bug28382.phpt]
Bug #36732 (add support for req_extensions in openss_csr_new and sign) [ext/openssl/tests/bug36732.phpt]
openssl_sign/verify: accept different algos [ext/openssl/tests/bug37820.phpt]
Bug #39217 (Large serial number return -1) [ext/openssl/tests/bug39217.phpt]
=====================================================================

Taking that on the chin we decided to ho ahead with the install and see what happened. It turned out that trying to use file_get_contents() on an https url resulted in this error:


Warning: file_get_contents(): SSL operation failed with code 114. OpenSSL Error messages:
error:00000000:lib(0):func(0):reason(0) in /server/path/httpsTest.php on line 5

Warning: file_get_contents(): Failed to enable crypto in /server/path/httpsTest.php on line 5

Warning: file_get_contents(https://www.securesite.com/data.xml): failed to open stream: Bad file descriptor in /server/path//httpsTest.php on line 5

So what was the solution? To cut a long story short there is a conflict between OpenSSL and the secure socket stuff in MySQL client api versions 5.0.22 (possibly earlier versions too) < 5.0.25. Upgrading to the latest version and then recompiling PHP against it should work a treat!

As I say, I've had a real pain with this - especially as I wasn't expecting the problem to be with MySQL! Hope this helps someone...

Setting MySQL’s connection time out from PHP

It’s easy… just not well documented:


	public static function setGlobalConnectionTimeOut($int) {
		ini_set('mysql.connect_timeout', $int);
	}

Have fun!

Using REST Web Services in PHP

Back in the day (the day being February 2001) all the cool kids were exchanging their data as XML over HTTP in an effort to break free from the hellish world of client side ODBC drivers (Mac OS 9 any one?) and firewalls blocking ports.

This revolution had one downside though: there was no common XML schema for all this data which meant that every implementation was different and every project needed a debate over what schema to use and a rigid spec that had to be adhered to.

Out of this recipe for disaster formal web services like SOAP and XML-RPC were born. With a strict XML schema and a mandatory documentation language, SOAP allowed developers to be completely abstracted from serialising/de-serialising their data and a lot of libraries let SOAP methods transparently map to native methods… which is great!

Then there was a curve ball in the shape of REST. Representational State Transfer is similar to SOAP/XML-RPC, it still exchanges data via http but isn’t necessarily as rigid in it’s implementation… it uses URL GET data to send parameters, the emphasis being placed on a common api for exchanging data between everything from HTML forms, JSON apps and RPC Web Services - it’s very light weight but a bit vague. More can be read here.

Below is an example PHP Class for consuming a simple implementation of a REST web-service, it assumes that the server is expecting a conventional HTTP query string which won’t be compatible with some services and it also doesn’t de-serialise the returned data - that’s up to you!


<?php

class RestServiceClient {

	private $url; //the URL we are pointing at

	private $data = array(); //data we are going to send
	private $response; //where we are going to save the response

	public function __construct($url) {
		$this->url = $url;
	}

	//get the URL we were made with
	public function getUrl() {
		return $this->url;
	}

	//add a variable to send
	public function __set($var, $val) {
		$this->data[$var] = $val;
	}

	//get a previously added variable
	public function __get($var) {
		return $this->data[$var];
	}

	public function excuteRequest() {
		//work ok the URI we are calling
		$uri = $this->url . $this->getQueryString();

		//get the URI trapping errors
		$result = @file_get_contents($uri);

		// Retrieve HTTP status code
		list($httpVersion, $httpStatusCode, $httpMessage) = explode(' ', $http_response_header[0], 3);

		//if we didn't get a '200 OK' then thow an Exception
		if ($httpStatusCode != 200) {
			throw new Exception('HTTP/REST error: ' . $httpMessage, $httpStatusCode);
		} else {
			$this->response = $result;
		}
	}

	public function getResponse() {
		return $this->response;
	}

	//turn our array of variables to send into a query string
	protected function getQueryString() {

		$queryArray = array();

		foreach ($this->data as $var => $val) {
			$queryArray[] = $var . '=' . urlencode($val);
		}

		$queryString = implode('&', $queryArray);

		return '?' . $queryString;
	}
}

?>

Usage:

<?php

$rws = new RestServiceClient('http://api.search.yahoo.com/ImageSearchService/V1/imageSearch');

$rws->query = 'Donnie Darko';
$rws->results = 8;
$rws->appid = 'YahooDemo';

$rws->excuteRequest();
// calls: http://api.search.yahoo.com/ImageSearchService/V1/imageSearch?query=Donnie+Darko&results=8&appid=YahooDemo
var_dump($rws->getResponse());

?>

Command Line PHP and MAMP

For the most part, I love MAMP. Sure, it has some short comings compared to a custom compile to exactly match your Production environment, but for a disposable boiler plate development environment it doesn’t get much better!

But what about using it for more than just web-development? I’m sure most people have used the MySQL server from MAMP separately from the rest of the package, if only with third party database development tools, but today I wanted to use the PHP interpreter by itself to develop some PHP shell scripts… and it was really easy!

Take this simple Perl script:


#!/usr/bin/perl

print "Hello World\\n";

To port this to PHP it is as simple as changing the path to the interpreter and adding some PHP tags:


#!/Applications/MAMP/bin/php5/bin/php
<?php

print "Hello World\\n";

?>

And it’s as simple as that! Of course it is a very good idea to put a symbolic link from MAMP’s PHP interpreter to the location of the interpreter on your Production server and use that in your scripts or you’ll be in for a nasty surprise when you try and run your code live!

Operation: Doggy Be Gone!

I work for a company that is part of a large group of other companies… all of which, at various times, have had corporate web sites independently developed for them by different developers using varying technologies and producing varying qualities of code.

The result of this is Doggy Day. This is a day that happens once a month when we get emailed a digest of all the press releases and copy changes that need to be added to the various different web sites because the required content management systems are either non existent or too buggy to be used by non-developers.

Now, the result of Doggy Day, no matter how well we thought we documented it last time, is always chaos (rampant in an age of mistrust) as: No one ever set up an FTP server up on the MS IIS box, so all changes have to be made over VNC… The press realise is larger than the varchar(4000) limit some muppet put on the MsSQL database… The Cold Fusion box’s been crashed for six months and no one noticed…

Need I go on?

The answer to Doggy Day is something dreamed up by Rob and myself (well mainly Rob actually) and it is called Operation: Doggy Be Gone!:

All the above took less than a day… thanks to the sheer hackibility (sorry I mean flexibility) of PHP, the neatness of Word Press and the always amazing wget! And the best bit is: No more doggy days!

PHP Form Security

I had to look into getting those “Please type this number into the form to prove you’re not a robot…” things today and I found this really cool idea.

When the browser requests the image it really calls a PHP script that puts the text value of the number into the users session before spitting out the image, which I thought was a really neat way of doing things… lets you do the entire thing in two scripts.