Home

Awesome

Pod, a simple Web Server Interface for PHP [WIP]

Show me the source code!

— You, just now.

No. There is no source code yet. I'm practicing Readme Driven Development here. But don't turn away! I really appreciate your Feedback on this, so please stay, read it and send your feedback to @yuri41 or submit an Issue to the Issue Tracker.

Everything is up for discussion (including the name)!


Pod, the socket for holding the bit in a boring tool.

Wordnik

Pod is a simple interface between the PHP Application and the Web Server. Pod is a port of the Rack Specification, with some things done the "PHP way".


I want to thank Christian Neukirchen for the Rack Specification and the Python Community for PEP 333 (and PEP 3333). These are great examples of very well written Specs and were a big help and inspiration.

Mission

Aside: Why $_SERVER is flawed

The $_SERVER variable has one big flaw: it's entirely up to the server which keys exist and what the values contain.

$_SERVER is an array containing information such as headers, paths, and script locations. The entries in this array are created by the web server. There is no guarantee that every web server will provide any of these; servers may omit some, or provide others not listed here.

http://www.php.net/$_SERVER

Most of $_SERVER is taken from the CGI Specification though, but there ain't any obligatory contract, which specifies what must be there and what values the application can expect.

Benefits for Web Server Authors

Benefits for Application Authors

Benefits for Framework Authors

Install

Pod is installed via Composer. To install it, add this to your composer.json:

# composer.json
{
    "require": {
        "chh/pod": ">=1.0.0,<2.0.0dev"
    }
}

Then run in your project directory:

# If you don't have composer already:
% wget http://getcomposer.org/composer.phar

# Download into the "vendor/" directory
% php composer.phar install

Usage

Like Rack, Pod distinguishes between two kinds of components:

Each component in Pod follows a simple interface: the Callback. This means that they can be implemented by:

Each callback takes exactly one argument (the environment) and returns an array of three elements:

  1. status, HTTP status code as Integer.
  2. headers, Array of header => value pairs.
  3. body, the response body as Array of Strings, Resource or Iterator.

A very minimal application could look like this:

# app.php
<?php

function helloWorldApp(&$env)
{
    return array(200, array(), array("<h1>Hello World</h1>"));
}

To serve this application the traditional way, put this into your index.php:

# index.php
<?php

$pod = Pod\Builder::load("pod_config.php");
# Serves the App as normal PHP app.
$pod->launch();

# pod_config.php
<?php

require_once(__DIR__."/app.php");

$this->run("helloWorldApp");

Pod will then call your app and send your response back as HTTP response.

Middleware components follow the same interface as Applications, the only difference is that they sit in a chain in front of the application.

A simple middleware which overrides the Content-Type with the format in a format parameter could look like this:

# FormatOverride.php
<?php

class FormatOverride
{
    var $formats = array(
        'html' => 'text/html',
        'json' => 'application/json',
        'xml'  => 'application/xml'
    );

    function __invoke(&$env) 
    {
        $query = $env['QUERY_STRING'];
        parse_str($query, $params);

        if ($format = @$params['format'] and isset($this->formats[$format])) {
            $env['HTTP_CONTENT_TYPE'] = $this->formats[$format];
        }
    }
}

Then register it in the chain:

# pod_config.php
<?php

require_once(__DIR__."/FormatOverride.php");

$this->register(new FormatOverride);

Servers

Servers should provide a Handler to interface with applications.

Handlers should implement a run method which takes any Pod callback. The run method should provide the initial environment, invoke the callback and send a HTTP response back to the client.