The New Myth family: SprintPHP Bonfire Practical CodeIgniter 3

New Myth Media Blog

Serving the New Myth Media Family.

Practical CodeIgniter 3 Released

My new book about making the most of CodeIgniter 3 is out!

Posts Filed Under “Codeigniter”

One of the biggest changes, conceptually, in CodeIgniter 4 is the way that Input and Output is handled. In prior versions, including the latest v3 releases, Input and Output were handled as two classes that contained mostly related functionality. There wasn't any "grand scheme" behind it, but it still worked pretty nicely. In v4, though, we've modeled the HTTP layer much more closely, building a new hierarchy of classes to represent the common HTTP requests and responses.

At A Glance

When working with web applications - as opposed to CLI-only services - you'll really just need to worry about two classes: IncomingRequest and Response.

IncomingRequest

The IncomingRequest class provides access to the HTTP request and all of the side data that comes with it, including:

  • GET, POST, SERVER, and ENV variables
  • Headers
  • Cookies
  • the URL object that is currently being looked at
  • uploaded files

and provides convenience methods for things like:

  • client IP Address
  • is it an AJAX request?
  • is it a CLI request?
  • is it over HTTPS?

If you're wondering about the difference in naming, and, "Shouldn't IncomingRequest be simply Request?" the answer is nope. There already is another Request class that is more generic and doesn't know the details of an HTTP request, which contains all of the fun stuff like GET and POST vars. A Request can be one of two things: either the request that a client browser has made to the server (incoming); or a request that you are sending out to an external server, (outgoing).

Response

The response class is what you work with to build your response to the client. You can assign headers, set the output directly, and more. It provides convenience methods for things like:

  • setting appropriate no-cache headers
  • working with HTTP cache headers
  • redirecting to a new page

A Quick Example

This may sound like it's going to be pretty technical to work with, but it's really not. The controller already has an instance of the classes as properties, but for simple work, you'll never even need to use them. Any output from the controller is captured and automatically set as the body of the Response. A Hello World example might look like this:

class Home extends \CodeIgniter\Controller
{
    public function index()
    {
        echo "Hello World!";
    }
}

Easy, peasy.

What this does do, though, is provide you the ability to really dig in and fine-tune the response if you need to. You can create with complex HTTP caching strategies, work with the IncomingRequest to tailor your response through Content Negotiation, and much more.

Here's a slightly more involved example, though you'll see it's all easily readable, and simple to work with.

class Home extends \CodeIgniter\Controller
{
    public function __construct(...$params)
    {
        parent::__construct(...$params);

        // This controller is only accessible via HTTPS
        if (! $this->request->isSecure())
        {
            // Redirect the user to this page via HTTPS, and set the Strict-Transport-Security
            // header so the browser will automatically convert all links to this page to HTTPS
            // for the next year.
            force_https();
        }
    }

    public function index()
    {
        $data = [
            ...
        ];

        // Set some HTTP cache rules for this page.
        $this->response->setCache([
            'max-age' => 300,
            's-max-age' => 900,
            'etag' => 'foo'
        ]);

        // Return JSON
        $this->response->setContentType('application/json')
                       ->setOutput(json_encode($data));
    }
}

In this example, we've done three primary things. First, we forced this page to be accessed via HTTPS by both a redirect to the HTTPS version of the current URL, and by setting a Strict-Transport-Security header, which is supported by most of the major browser vendors and lets the browser convert the URL to HTTPS automatically before ever sending the request. Second, we're setting some HTTP cache rules to help the browser know when it can reuse data it already has and when it can't, which means fewer HTTP requests, never hitting the server, and increasing performance to boot. Finally, we're outputting some JSON data to the user, ensuring that the correct content type is set.

Hopefully, this helps to get a glimpse at the future of CodeIgniter, and realize that change doesn't always have to be scary :) More articles will come in the future talking about the concepts of the framework as more and more parts are pinned down to a fairly stable place.

As the year comes to a close, it’s time to look back at the work that’s been done so far on the rewrite for CodeIgniter. Much of the work needed to get the core into a place where it’s more in the public eye has been done. That doesn’t mean that things won’t change, but it’s getting closer and more finalized every day.

So, what can you expect?

It’s Simple

Simplicity has always been a hallmark of CodeIgniter in the past. It’s simple to pick up and get started with. It’s fairly simple to learn. And it doesn’t do a lot of magic in the background to make everything happen. That’s one of the things that has come more and more to the forefront while we’re developing this: a focus on simplicity.

Not just simple for the user, though we feel that we’re doing pretty good there, too. But a simplicity of the solutions chosen within the core framework itself. Config files are one example. They are simply classes. That means that there’s no extra loader needed for a configuration file, and that a configuration file can exist anywhere that the autoloader can find it. While we’ve used some modern practices like dependency injection, that has been kept simple, too. Initially, I had created a convention-based DI container that I was pretty proud of. Eventually, though, I decided it was too complex of a solution, when all that was needed was a single class with methods that return a class for you.

Simpler isn’t just code for us. Simpler code frequently executes faster. It’s also simpler to understand when you’re debugging your own code. And simpler for us to maintain.

It’s Fast

CodeIgniter has always been known for being pretty speedy compared to some of the other well-known frameworks. Version 4 will continue that trend. Now that we have all of the required pieces in place that are loaded during a simple “Hello World” example, I had to see how we were comparing with CI3. I was pleasantly surprised.

My first, very informal, test was done by simply refreshing the page quite a few times on both versions and determining an average display time based on the number that it shows on the default home page. CI4 was showing an average of around 0.0086 seconds, while CI3 was averaging 0.0124. Now, this is on a 5-year old iMac, running Apache with XDebug off and no opcaching, and entirely too many applications open. Nothing here has been optimized for speed, so ignore the actual numbers. But that’s a pretty good speed difference there.

Next up was to determine how that translated to something more like a real-world use case. Tests were ran on the same computer, using Apache, with XDebug disabled and opcache turned on. I used Apache bench to slam the sites with 3 rounds of the following command, taking the average number:

ab -n 2000 -c 10 http://ci4.dev/

The results? CI4 gave around 2500 requests per second, while CI3 clocked about 2250 requests per second. That’s about a 10% improvement. On code that has had no optimization, yet, and that has a few portions where more files were needed to implement a more robust solution, like the Request and Response process. I’m thrilled by those results so far. Use that with Nginx and you’d see even better results.

It’s Flexible

Another thing that I’ve seen touted about CodeIgniter on the forums for years has been that it doesn’t force you do anything in one particular way. You’re free to use models (or not) as you see fit. Controllers can be thin or fat. The choices are yours. In many ways, I feel that the core we’ve come up with takes that even farther.

You can still work with models and controllers in much the same way that you’re used to, sticking them in the familiar directories. You’re encouraged, though, to use Namespaces. Certain parts of the framework do require it, like config files. Once you get in the habit of namespacing all of your classes, then the flexibility explodes. The application folder can be modified to whatever fits your need, or your application’s architecture. You can add directories for EntityModels, Repos, Interfaces, whatever you need.

You can split your code into modules by simply namespacing them and letting the autoloader know where to find that namespace. Simple classes make up most of your module’s parts (config files, controllers, models, and libraries), and non-class files, like helpers and views can be loaded from namespaced directories just like they were actually namespaced. In addition, routes can point to any class/method that the autoloader can find, whether it’s officially a controller or not.

It’s Secure

I know, everyone says that, and we all try as hard as we can. And in many cases, the framework itself cannot make it secure, but it can provide you the tools to most easily secure it yourself, and make it as easy as possible to use. Some tools you’re already familiar with. CSRF protection is largely the same as what we currently have. It’s good, effective, and meets the OWASP recommendations. Other parts, like XSS protection have drastically changed.

First off, doing XSS protection well is hard work. The solution that CI has always had was a little brittle, and a gave a false sense of security that you could simply flip one config setting to TRUE and have your site protected. There’s too many variables to make that work. So we’ve broken the problem down into it’s component parts so that you can always know what you’re securing and what you’re not. There will be a little bit of a learning curve for many developers, but that’s a good thing in the long run for everyone. The more you know and understand about securing your applications, the better job you’ll do.

Filter Input

The first part is filtering the input. The Request class provides a simple integration with PHP’s filter_var command and the methods to retrieve GET and POST variables, as well as SERVER, ENV, and COOKIE values. It’s not automatic, but it couldn’t be simpler. The filter_* commands built into PHP are very good, and they only get better over time with no effort on your part.

Escape Output

The second stage is escaping the output. This one is really tricky to do right. And its one area that we are trusting someone else to do right. We’re using Zend’s Escaper which provides context-specific escaping methods. This means that it can use the most effective method for escaping the output based on whether the context is basic HTML body, or a URL, an HTML tag’s attribute, in javascript, or within a stylesheet. It can help protect against character encoding trickery, and more. It’s the best, most thorough, library we know of. And it’s built into CodeIgniter now.

Content Security Policy

Finally, we make it easy to implement Content Security Policy which is probably the best defense available against XSS attacks. It basically forces you to whitelist URI’s for scripts, images, etc. Very powerful and most browsers have pretty good support for it today.

Before it’s all said and done, we’ll walk through OWASP’s Top Ten vulnerabilities and do what we can to provide tools to combat those situations.

It’s the Bonuses

Much of what is in the framework, when it’s done, will be familiar to you if you’re a old hand with CodeIgniter. Already, though, new features are making their way into the system.

Content Negotiation

When creating API’s it’s especially important to be able give the user agents content the way they want it. They might request the data preferably in JSON, but XML is fine if you don’t support JSON. They might request it in a certain language, or encoded a certain way. Your application's job is to be able to interpret those requests and match what you can provide up with what they are requesting and give them the best match. This is known as Content Negotiation and is now almost as simple as $lang = $negotiate->language().

HTTP Client

Quite often, our application’s need to interact with other servers, usually through cURL. Often, though, we need to pull in a third-party library like Guzzle to handle authentication, etc. This will be made easier in many cases with CodeIgniter’s new CURLRequest class, which is a lightweight HTTP client. We know that it won’t meet every need you’ll have, so the syntax has been kept as close as possible to Guzzle’s so that if you find you need asynch calls, or some other advanced features, you won’t need to modify what you’ve already written much to get it working.

CLI Tools

CodeIgniter has never required the command line to work. However, there are times when having scripts in our apps that did work on the CLI would be a great thing. That might be part of an installation script, or maybe a CRON job. You could even build tools that allow you to interact with your site through SSH, even when the site is down for maintenance. The framework now makes it easy to create cli-only routes, and provides tools for interacting with the user on the CLI by asking them questions, displaying colored output, and more.

Wrap It Up, Already!

We’ve been hard at work these past 3 months or so creating a system that helps you out when you need it, and stays out of the way when you don’t. We’ve tried to balance the changes that the system needs to bring it into the modern era and thrive for years to come, with the feel and features that have made CodeIgniter popular. We think you’re going to love it and can’t wait for you to get your hands on it.

When Can You Get It?

Of course, at this point you’ll be wondering when you can get it. As always, the only answer we can give is, “When it’s ready”. There are two main portions remaining to be implemented, including one beast: the database layer. Then we’ll need to increase our unit tests, write some better and more accurate docs than we currently have, and put it through it’s paces a little bit. So, we’re close to having Phase 1 done, but we’re not there, yet.

We are excited, though, and hope that you are, too.

The cries happen every year or so. CodeIgniter is dead. They've been saying this for quite a while, but I don't believe them. Granted, I'm fond of the framework and have been using it since 2006. It's extremely stable. Fast. Quite flexible. It can do everything I've ever needed it to. Sure there are a few annoyances, but that's the same with every other framework I've used, including Rails, Laravel, and Cake. Here at Bonfire, though, we believe in CodeIgniter.

However, we also believe it needs to be able to grow and morph a bit to keep up with the demands of modern developers. So I've decided that Bonfire will no longer be a pure CodeIgniter application. What does this mean? Simply that we won't be afraid to tweak core files anymore where we need to.

Yeah, I hear the screams of "Blasphemy!" but hear me out.

We will strive to keep the changes minimal but there are a few places where some additional tweaks are needed in order to provide a more powerful, flexibile experience. Starting with version 0.7.1 we are overriding a couple of core files. I think you'll be happy with the changes coming down the pike.

Code Separation

We made huge strides in 0.7 in getting Bonfire's code away from your application's code as much as possible. However, there were a few things that we couldn't separate out and had to be left in the application folder. So we're making a couple tweaks to the Common and CodeIgniter files that allow us to store ALL of Bonfire's specific, do not touch, code in the bonfire folder. This allows us you to upgrade as easily as possible.

The only exception here will be the stock controllers that we build on top of. They'll still reside in the application folder, but only because there are likely changes that you'll need to make for most any application within those files so we don't want to overwrite in core upgrades.

Routing

One of the places that feels the weakest to me, compared to more recent PHP frameworks, is the routing system. So we've made some big additions here.

The first is a new Route library class, patterned after Jamie Rumbelow's excellent Pigeon library and Laravel's Router. This new library is already written and provides great new features like:

  • HTTP Verb-based routing, so you can assign routes only to respond if certain HTTP verb is in use. Like specifying a route just for GET request and another (at the same URL) for POST request. This makes building RESTfull routes easy.
  • Resourceful Routes make REST even easier by providing a single method to create all standard REST routes for you, though you can definitely customize the way it works.
  • Prefixing Routes groups routes together under a single URI segment heading, like 'api' or 'banking' or whatever.
  • Context Routes replace the current context system and makes it easy to add new context areas that map from one segment to any controller in your modules. Yes, it still requires modules, but is a little less magic and much more flexible.
  • Named Routes give names to routes so that you can reference the names throughout your application instead of the route. That way you can change the URL in the routes config file and not have to worry about your application breaking.

You can grab this library for any of your CI based applications today over at my GitHub account. It's fully tested and has an in-depth readme over there.

Modules

We've overridden the Loader and Router classes with our own custom versions. These contain the new module code that we'll be using from here on out. It replaces WireDesignz excellent HMVC code that we've been using since day one and will provide all of the same functionality. This is based on Jens Segers HMVC code with some modifications along the way.

So, why did we switch if it has the same functionality? We needed a solution that would help us load files from Bonfire directly, and from Bonfire's modules. So it had to be something easy to integrate. Jen's code is built on top of, and takes great advantage of, CodeIgniter's built-in packages. This creates cleaner, more elegant code than WireDesignz'.

The other reason I wanted to integrate and replace the core was so that we have the potential for even more advanced routing tricks, like filters, etc. Don't expect those items for 0.7.1, but the possibility is always there.

Saying Farewell. And Hello

In some ways it feels like this break is us saying "Good bye" to CodeIgniter and starting to fork it ourselves. Please understand, though, that this is not my intention. Instead, it's simply tweaking the core to give your code room, provide easier upgradability, and bring a little more fun back into your coding.

Instead, think of this as saying "Hello" to a slightly more mature version of your favorite framework.

Coming soon in version 0.7.1.