dl

David Lundgren

Web Developer & Systems Administrator

ZfRest — RESTful-ness for Zend Framework 1

For both a client and my work we are working on creating a RESTful API. The problem is that all of the current solutions for Zend Framework are either one off (Resauce, ZfApiVersioning) or otherwise do not play well with a pre-built Zend Framework 1 application. The solution I was looking needed the following

  • handle API versions in the route (I know this isn’t in the spirit of RESTful)
  • handle OAuth
  • Plays well with ZF1 Module architecture (using a Module Bootstrap)

REST modules

In the end most of the solutions out there handle one thing or another but do not address the playing well with ZF1. Resauce deletes the default routes and sets it’s own root url (‘/’), this is not acceptable when you are trying to integrate it with an existing application. ZfApiVersioning suffered the same thing. The only available solution that I found was to write my own REST library for ZF1, so I am introducing ZfRest. It handles the requirements above, and more. The OAuth part is actually loaded as a plugin, requires PECL Oauth, and provides a basic way to handle using Oauth.

OAuth

I also needed an OAuth provider or server. Out of the few solutions I found for ZF1 (link: Zend_Oauth_Provider [incorrect naming], link: Oauth_Server [too complex]), I opted to just use the PECL OAuth module. I quickly ran into a problem where the Exceptions from an internal function were not being passed to my script when you pass in a path such as “/api/users”. Once I figured this out, everything was just working.

$oauthProvider = new OauthProvider();
$oauthProvider->consumerHandler('lookupConsumer');
$oauthProvider->timestampNonceHandler('lookupTimestampNonce');
try {
    $oauthProvider->checkOAuthRequest($uri, $method);
}
catch (Exception $e) {
    // Set HTTP response code to 403
    echo json_encode(array('statusCode' => 403, 'message' => 'Access denied to this resource'));
}

I’ve had several updates to problems I’ve found while using it, but overall I’ve found it works rather well.

MySQL Transactions and Altering Schema

While reviewing the log files for a project I am working on I came across a MySQL error that dealt with mismatched character sets. Specifically the table was set to latin1 and the connection was set to UTF8. This error was rare but happened at the right time for me to catch it, as I was reviewing the log files for an unrelated problem.

Further investigation revealed that the schema and some tables were set to latin1. If we weren’t setting the connection to UTF8 this wouldn’t be a problem. So I set to work on creating a database update to include the alter database and necessary alter table statements.

The first statement among the list of statements that needs to run:

ALTER DATABASE project CHARACTER SET UTF8.

Response from MySQL: Error 1192: “Can’t execute the given command because you have active locked tables or an active transaction”

I was stuck, as this had run fine in the development, QA, and staging environments. Why would it fail in production? The tables didn’t have any locks, and there were no transactions that I was aware of. My Google-Fu led me to the MySQL 5.1 Reference section 13.3.3. Statements That Cause an Implicit Commit. Armed with the knowledge that create, alter, delete table statements cause implicit commits, I was still stuck where I began.

I began reviewing our database update mechanism (based on Zend Framework Database Table Adapters) and found that it was starting a transaction before running the statements. I set forth to update the tool, but some updates needed transactions for their modifications, so I ended up running the query manually.

Sometimes there is no easy answer and you need to just Ops up and get your DBA on.

Redux: PHP5 cronjob in Debian packages

After running into “session could not be started because it was already started with session_start() or session.auto_start” on a project, I realized that removing the cronjob is not the only thing that needs to happen to let PHP manage it’s own sessions.

  • chmod www-data:www-data /var/lib/php5
  • update /etc/php5/apache2/php5.ini and set
    session.gc_probability = 1

I’m assuming that this more paranoid than usual security measure was a way to help inexperienced admins and developers to help prevent session hijacking should the web server be breached. However, if root is gained, it doesn’t matter anyway. I’m not going to say that I am an expert in security for servers, but I can tell you that Debian, and therefore Ubuntu, are the only ones doing this type of paranoid security practice. Coming from the FreeBSD world, you are responsible for the security of your machine, not the developers or port maintainers.

</rant>

Zend Framework 1.11 + PHPUnit 3.6 unit testing

At work we are up to date with PHPUnit  at 3.6, yet officially ZF1 will only support PHPUnit 3.4. Looking through the code there is some support for PHPUnit 3.5, but I actually make use of the additional assertions that PHPUnit 3.6 provides. Initially I had intended on just extending the Zend_Test PHPUnit classes but I quickly ran into the problem where the ZF classes didn’t implement methods in the interfaces when they were brought into the PHP interpreter. I then thought about copying over the Zend_Test classes and renaming them, this would have created a maintenance issue since we don’t want to maintain our own fork of the Zend_Test classes.

My final solution was simply to create my own DatabaseTestCase. This is what I came up with:
Continue reading