Category Archives: Symfony

Microservice container with Guzzle

This days I’m reading about Microservices. The idea is great. Instead of building a monolithic script using one language/framowork. We create isolated services and we build our application using those services (speaking HTTP between services and application).

That’s means we’ll have several microservices and we need to use them, and maybe sometimes change one service with another one. In this post I want to build one small container to handle those microservices. Similar idea than Dependency Injection Containers.

As we’re going to speak HTTP, we need a HTTP client. We can build one using curl, but in PHP world we have Guzzle, a great HTTP client library. In fact Guzzle has something similar than the idea of this post: Guzzle services, but I want something more siple.

Imagine we have different services:
One Silex service (PHP + Silex)

use Silex\Application;

$app = new Application();

$app->get('/hello/{username}', function($username) {
    return "Hello {$username} from silex service";
});

$app->run();

Another PHP service. This one using Slim framework

use Slim\Slim;

$app = new Slim();

$app->get('/hello/:username', function ($username) {
    echo "Hello {$username} from slim service";
});

$app->run();

And finally one Python service using Flask framework

from flask import Flask, jsonify
app = Flask(__name__)

@app.route('/hello/<username>')
def show_user_profile(username):
    return "Hello %s from flask service" % username

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=5000)

Now, with our simple container we can use one service or another

use Symfony\Component\Config\FileLocator;
use MSIC\Loader\YamlFileLoader;
use MSIC\Container;

$container = new Container();

$ymlLoader = new YamlFileLoader($container, new FileLocator(__DIR__));
$ymlLoader->load('container.yml');

echo $container->getService('flaskServer')->get('/hello/Gonzalo')->getBody() . "\n";
echo $container->getService('silexServer')->get('/hello/Gonzalo')->getBody() . "\n";
echo $container->getService('slimServer')->get('/hello/Gonzalo')->getBody() . "\n";

And that’s all. You can see the project in my github account.

Why did this year has passed so swiftly? My 2014 Retrospective.

Today an original post. Maybe I’m the only one doing this, I know. 2014 is close to finish and I want to review how it went the year. Let’s start.

The bad parts:

  • My book about SOLID principles (in Spanish) isn’t released yet. It’s almost finished. It only needs a few reviews, but because one thing or another it looks like it isn’t be released this year. Lesson learned: Those kind of side projects must have a release date. If they haven’t, another side projects can grab our attention and they can be frozen.
  • No new languages learned this year. There was a good chance with Swift. A new language, but it didn’t attract my attention. Erlang books are still in my desk and also my aim to improve my Java skills didn’t success. I found nothing where apply my Java learning.

The good parts:

  • Finally I can say JavaScript is a first class language within my personal software stack. Various projects with JS this year and I feel very comfortable writing JavaScript code. That’s also the year of Angular.js (for me and probably a lot of people).
  • This year has been the year of mobile development for me. I’ve been involved with several projects using Cordova/Phonegap framework. I the beginning to install Cordova environment, compile, deploy the application into the device was something “heroic” but now it turns into trivial operations. I still remember my beginning with jQuery Mobile. Horrible. Then I started using Angular.js and Topcoat. Much better, but still problems when switching between Android and IOs. Finally I re-discover Ionic framework. Incredible project. Hybrid applications with angular.js with very complete toolkit. This year has been crowed by push notifications, camera plugins, barcode scanners, token based authorisations, Websockets and things like that. Now hybrid applications with Phonegap/Cordova live in my comfort zone along with Silex, Angular, PHP… (that’s means I need to find other places outside it)
  • The last part of the year I’ve been working a lot with automation tools: Bower and Grunt mainly. I also started to work with JavaScript testing with Karma and Jasmine
  • This year I’ve been a proud speaker at DeSymfony Day in Barcelona. On incredible weekend. Meeting with colleagues, speaker dinner, great conversations, and tourism in a great city. Definitely the most beautiful room for a conference that I ever been
  • Katayunos The coding dojo where we play with TDD and Pair Programming is still alive. Maybe not as continuous as I’d like, but we still meet together 20-25 people one Saturday morning to improve our programming skill, from time to time
  • My personal blog is still alive too. It’s close to be 5 years old (OK, technically speaking 6, but first year it wasn’t a serious one). More than 20k views per month and sometimes close to 30k (Hey, thank you for reading!)

And that’s all. It was a good year. Hopefully it will be worse than 2015 :)

See you!

Building a Pimple/Container from a YAML file

The last May I attended to the great deSymfony day conference in Barcelona. At speaker’s dinner I had a great conversation with Máximo Cuadros about Dependency Injection Containers. We discuss about the customisation of containers. I said that I prefer Symfony´s DIC instead of Pimple, mainly because its configuration with YAML (or even xml) files. But In fact we can customise Pimple/Containers with YAML files in a similar way than we do it with Symfony’s DIC. In this example we’re going to see one way to do it.

We can easily extend the Pimple/Container and add a function to load a YAML files, parse them and build the container. But doing this we’re violating various SOLID principles. First we’re violating the Open-Close principle, because to extend our Pimple/Container with the new functionality we are adding new code within an existing class. We’re also violating the Dependency Inversion Principle and our new Pimple/Container is going to be harder to maintain. And finally we’re obviously violating the Single Responsibility Principle, because our new Pimple/Container is not only a DIC, it’s also a YAML parser.

There’s another way to perform this operation without upsetting SOLID principles. We can use the Symfony’s Config component

The idea is simple. Imagine this simple application:

use Pimple\Container;

$container = new Container();
$container['name'] = 'Gonzalo';

$container['Curl'] = function () {
    return new Curl();
};
$container['Proxy'] = function ($c) {
    return new Proxy($c['Curl']);
};

$container['App'] = function ($c) {
    return new App($c['Proxy'], $c['name']);
};

$app = $container['App'];
echo $app->hello();

We define the dependencies with code. But we want to define dependencies using a yml file for example:

parameters:
  name: Gonzalo

services:
  App:
    class:     App
    arguments: [@Proxy, %name%]
  Proxy:
    class:     Proxy
    arguments: [@Curl]
  Curl:
    class:     Curl

As we can see we’re using a similar syntax than Symfony’s DIC YAML files.
Now, with our new library we can use the following code:

use Pimple\Container;
use G\Yaml2Pimple\ContainerBuilder;
use G\Yaml2Pimple\YamlFileLoader;
use Symfony\Component\Config\FileLocator;

$container = new Container();

$builder = new ContainerBuilder($container);
$locator = new FileLocator(__DIR__);
$loader = new YamlFileLoader($builder, $locator);
$loader->load('services.yml');

$app = $container['App'];
echo $app->hello();

Now our Pimple/Container is just a Pimple/Container nothing more. It doesn’t know anything about yaml, parsers and thing like that. It’s doesn’t have any extra responsibility. The responsibility of the parser falls on YamlFileLoader
You can see the library in my github account. It’s but one usage example of Symfony’s Config component. It only allows Yaml files, but it can be extended with Xml files adding a XmlFileLoader.

Token based authentication with Silex and AngularJS

According to my last post today we’re going to create a AngularJS application that uses the Silex Backend that we create previously. The idea of this application is to use it within a Phonegap/Cordova application running in a mobile device.

The application will be show a login form if device haven’t a correct token.

Gonzalo_Login_Example_and_LoginServiceProvider_php_-_token_-____work_projects_token_

And whit a correct token:

Gonzalo_Login_Example

Nothing new under the sun, isn’t it?

Our front-end application will use AngularJS and Topcoat.

<!DOCTYPE html>
<html xmlns:ng="http://angularjs.org" lang="es" ng-app="G">
<head>
    <meta charset="utf-8"/>
    <meta name="format-detection" content="telephone=no"/>
    <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
    <meta name="viewport"
          content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi"/>
    <link rel="stylesheet" type="text/css" href="/bower_components/topcoat/css/topcoat-mobile-light.min.css">
    <title>Gonzalo Login Example</title>
</head>
<body ng-controller="MainController">

<div ng-view class="main-content"></div>

<script src="/bower_components/angular/angular.min.js"></script>
<script src="/bower_components/angular-route/angular-route.min.js"></script>

<script src="js/app.js"></script>
<script src="js/services.js"></script>

</body>
</html>

And our AngularJS application:

'use strict';
var appControllers, G;
var host = 'http://localhost:8080'; // server API url

appControllers = angular.module('appControllers', []);
G = angular.module('G', ['ngRoute', 'appControllers']);

G.run(function (httpG) {
    httpG.setHost(host);
});

G.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/login', {templateUrl: 'partials/login.html', controller: 'LoginController'}).
        when('/home', {templateUrl: 'partials/home.html', controller: 'HomeController'});
}]);

appControllers.controller('HomeController', ['$scope', 'httpG', '$location', function ($scope, httpG, $location) {
    $scope.hello = function () {
        httpG.get('/api/info').success(function (data) {
            if (data.status) {
                alert("Hello " + data.info.name + " " + data.info.surname);
            }
        });
    };

    $scope.logOut = function () {
        alert("Good bye!");
        httpG.removeToken();
        $scope.isAuthenticated = false;
        $location.path('login');
    };
}]);

appControllers.controller('MainController', ['$scope', '$location', 'httpG', function ($scope, $location, httpG) {
    $scope.isAuthenticated = false;

    if (httpG.getToken()) {
        $scope.isAuthenticated = true;
        $location.path('home');
    } else {
        $location.path('login');
    }
}]);


appControllers.controller('LoginController', ['$scope', '$location', 'httpG', function ($scope, $location, httpG) {
    $scope.user = {};

    $scope.doLogIn = function () {
        httpG.get('/auth/validateCredentials', {user: $scope.user.username, pass: $scope.user.password}).success(function (data) {
            if (data.status) {
                httpG.setToken(data.info.token);
                $scope.isAuthenticated = true;
                $location.path('home');
            } else {
                alert("login error");
            }
        }).error(function (error) {
            alert("Login Error!");
        });
    };

    $scope.doLogOut = function () {
        httpG.removeToken();
    };
}]);

In this example I’m using angular-route to handle the application’s routes. Nowadays I’m swaping to angular-ui-router, but this example I’m still using “old-style” routes. We define two partials:

partial/home.html

<div class="topcoat-button-bar full" style="position: fixed; bottom: 0px;">
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button full" ng-click="logOut()">
            <span class="">Logout</span>
        </button>
    </label>
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button--cta full" ng-click="hello()">
            <span class="">Hello</span>
        </button>
    </label>
</div>

partial/login.html

<div class="topcoat-navigation-bar">
    <div class="topcoat-navigation-bar__item center full">
        <h1 class="topcoat-navigation-bar__title">Login</h1>
    </div>
</div>

<ul class="topcoat-list__container">
    <li class="topcoat-list__item center">
        <input ng-model="user.username" class="topcoat-text-input--large" type="text" name="user"
               placeholder="Username"/>
    </li>
    <li class="topcoat-list__item center">
        <input ng-model="user.password" class="topcoat-text-input--large" type="password" name="pass"
               placeholder="Password"/>
    </li>
</ul>

<div class="topcoat-button-bar full" style="position: fixed; bottom: 0px;">
    <label class="topcoat-button-bar__item">
        <button class="topcoat-button--cta full" ng-click="doLogIn()">
            <span class="">Login</span>
        </button>
    </label>
</div>

As we can see in the application we’re using a service to handle Http connections with the token information.

'use strict';

G.factory('httpG', ['$http', '$window', function ($http, $window) {
    var serviceToken, serviceHost, tokenKey;
    tokenKey = 'token';
    if (localStorage.getItem(tokenKey)) {
        serviceToken = $window.localStorage.getItem(tokenKey);
    }

    $http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";

    return {
        setHost: function (host) {
            serviceHost = host;
        },

        setToken: function (token) {
            serviceToken = token;
            $window.localStorage.setItem(tokenKey, token);
        },

        getToken: function () {
            return serviceToken;
        },

        removeToken: function() {
            serviceToken = undefined;
            $window.localStorage.removeItem(tokenKey);
        },

        get: function (uri, params) {
            params = params || {};
            params['_token'] = serviceToken;
            return $http.get(serviceHost + uri, {params: params});
        },

        post: function (uri, params) {
            params = params || {};
            params['_token'] = serviceToken;

            return $http.post(serviceHost + uri, params);
        }
    };
}]);

And that’s all. You can see the full example in my github account.

Talk about SOLID and Symfony at the deSymfony 2014 conference.

Last saturday I attended to the deSymfony conference in Barcelona. A great opportunity to meet again with the PHP and Symfony community in Spain. This year the conference accepted my talk about SOLID and Symfony. Here you can see the slides of the talk (slides in spanish):

The conference was perfect. Barcelona is an incredible city and the conference place (10 minutes walking from the Sagrada Familia), was incredible too. Great talks. But the best, as always, the coffe breaks with the conversations with the Symfony and PHP community from Valencia, Zaragoza, Madrid, Barcelona, …

That’s me in action speaking about SOLID principles and Symfony:
Bo90AasCMAAdHL8 (photo source)

But the best of my speech was in the opposite direction. Many thanks to all of you :)

20140531_152345

Token based authentication with Silex Applications

Imagine this simple Silex application:

use Silex\Application;

$app = new Application();

$app->get('/api/info', function (Application $app) {
    return $app->json([
        'status' => true,
        'info'   => [
            'name'    => 'Gonzalo',
            'surname' => 'Ayuso'
        ]]);
});

$app->run();

What happens if we want to use a security layer? We can use sessions. Sessions are the “standard” way to perform authentication in web applications, but when our application is a PhoneGap/Cordova application that uses a Silex server as API server, sessions aren’t the best way. The best way now is a token based authentication. The idea is simple. First we need a valid token. Our API server will give us a valid token if we send valid credentials in a login form. Then we need to send the token with each request (the same way than we send the session cookie with each request).

With Silex we can check this token and validate.

use Silex\Application;

$app = new Application();

$app->get('/api/info', function (Application $app) {
    $token = $app->get('_token');
    
    // here we need to validate the token ...

    return $app->json([
        'status' => true,
        'info'   => [
            'name'    => 'Gonzalo',
            'surname' => 'Ayuso'
        ]]);
});

$app->run();

It isn’t an elegant solution. We need to validate the token within all routes and that’s bored. We also can use middlewares and validates the token with $app->before(). We’re going to build something like this, but with a few variations. First I want to keep the main application as clean as possible. Validation logic must be separated from application logic, so we will extend Silex\Application. Our main application will be like this:

use G\Silex\Application;

$app = new Application();

$app->get('/api/info', function (Application $app) {
    return $app->json([
        'status' => true,
        'info'   => [
            'name'    => 'Gonzalo',
            'surname' => 'Ayuso'
        ]]);
});

$app->run();

Instead of Silex\Application we’ll use G\Silex\Application.

namespace G\Silex;

use Silex\Application as SilexApplication;
use G\Silex\Provider\Login\LoginBuilder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class Application extends SilexApplication
{
    public function __construct(array $values = [])
    {
        parent::__construct($values);

        LoginBuilder::mountProviderIntoApplication('/auth', $this);

        $this->after(function (Request $request, Response $response) {
            $response->headers->set('Access-Control-Allow-Origin', '*');
        });
    }
}

Our new G\Silex\Application is a Silex\Application enabling CORS. We also mount a Service provider.

The responsibility of our API server will be check the token of every request and to provide one way to get a new token. To get a new token we will create a route “/auth/validateCredentials”. If a valid credentials are given, new token will be send to client.

Our Service provider has two parts: a service provider and a controller provider.

To mount both providers we will use a LoginBuilder class:

namespace G\Silex\Provider\Login;

use Silex\Application;

class LoginBuilder
{
    public static function mountProviderIntoApplication($route, Application $app)
    {
        $app->register(new LoginServiceProvider());
        $app->mount($route, (new LoginControllerProvider())->setBaseRoute($route));
    }
}

Our Controller provider:

namespace G\Silex\Provider\Login;

use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpFoundation\Request;
use Silex\ControllerProviderInterface;
use Silex\Application;

class LoginControllerProvider implements ControllerProviderInterface
{
    const VALIDATE_CREDENTIALS = '/validateCredentials';
    const TOKEN_HEADER_KEY     = 'X-Token';
    const TOKEN_REQUEST_KEY    = '_token';

    private $baseRoute;

    public function setBaseRoute($baseRoute)
    {
        $this->baseRoute = $baseRoute;

        return $this;
    }

    public function connect(Application $app)
    {
        $this->setUpMiddlewares($app);

        return $this->extractControllers($app);
    }

    private function extractControllers(Application $app)
    {
        $controllers = $app['controllers_factory'];

        $controllers->get(self::VALIDATE_CREDENTIALS, function (Request $request) use ($app) {
            $user   = $request->get('user');
            $pass   = $request->get('pass');
            $status = $app[LoginServiceProvider::AUTH_VALIDATE_CREDENTIALS]($user, $pass);

            return $app->json([
                'status' => $status,
                'info'   => $status ? ['token' => $app[LoginServiceProvider::AUTH_NEW_TOKEN]($user)] : []
            ]);
        });

        return $controllers;
    }

    private function setUpMiddlewares(Application $app)
    {
        $app->before(function (Request $request) use ($app) {
            if (!$this->isAuthRequiredForPath($request->getPathInfo())) {
                if (!$this->isValidTokenForApplication($app, $this->getTokenFromRequest($request))) {
                    throw new AccessDeniedHttpException('Access Denied');
                }
            }
        });
    }

    private function getTokenFromRequest(Request $request)
    {
        return $request->headers->get(self::TOKEN_HEADER_KEY, $request->get(self::TOKEN_REQUEST_KEY));
    }

    private function isAuthRequiredForPath($path)
    {
        return in_array($path, [$this->baseRoute . self::VALIDATE_CREDENTIALS]);
    }

    private function isValidTokenForApplication(Application $app, $token)
    {
        return $app[LoginServiceProvider::AUTH_VALIDATE_TOKEN]($token);
    }
}

And our Service provider:

namespace G\Silex\Provider\Login;

use Silex\Application;
use Silex\ServiceProviderInterface;

class LoginServiceProvider implements ServiceProviderInterface
{
    const AUTH_VALIDATE_CREDENTIALS = 'auth.validate.credentials';
    const AUTH_VALIDATE_TOKEN       = 'auth.validate.token';
    const AUTH_NEW_TOKEN            = 'auth.new.token';

    public function register(Application $app)
    {
        $app[self::AUTH_VALIDATE_CREDENTIALS] = $app->protect(function ($user, $pass) {
            return $this->validateCredentials($user, $pass);
        });

        $app[self::AUTH_VALIDATE_TOKEN] = $app->protect(function ($token) {
            return $this->validateToken($token);
        });

        $app[self::AUTH_NEW_TOKEN] = $app->protect(function ($user) {
            return $this->getNewTokenForUser($user);
        });
    }

    public function boot(Application $app)
    {
    }

    private function validateCredentials($user, $pass)
    {
        return $user == $pass;
    }

    private function validateToken($token)
    {
        return $token == 'a';
    }

    private function getNewTokenForUser($user)
    {
        return 'a';
    }
}

Our Service provider will have the logic to validate credentials, token and it must be able to generate a new token:

    private function validateCredentials($user, $pass)
    {
        return $user == $pass;
    }

    private function validateToken($token)
    {
        return $token == 'a';
    }

    private function getNewTokenForUser($user)
    {
        return 'a';
    }

As we can see the logic of the example is very simple. It’s just an example and here we must to perform our logic. Probably we need to check credentials with our database, and our token must be stored somewhere to be validated later.

You can see the example in my github account. In another post we will see how to build a client application with angularJs to use this API server.

Auto injecting dependencies in PHP objects

I must admit I don’t really know what’s the correct title for this post. Finally I use “Auto injecting dependencies in PHP objects”. I know it isn’t very descriptive. Let me explain it a little bit. This time I want to automate the Hollywood Principle (“Don’t call us, we’ll call you”). The idea is simple. Imagine one “controller”

class Controller
{
    public function hi($name)
    {
        return "Hi $name";
    }
}

We can easily automate the “hi” action

$controller = new Controller();
echo $controller->hi("Gonzalo");

Or maybe if we are building a framework and our class name and action name depends on user-input:

$class = "Controller";
$action = "hi";
$arguments = ['name' => "Gonzalo"];

echo call_user_function_array([new $class, $action], arguments);

But imagine that we want to allow something like that:

class Controller
{
    public function hi($name, Request $request)
    {
        return "Hi $name " .$request->get('surname');
    }
}

Now we need to inject Request object within our action “hi”, but not always. Only when user set a input variable with the type “Request”. Imagine that we also want to allow this kind of injection in the constructor too. We can need to use Reflection to create our instance and to call our action. Sometimes I need to work with custom frameworks and legacy PHP applications. I’ve done it in a couple of projects, but now I want to create a library to automate this operation.

The idea is to use a Dependency Injection Container (Pimple in my example) and retrieve the dependency from container (if it’s available). I cannot use “new” keyword to create the instance and also I cannot call directly the action.

One usage example is:

class Foo
{
    public function hi($name)
    {
        return "Hi $name";
    }
}

class Another
{
    public function bye($name)
    {
        return "Bye $name";
    }
}

class Bar
{
    private $foo;

    public function __construct(Foo $foo, $surname = null)
    {
        $this->foo     = $foo;
        $this->surname = $surname;
    }

    public function hi(Another $another, $name)
    {
        return $this->foo->hi($name . " " . $this->surname) . ' ' . $another->bye($name);
    }
}

$container = new Pimple();
$container['name'] = "Gonzalo2";

$builder = new G\Builder($container);

$bar = $builder->create('Bar', ['surname' => 'Ayuso']);
var_dump($builder->call([$bar, 'hi']));

var_dump($bar->hi(new Another(), 'xxxxx'));

Our library tries to retrieve the dependecy from the DIC. If it cannot do it, it creates the a new instance.
The whole “magic” is in the Builder class. You can see the library in my github account.

Integrating WebSockets with PHP applications. Silex and socket.io playing together.

WebSockets are great. We can start a persistent connection from our browser to our server and use this connection to send real time notifications to our users. Normally when we integrate WebSockets with an existing Web application, we need to face with one slight problem. Our Web application runs on a Web server (imagine, for example one Silex application). We can use a login form and ensure all requests are authorized (using a security layer). This problem is solved years ago. We can use Basic HTTP authentification, Digtest authentification, a session based authentication, token based authentificatio, OAuth, … The problem arrives when we add WebSocket server. WebSocket server is another serve. We can use node.js, ruby, or even PHP with Rachet. But how we can ensure that WebSocket server’s requests are also authenticated? We can try to share our authentification provider between both servers, but this solution is quite “exotic”. That was the idea behind my blog post: post some time ago. I’ve been thinkin a lot about it, and also read posts and speak with colleages about this subject. Finally I’m using the following solution. Let me explain it.

Websockets are bi-directional. We can get messages in the browser and send them from browser to server. Basically the solution is to disable the messages from the browser to the server via WebSockets. In fact HTML5 provides another tool to do that called Server Side Events (aka SSE), but SSE aren’t as widely used as WebSockets. Because of that I preffer to use WebSockets (without using the browser-to-server chanel) instead of SSE.

Let’s create a simple Silex application:

class Application extends Silex\Application
{
    use Silex\Application\TwigTrait;
}

$app = new Application();

$app->register(new Silex\Provider\TwigServiceProvider(), array(
    'twig.path' => __DIR__ . '/../views',
));

$app->get('/', function () use ($app) {
    return $app->render('home.twig');
});

$app->run();

And our main template with html file

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<script src="//localhost:8080/socket.io/socket.io.js"></script>
<script>
    var socket = io.connect('//localhost:8080');

    socket.on('id1', function (data) {
        console.log("mensage from websocket: " + data);
    });
</script>
</body>
</html>

Now we have Silex application that connects to a WebSockets server. I will use socket.io to build the WebSocket server:

var CONF = {
        IO: {HOST: '0.0.0.0', PORT: 8080}
    },
    io = require('socket.io').listen(CONF.IO.PORT, CONF.IO.HOST);

Whit this ultra minimal configuration we can connect from Silex application to WebSocket server and our web application will listen to messages marked as’id1′ from the WebSocket server but, how can we do to send messages? As I said before we only rely on Silex application (in this example there isn’t any security layer, but we can use our custom login). The trick is to create a new server within our node.js server. Start this server at localhost and perform a curl request from our Silex Application to our node.js server to send the WebSockets push notifications. The idea is:

  • User clicks a link in our html (generated by our Silex application)
  • This request is a standard Silex request (using our security layer)
  • Then Silex performs a curl request to node.js server.
  • If our Silex application and node.js application are in the same server we will create a new server at localhost. In this example we are going to use Express to do that.
  • Express server will handle requests from our Silex application (not from any other host) and will send WebSocket messages

Now our node.js application will change to

var CONF = {
        IO: {HOST: '0.0.0.0', PORT: 8080},
        EXPRESS: {HOST: 'localhost', PORT: 26300}
    },
    io = require('socket.io').listen(CONF.IO.PORT, CONF.IO.HOST),
    app = require('express')();

app.get('/emit/:id/:message', function (req, res) {
    io.sockets.emit(req.params.id, req.params.message);
    res.json('OK');
});

app.listen(CONF.EXPRESS.PORT, CONF.EXPRESS.HOST);

And our html template will change to (I will use Zepto to perform AJAX requests):

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<ul>
    <li><a href="#" onclick="emit('id1', 'hello')">emit('id1', 'hello')</a></li>
    <li><a href="#" onclick="emit('id1', 'bye')">emit('id1', 'bye')</a></li>
</ul>
<script src="//localhost:8080/socket.io/socket.io.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.1.1/zepto.min.js"></script>
<script>
    var socket = io.connect('//localhost:8080');

    socket.on('id1', function (data) {
        console.log("mensage from websocket: " + data);
    });

    function emit(id, message) {
        $.get('/emit/' + id +  '/' + message);
    }
</script>
</body>
</html>

Now we need to add another route to our Silex application

use Symfony\Component\HttpFoundation\Response;

$app->get('/emit/{id}/{message}', function ($id, $message) use ($app) {
    $s = curl_init();
    curl_setopt($s, CURLOPT_URL, "http://localhost:26300/emit/{$id}/{$message}");
    curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
    $content = curl_exec($s);
    $status = curl_getinfo($s, CURLINFO_HTTP_CODE);
    curl_close($s);

    return new Response($content, $status);
});

And that’s all. Our Request from Silex arrives to WebSocket emmiter using a “secure” layer. OK, now you can said: yes, but anybody can connect to the WebSocket server and listen to ‘id1’ chanel, without any restriction. Yes, it’s true. But here you can use different solutions to ensure privacy. For example you can use a “non-obvious” chanel name based on cryptografic funcions. It’s not 100% secure, but it’s the same security layer than the standard session based security mechanism. If we know the cookie name we can perform a session hijacking attack and gain access to secure areas (without knowing the login credentials). We can generate chanel names like this: 7265cfe8fe3daa4c5069d609a0312dd2 with our Silex Application and send to the browser with an AJAX request.

I’ve created an small screencast to see the prototype in action. (source code in my github account)
In the screencast we can see how to install the prototype from github, install PHP’s vendors and the node js modules. We also can see how websocket works with two browser instances, and how to send messages directly accesing to Express application using localhost interface (and an error when I try to reach to Express server using a different network interface)

What do you think? Do you have another solution?

Enabling CORS in a RESTFull Silex server, working with a phonegap/cordova applications

This days I’m working with phonegap/cordova projects. I’m using topcoat and AngularJs to build the client side and Silex for the backend. Cordova applications are “diferent” than a common web application. Our client side is normally located inside our mobile device (it’s also possible to use remote webviews). Our cordova application must speak with our backend. The easiest way to perform this operation is to use a REST. AngularJS has a great tool to connect with RESTFull resources. Silex is also great to build RESTFull services. I wrote a couple of posts about it.

With the first request form our AngularJS application (into our android/iphone device) to our Silex application, we will face with CORS. We cannot perform a request from our “local” phonegap/cordova application to our remote WebServer. We cannot do it if we don’t allow it explictily. With Silex it’s pretty straight forward to do it. We can use the event dispatcher and change the request with after handler.

$app->after(function (Request $request, Response $response) {
    $response->headers->set('Access-Control-Allow-Origin', '*');
});

We can do more strict, setting also “Access-Control-Allow-Methods” and “Access-Control-Allow-Headers” headers but only with this header we can work properly with our RESTFull Silex application from our phonegap/cordova application.

How to run a Web Server from a PHP application

Normally we deploy our PHP applications in a webserver (such as apache, nginx, …). I used to have one apache webserver in my personal computer to play with my applications, but from time to now I preffer to use PHP’s built-in webserver for my experiments. It’s really simple. Just run:

php -S 0.0.0.0:8080 

and we’ve got one PHP webserver at our current directory. With another languages (such as node.js, Python) we can start a Web Server from our application. For example with node.js:

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8080, '0.0.0.0');
console.log('Server running at http://0.0.0.0:8080');

With PHP we cannot do it. Sure? That assertion isn’t really true. We can do it. I’ve just create one small library to do it in two different ways. First running the built-in web server and also running one React web server.

I want to share the same interface to start the server. In this implementation we will register one callback to handle incomming requests. This callback will accept a Symfony\Component\HttpFoundation\Request and it will return a Symfony\Component\HttpFoundation\Response. Then we will start our server listening to one port and we will run our callback per Request (a simple implementeation of the reactor pattern)

We will create a static factory to create the server

namespace G\HttpServer;
use React;

class Builder
{
    public static function createBuiltInServer($requestHandler)
    {
        $server = new BuiltInServer();
        $server->registerHandler($requestHandler);

        return $server;
    }

    public static function createReactServer($requestHandler)
    {
        $loop   = React\EventLoop\Factory::create();
        $socket = new React\Socket\Server($loop);

        $server = new ReactServer($loop, $socket);
        $server->registerHandler($requestHandler);

        return $server;
    }
}

Each server (BuiltIn, and React) has its own implementation.

And basically that’s all. We can run a simple webserver with the built-in server

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

Builder::createBuiltInServer(function (Request $request) {
        return "Hello " . $request->get('name');
    })->listen(1337);

Or the same thing but with React

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

Builder::createReactServer(function (Request $request) {
        return "Hello " . $request->get('name');
    })->listen(1337);

As you can see our callback handles one Request and returns one Response (The typical HttpKernel), because of that we also can run one Silex application:
With built-in:

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

$app = new Silex\Application();

$app->get('/', function () {
        return 'Hello';
    });

$app->get('/hello/{name}', function ($name) {
        return 'Hello ' . $name;
    });

Builder::createBuiltInServer(function (Request $request) use ($app) {
        return $app->handle($request);
    })->listen(1337);

And the same with React:

use G\HttpServer\Builder;
use Symfony\Component\HttpFoundation\Request;

$app = new Silex\Application();

$app->get('/', function () {
        return 'Hello';
    });

$app->get('/hello/{name}', function ($name) {
        return 'Hello ' . $name;
    });

Builder::createReactServer(function (Request $request) use ($app) {
        return $app->handle($request);
    })->listen(1337);

As an exercise I also have created one small benchmark (with both implementations) with apache ab running 100 request with a 10 request at the same time. Here you can see the outcomes.

  builtin react
Simple response    
ab -n 100 -c 10 http://localhost:1337/
Time taken for tests 0.878 seconds 0.101 seconds
Requests per second (mean) 113.91 [#/sec] 989.33 [#/sec]
Time per request (mean) 87.791 [ms] 10.108 [ms]
Time per request (mean across all concurrent requests) 8.779 [ms] 1.011 [ms]
Transfer rate 21.02 [Kbytes/sec] 112.07 [Kbytes/sec]
Silex application
ab -n 100 -c 10 http://localhost:1337/
Time taken for tests 2.241 seconds 0.247 seconds
Requests per second (mean) 44.62 [#/sec] 405.29 [#/sec]
Time per request 224.119 [ms] 24.674 [ms]
Time per request (mean across all concurrent requests) 22.412 [ms] 2.467 [ms]
Transfer rate 10.89 [Kbytes/sec] 75.60 [Kbytes/sec]
ab -n 100 -c 10 http://localhost:1337/hello/gonzalo
Time taken for tests 2.183 seconds 0.271 seconds
Requests per second (mean) 45.81 [#/sec] (mean) 369.67 [#/sec]
Time per request (mean) 218.290 [ms] (mean) 27.051 [ms]
Time per request (mean across all concurrent requests) 21.829 [ms] 2.705 [ms]
Transfer rate 11.54 [Kbytes/sec] 71.84 [Kbytes/sec]

Built-in web server is not suitable for production environments, but React would be a useful tool in some cases (maybe not good for running Facebook but good enough for punctual situations).

Library is available at github and also you can use it with composer

Follow

Get every new post delivered to your Inbox.

Join 1,085 other followers