Confoo 2012 Montreal

My second year speaking at Confoo was more fun than my first. This year I met a lot of new people and had a lot of interesting discussions, particularly in the CMS room and at lunch after my Stackbox CMS presentation. The whole philosophy and approach of Stackbox seemed to have stuck a chord with other people passionate about CMSes and a lot of discussion emerged about different CMS concepts and how to integrate them into the various CMSes around. The whole edit-on-page approach of Stackbox isn’t new, but it’s striking how much simpler it is for the end user than most existing CMSes that are used today – Drupal, Joomla, and WordPress included. I think  all CMSes should strive to enable on-page and in-place editing wherever possible – it really makes a huge difference in usability.

The second talk I gave at Confoo was  Hierarchical MVC (HMVC) – What, Why, and How – an architectural talk I have been wanting to give at several conferences for a little while now (but had until now not been accepted). The talk was very well received, and hopefully helped at least a few people though some of the tougher architectural decisions they might be facing in their own projects. The gist of the talk is that HMVC can help break up code into "widget" type blocks, and can go further down the path of fully separating concerns than more strict traditional MVC can. HMVC is all about code re-use across multiple places, like a comment module that is dispatched to anywhere you display comments across multiple types of content (blog posts, articles, pages, events, etc.). Traditional MVC forces you to use view partials, different layouts, duplicate code, or some other separate widget system to achieve the same level of flexibility you get from HMVC.

One of the best things I like about Confoo is the sheer diversity of the schedule. There were 10 tracks this year, with talks spanning across all types of technologies, markets, and languages, like PHP, Ruby, Python, .NET, Java, and JavaScript to Scaling, Startups, CMSes and Agile. Confoo is the most technologically diverse conference I have had the privilege of speaking at, and I benefit from that diversity every year by expanding my horizons a little bit. While I was there, I attended a talk on a Ruby framework called Renee by Joshua Hull. Even though most of my background is in PHP and I was presenting with PHP examples and projects for my talks, I use Ruby on Rails quite a bit for client work at my company  Brightbit and was working on a Rails API at the time, so I thought I’d check it out. I had been thinking about better REST frameworks beyond MVC for a little while, and the talk inspired me to try the same nested callback style with closures in PHP, and I started hacking together the very first (crude) implementation of Bullet on the plane ride back home the next day, just to see if it was possible. I had the basic concept working well in under an hour thanks to PHP 5.3’s awesome closures. That’s why I like and value the diversity at Confoo so much. You get to see things that are going on in other languages and expand your horizon a bit, then you can bring those benefits back to another language you work in, and benefit even more people. I’ve fleshed out Bullet a little more now and made it a proper project, but the details of that are for another blog post. For now, I leave you with the slide decks I presented at Confoo.

Slide Decks

Stackbox CMS Slides

Hierarchical MVC (HMVC) Slides

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

Excessive Data Usage with iPhone 4S / iOS5

Got a new iPhone 4S or recently upgraded your iPhone 4 or 3GS to IOS5 and noticing unusually high cellular data usage? Are you close to exceeding your data usage limit when you never have before? Have you already exceeded it? You are not alone.

My wife recently traded in her old iPhone 3G for a shiny new iPhone 4S, and within 10 days had exceeded her 200MB AT&T data plan limit when she has never exceeded it before. So what gives? It’s a new phone, and Siri does transmit voice data back to Apple’s servers, but could that really have caused the usage? Continue reading

How to add Photos to the iPhone Simulator

Building an app that needs to access the photo library but don’t have any photos in the iPhone simulator? No problem. Follow these simple steps to import photos into the iPhone Simulator:

  1. Open the iPhone Simulator
  2. Browse to the photo you want to put into the simulator (Finder or web browser)
  3. Click and drag the photo over the simulator window. A green "plus" icon should appear under your cursor with the simulator frame highlighted. Drop the photo.
  4. Mobile Safari should open on the simulator to the location of the image you just dragged and dropped over it
  5. Note that if the image you dropped is linked in a webpage, it will open the link instead of the image URL.
  6. Click the mouse down over the image and hold it until a popup window appears.
  7. Click "Save Image"

The photo will now reside in the "Saved Photos" album on the iPhone Simulator. Rince and repeat as many times as you need to get all your photos in the album.

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.

php|tek 2011

php|tek 2011 Speaker Chicago – May 24-27 php|tek in Chicago was fun as always. It is the best PHP conference I have ever been to, which makes sense, given that it is focused solely on PHP and surrounding technologies. The best thing about the conference is the community feeling in general. You get a real sense that everyone there really cares about PHP and is heavily invested in it, which is good for moving the whole language and ecosystem forward.

I myself gave two talks – one about Stackbox CMS, a new CMS project I have been working on, and one about Apppcelerator Titanium Mobile since I have been working with it a lot lately. The presentations are embedded below.

Continue reading

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.

Android+iPhone SEO App

I just released a new iPhone SEO app and Android SEO app called SEMTab SEO Pro. The basic idea is to keep a list of domains saved, and check SEO/SEM stats like Google PageRank (PR), backlinks, Alexa rank, etc. and Social share information from Twitter, Facebook, and Delicious. more

ss1-listss2-webss3-social1

 

The first two pictures are of the iPhone app, and the last one is of the Android app. SEMTab SEO Pro was built with  Titanium using all native cross-platform UI controls, so it builds both the iPhone and Android app from a single codebase and a single development effort.

The nice thing about SEMTab is that it makes extensive use of Titanium’s event system to fire off simultaneous asynchronous HTTP requests to the various web services and APIs to fetch data about the current domain you are checking. This prevents the application from locking up while fetching rank or share information, and it prevents the HTTP requests from stacking up in a queue and waiting for the ones in front of it to finish. The end result is a pretty slick & simple SEO app that gets the results you want quickly, without feeling sluggish or unresponsive.

Check out SEMTab SEO Pro in the App Store or the Android Market when you get the chance — and don’t forget to leave some feedback with a rating.