Using Dokku to Deploy PHP Applications with a “git push” on DigitalOcean

Want a Platform-as-a-Service setup like Heroku on your own $5/month VPS from DigitalOcean? Look no further than Dokku

  • a set of scripts built on Docker and Heroku’s own buildpacks. After this setup, you’re just one git push away from deploying your app to your own server.

Step 1: Create a new Droplet with Dokku

DigitalOcean has a great guide on how to use the DigitalOcean Dokku Application, so there is no sense in repeating the steps here. Follow the steps in that article, and then come back here. There are issues I ran into after the Dokku setup that are important steps not to skip. So be sure to come back here before trying to deploy your PHP application.

Step 2: Setup Swap Space

DigitalOcean boxes don’t come with any disk swap space configured by default, but Dokku uses some when deploying your apps, so you need to configure some using this guide before your first git push or you may run into errors (I sure did). The guide says Ubuntu 12.04, but it works on 13.04 too, so no worries. Do this and then come back. I’ll wait.

Step 3: Deploy Your App

Although the setup is not fully complete, try and deploy your app now to make sure your dokku setup is working properly. You also need to deploy your app now so you will have a container ready for the next steps.

git remote add dokku dokku@yourdomain.com:app_name
git push dokku master

The ouput of the git push will let you know if your deploy was successful or not. If you have a successful deploy, but get a “502 Bad Gateway” response from Nginx, continue with the steps below.

Step 4: Install the user-env-compile Plugin

Install the user-env-compile plugin. This will allow you to set environment variables on your app that are available to be used at build time. This is important for the next step.

Step 5: Use CHH’s PHP Buildpack

Now that you have the user-env-compile plugin installed and have created your app’s initial container, you can set environment variable configuration values on it. To specify what buildpack you want to use, set the BUILDPACK_URL ENV value.

ssh dokku@<yourserver.com> config:set <app_name> BUILDPACK_URL=https://github.com/CHH/heroku-buildpack-php

You should see output like this:

-----> Setting config vars and restarting <app_name> BUILDPACK_URL: https://github.com/CHH/heroku-buildpack-php
-----> Releasing <app_name> ...
-----> Release complete!
-----> Deploying <app_name> ...
-----> Deploy complete!

NOTE: ANY Heroku buildpack will work, so if you want to use another one, you are free to do so, although it is very doubtful you will find a better one for PHP :).

Step 6: Set your Document Root

Now open your composer.json file, and add the extra configuration block to specify your document-root and index-document so the PHP buildpack will know where to serve your files from.

{
     "require": {
         "php": ">=5.4.0",
         "vlucas/bulletphp": "~1.3.x"
     },
     "extra": {
         "heroku": {
             "framework": "slim",
             "document-root": "web",
             "index-document": "index.php"
         }
     }
}

Note: The framework key here is slim. This doesn’t match my framework Bullet, but I have to put this in here because this maps to the nginx config file used. So if I don’t specify this here, the buildpack assumes a standard classic PHP setup and will only execute .php files, and not rewrite all requests to the main index.php file like most frameworks (including Bullet) require, causing nginx to throw lots of “404 error” responses.

The configuration key says heroku, but this works for dokku too – remember Dokku basically uses all the same basic things that Heroku does – buildpacks, git based deploys, putting apps in their own sandboxed containers, etc.

Step 7: Install Other Plugins Your App Needs

Custom Domains

You will want the dokku domains plugin so your app can use domains instead of subdomains or ports.

Then add your domain to your your app using:

ssh dokku@<yourserver.com> domains:set <app_name> yourdomain.com api.yourdomain.com

MySQL / MariaDB

If your app uses MySQL, install the dokku MariaDB plugin (drop-in MySQL Replacement).

Then create a database for your app using:

ssh dokku@<yourserver.com> mariadb:create <app_name>

This will create a DATABASE_URL environment variable that will be available as a DSN string for your app to use to connect to the database via PDO or other ORM that you may want to use. You can access this in PHP via $_SERVER['DATABASE_URL'].

Other Plugins

If you use Redis, Memcached, or anything else, check the Dokku Plugins page and install whatever you need.

Step 8: Re-Deploy Your App

This time when you deploy your app via git push, it will use the custom buildpack you set in Step 4. You should be able to view your app live on your custom port, subdomain, or domain now, and all should be well.

Now sit back, relax, and enjoy your own mini-Heroku at a fraction of the cost!

Valitron: The Simple Validation Library That Doesn’t Suck

Valitron is a simple, minimal and elegant stand-alone PHP validation library with NO dependencies. Valitron uses simple, straightforward validation methods with a focus on readable and concise syntax.

Why Another Validation Library?

Valitron was created out of frustration with other validation libraries that have dependencies on large components from other frameworks unrelated to validation like Illuminate Validation (laravel 4) requiring  Symfony HttpFoundation, pulling in a ton of extra files that aren’t needed for basic validation. It also has purposefully simple syntax used to run all validations in one call instead of individually validating each value by instantiating new classes and validating values one at a time like Respect Validation requires you to do. Valitron also has a focus on being concise – validation rules are just a single line per rule, and can include multiple fields in an array. This is handy, because in most use cases, a single validation rule – like “required” will be applied to many fields, so it doesn’t make sense to start with the field first like Fuel Validation does.

In short, Valitron is everything you’ve been looking for in a validation library but haven’t been able to find until now: simple pragmatic syntax, lightweight code that makes sense, extensibility for custom callbacks and validations, good test coverage, and no dependencies.

Usage Example

Valitron is made to setup all your validation rules on the fields you need, and then run all the validations in one call. This is better than validating the fields one-by-one, because that approach causes a lot of “if” statements and branching logic that doesn’t make the resulting code any better than doing the validations by hand (which obviously sucks).

<?php
$v = new Valitron\Validator($_POST);
// Input array
$v->rule('required', ['name', 'email', 'date_start']);
$v->rule('email', 'email'); // Email uses filter_var
$v->rule('dateAfter', 'date_start', new \DateTime()); // After today
if($v->validate()) {
     echo "Yay! We're all good!";
     print_r($v->data());
} else {
     // Errors
     print_r($v->errors());
}

More usage examples and documentation can be found on the Valitron GitHub Page. Valitron is on Packagist, and can be installed via Composer.

Introducing Bullet: The Functional PHP Micro-Framework

Bullet is a new PHP micro-framework with a unique functional approach to URL routing that allows for more flexibility and requires less verbosity than the more typical full route+callback approach found in other micro-frameworks.

The Problem with Independent Scope

The main problem with most micro-frameworks and even full-stack MVC frameworks that leads to code duplication is that the callback or method executed to perform the action and respond to the URL route lives fully within its own scope. This means that you are forced to repeat a lot of setup code across URL route handlers that load the same resource, authorize it, etc.

Some typical micro-framework code might look like this:

<?php
// View single post
$app->get('/posts/:id', function($id) {
     $post = Post::find($id);
     check_user_acl_for($post);
     // ...
});

// Delete post
$app->delete('/posts/:id', function($id) {
     $post = Post::find($id);
     check_user_acl_for($post);
     $post->delete();
     // ...
});

// Edit post
$app->get('/posts/:id/edit', function($id) {
     $post = Post::find($id);
     check_user_acl_for($post);
     // ...
});

You may be able to move the ACL check to a middleware layer or “before” hook if the framework supports it, but there is always a certain amount of duplicate code you will either never be able to get rid of, or have to jump through hoops to get rid of (like adding more abstraction or re-checking the current URL, etc).

The Benefits of Shared Scope

Bullet uses a unique nested callback style that splits the URL by directory separator and only handles a single part of the URL at a time with it’s own callback. At first blush, this approach might seem like more work, but the key to how Bullet works is that nested closures – by definition – can use variables defined in the scope of their parent. This leads to some pretty powerful and profund capabilities that can only be done using the same nested closure style that Bullet uses.

Continue reading

Handling Exceptions in Gearman Tasks (Even Background Ones)

I recently had some issues with Gearman tasks throwing exceptions and killing the whole Gearman daemon. This made it nearly impossible to trace errors back to their origin, because the logged exception stack trace didn’t provide much useful information, because it just logged where it failed in Gearman – not the actual file and line of code that was doing the work. I dug into the code and started trying things like GearmanClient::setExceptionCallback and running the tasks, but since the tasks were being run with addTaskBackground instead of just addTask, the callbacks were never getting executed, and I still was not able to do anything to handle exceptions for the jobs that were being run (and they were still killing the Gearman daemon). Clearly, I was going to have to get a little more creative.

The only other place to add code that will catch exceptions for all jobs run is in the GearmanWorker::addFunction method. So I looked at the following one-liner for adding named job callbacks:

<?php
$worker->addFunction($name, $task);

And replaced it with a closure that uses a try/catch and then logs any exceptions to Exceptional so we can see the full stack trace and exact point of failure for any job – even background jobs:

<?php
$worker->addFunction($name, function() use($task) {
     try {
         $result = call_user_func_array($task, func_get_args());
     } catch(\Exception $e) {
         $result = GEARMAN_WORK_EXCEPTION;
         echo "Gearman: CAUGHT EXCEPTION: " . $e->getMessage();
         // Send exception to Exceptional so it can be logged with details
         Exceptional::handle_exception($e, FALSE);
     }

     return $result;
});

And it works beautifully. Now all the jobs are run, the Gearman daemon is never killed by a PHP process, and all the exceptions are logged with full granular details that makes it easy to troubleshoot and fix any errors.

Nginx + PHP-FPM Blank Pages with PHAR Packages

Ran into this issue when setting up a new VPS for AutoRidge. This happens when using Nginx and PHP-FPM with PHP 5.3+ and the Suhosin patch when trying to run a PHP script using a PHAR package. From what I can gather, the Suhosin patch basically blocks PHP include/require functions from executing files ending with .phar, which results in a PHP segfault that leaves no trace of any error at all. This is what makes this error so frustratingly difficult to track down – there is no trace left in any logs about what is happening or that any PHP error even occurred at all.

The solution is to open your "suhosin.ini" file to ensure the Suhosin patch is allowing PHP to open and execute PHAR files.

Mine was at:

/etc/php5/conf.d/suhosin.ini

If your suhosin config file is not there and you don’t know where it is, run this:

locate suhosin.ini

Find the config key suhosin.executor.include.whitelist and add "phar" to it.

suhosin.executor.include.whitelist ="phar"

Then restart PHP-FPM and Nginx and you should be good to go!

/etc/init.d/php5-fpm restart /etc/init.d/nginx restart

Easier Titanium XHR and AJAX Requests

One question I see a lot on the Appcelerator Titanium Developer Q&A is how to perform AJAX requests and/or work with APIs, etc. There is a built-in way to do this with the Ti.Network.HTTPClient module that is pretty easy, but it does have a few drawbacks and “gotchas”, like executing the “success” event for ANY returned status code – even 500 errors. Since working with APIs is so common with mobile apps, I made a wrapper function modeled after jQuery’s $.ajax method that I use in all my apps. It shortens the syntax quite a bit and is much more familiar to those who are used to using jQuery.

The usage looks like this:

// Geocode input text location
app.utils.ajax({
     url: 'http://maps.googleapis.com/maps/api/geocode/json?address=' + txtLocation.value +'&region=us&sensor=true',
     method: 'get',
     success: function(xhr) {
         var data = JSON.parse(xhr.responseText);
         Ti.API.info(data);

         if("OK" == data.status) {
             var res = data.results[0];
             if(res) {
                 alert("Location: " + res.geometry.location.lat + ', ' + res.geometry.location.lng);
             }
             // Do something with coordinates
         } else {
             Ti.UI.createAlertDialog({
                 title: 'Geocode Error',
                 message: 'Unable to geocode location input'
             }).show();
         }
     },
     error: function(xhr) {
         Ti.UI.createAlertDialog({
             title: 'Geocode Error',
             message: 'No location matches found. Please try something else.'
         }).show();
     }
});

And the actual code for the utility function:

/**  * Application Utilities and Helper Methods  **/
(function(_app) {
     _app.utils = {};

     // AJAX method that mimmicks jQuery's
     _app.utils.ajax = function(_props) {
          // Merge with default props
         var o = _app.combine({
             method: 'GET',
             url: null,
             data: false,
             contentType: 'application/json',

             // Ti API Options
             async: true,
             autoEncodeUrl: true,

             // Callbacks
             success: null,
             error: null,
             beforeSend: null,
             complete: null
         }, _props);

         Ti.API.info("XHR " + o.method + ": \n'" + o.url + "'...");
         var xhr = Ti.Network.createHTTPClient({
             autoEncodeUrl: o.autoEncodeUrl,
             async: o.async
         });

         // URL
         xhr.open(o.method, o.url);

         // Request header
         xhr.setRequestHeader('Content-Type', o.contentType);

         if(o.beforeSend) {
             o.beforeSend(xhr);
         }

         // Errors
         xhr.setTimeout(10000);
         xhr.onerror = function() {
             Ti.API.info('XHR "onerror" ['+this.status+']: '+this.responseText+'');
             if(null !== o.error) {
                 return o.error(this);
             }
         };

         // Success
         xhr.onload = function() {
             // Log
             Ti.API.info('XHR "onload" ['+this.status+']: '+this.responseText+'');

             // Success = 1xx or 2xx (3xx = redirect)
             if(this.status < 400) {
                 try {
                     if(null !== o.success) {
                         return o.success(this);
                     }
                 } catch(e) {
                     Ti.API.info('XHR success function threw Exception: ' + e + '');
                     return;
                 }

             // Error = 4xx or 5xx
             } else {
                 Ti.API.info('XHR error ['+this.status+']: '+this.responseText+'');
                 if(null !== o.error) {
                     return o.error(this);
                 }
             }
         };

         // Send
         if(o.data) {
             Ti.API.info(o.data);
             xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
             xhr.send(o.data);
         } else {
             xhr.send();
         }

         // Completed
         if(null !== o.complete) {
             return o.complete(this);
         }
     };

     // And it does depend on this code below to combine object properties:

     // Extend an object with the properties from another
     // (thanks Dojo - http://docs.dojocampus.org/dojo/mixin)
     var empty = {};
     function mixin(/*Object*/ target, /*Object*/ source){
         var name, s, i;
         for(name in source){
             s = source[name];
             if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
                 target[name] = s;
             }
         }
         return target; // Object
     };
     _app.mixin = function(/*Object*/ obj, /*Object...*/ props){
         if(!obj){ obj = {}; }
         for(var i=1, l=arguments.length; i<l; i++){
             mixin(obj, arguments[i]);
         }         return obj; // Object
     };

     // Create a new object, combining the properties of the passed objects with the last arguments having
     // priority over the first ones
     _app.combine = function(/*Object*/ obj, /*Object...*/ props) {
         var newObj = {};
         for(var i=0, l=arguments.length; i<l; i++){
             mixin(newObj, arguments[i]);
         }
         return newObj;
     };
})(app);

The particular organization of this utilities file assumes that your app structure follows the organization model shown in the Tweetanium example app (using the ‘app’ namespace within a single window context), but is easy to adapt if you are not.

Count the Number of Object keys/properties in Node.js

When using the excellent formidable library to handle file uploads, I needed to get a count of the number of files unloaded in a multi-part form. Javascript arrays have a .length property that you can use, but objects do not. I instinctively typed:files.length

Which returned undefined. So if there is no length property present, an easy way to count the number of keys or properties of an object in ES5-compliant javascript environments like Node.js is to use the Object prototype directly:

Object.keys(files).length

A little more typing, but it is fast, efficient, and most importantly: already built-in.

Titanium Mobile: How to Display an Image with Pinch-to-Zoom and Panning

There are many things that are not immediately obvious when working with Appcelerator’s Titanium platform. Displaying a large image with support for common gestures like pinch-to-zoom or panning around, for instance. If you are used to the Titanium platform and developing apps with it, you think it would be available in the events you can listen for – something like "twofingertouch" or similar that would have a dictionary of coordinates for each finger that is present on the screen.

is one of the most often posted questions in the Q&A section.

Protected vs Private Scope: Arrogance, Fear, and Handcuffs

The age old private vs protected debate has been re-ignited in the PHP community recently following the decision of Doctrine2 and Symfony2 to make all class methods private until there is a very clear and proven reason to change them to protected or public. The intention is a good one – to ensure they are providing a clear and stable API through intentional and known extension points that they can better test and support. Fabien (the creator of Symfony) points to this benefit in an article of his own explaining the thinking behind the decision. The primary started point of Fabien’s article and the driving thought behind this whole change and philosophy is (emphasis his):

Having a few well defined extension points force the developer to extend your library the right way instead of hacking your code.

The problem is that this kind of thinking is a slippery slope that kills the spirit of programming. It alienates the more pragmatic developers within communities. Telling other developers that you are going to force them to work with your code in some pre-determined "right way" is an incredibly arrogant statement to make. more Instead of letting the codebase grow organically and be modified or extended at will, you handcuff developers and send them a different message. Allow me to re-phrase it using my own words:

I know the right way to use this code and I have thought of all the possible use cases. If you don’t agree, then you have to prove me wrong and wait until I either agree or figure out a better right way for you.

This is the real message developers hear when internal code is private scope or marked with the final keyword – a message that they have arbitrarily limited power and ability to make changes where they need to. But it doesn’t stop there.

When you take the position that all methods should be private unless proven otherwise, you plant a seed of fear in the developers that use your code. Fear that whenever they may have to veer off the beaten path to meet a project requirement they won’t be able to. Fear that they might miss deadlines waiting for the "right way"  to enable the functionality they need. Fear that they might have to modify or hack the actual file or class they need to change the behavior of to achieve the functionality they want within the project deadline because they are not able to extend it.

Using private scope removes the fun from programming and kills the hacking spirit by creating fear through the knowledge that you will not have the ability to make changes anywhere in the codebase you need to when you need to. You are no longer in control of your own code. You were forced to submit to a nanny state mentality by sacrificing your freedoms to modify the code for the promise of future stability and safety. That’s not a fun place to be when you’re on the receiving end, and it’s not a policy I would ever consider enforcing with my own code. I sincerely hope this line of thinking does not proliferate within the PHP community and infect other projects.