Category Archives: Symfony2

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?

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

Using the event dispatcher in a Silex application

Symfony has one component called The Event Dispatcher. This component is one implementation of Mediator pattern and it’s widely used in modern frameworks, such as Symfony. Silex, as a part of Symfony, also uses this component and we can easily use it in our projects. Let me show you one little example. Imagine one simple route in Silex to create one png file containing one text:

$app->get("/gd/{text}", function($text) {
    $path = "/tmp/qr.png." . uniqid();
    $im = imagecreate(90, 30);
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    return $app->sendFile($path);
});

It works, but there’s one mistake. We need to unlink our temporally file $path, but where? We need do if after “return $app->sendFile($path);” but it’s not possible.

$app->get("/gd/{text}", function($text) {
    $path = "/tmp/qr.png." . uniqid();
    $im = imagecreate(90, 30);
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);;
    unlink($path); // unreachable code
});

We can use BinaryFileResponse instead of the helper function “sendFile”, but there’s one smarter solution: The event dispatcher.

use Symfony\Component\HttpKernel\KernelEvents;

$app->get("/gd/{text}", function($text) use (app) {
    $im = imagecreate(90, 30);
    $path = "/tmp/qr.png." . uniqid();
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    
    $app['dispatcher']->addListener(KernelEvents::TERMINATE, function() use ($path) {
        unlink($path);
    });

    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);
});

(Updated! thanks to Hakin’s recommendation)
Or even better using Silex’s Filters. In this case we after or finish. In fact those filters are nothing more than an elegant way to speak to the event dispatcher.


$app->get("/gd/{text}", function($text) use (app) {
    $im = imagecreate(90, 30);
    $path = "/tmp/qr.png." . uniqid();
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    
    $app->after(function() use ($path) {
        unlink($path);
    });

    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);
});

We also can use the generic function to add events to the event listener:

use Symfony\Component\HttpKernel\KernelEvents;

$app->get("/gd/{text}", function($text) use (app) {
    $im = imagecreate(90, 30);
    $path = "/tmp/qr.png." . uniqid();
    $background = imagecolorallocate($im, 255, 255, 255);
    $color = imagecolorallocate($im, 0, 0, 0);
    imagestring($im, 5, 5, 5,  $text, $color);
    imagepng($im, $path);
    imagedestroy($im);
    
    $app->on(KernelEvents::TERMINATE, function() use ($path) {
        unlink($path);
    });

    return $app->sendFile($path, 200, ['Content-Type' => 'image/png']);
});

Now our temporally file will be deleted once a response is sent. Life is simpler with event dispatcher :)

Bundles in Silex using Stack

In the last Desymfony conference I was speaking with Luis Cordova and he introduced me “Stack” (I must admit Stack was in my to-study-list but only marked as favorite). The idea behind Stack is really cool. (In fact every project where Igor Wiedler appears is brilliant, even the chicken one :)).

Nowadays almost every modern framework/applications implements HttpKernelInterface (Symfony, Laravel, Drupal, Silex, Yolo and even the framework that I’m working in ;)) and we can build complex applications mixing different components and decorate our applications with an elegant syntax.

The first thing than come to my mind after studying Stack is to join different Silex applications in a similar way than Symfony (the full stack framework) uses bundles. And the best part of this idea is that it’s pretty straightforward. Let me show you one example:

Imagine that we’re working with one application with a blog and one API. In this case our blog and our API are Silex applications (but they can be one Symfony application and one Silex application for example).

That’s our API application:

use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from API";
    });

$app->run();

And here our blog application:

use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from Blog";
    });

$app->run();

We can organize our application using mounted controllers or even using RouteCollections but today we’re going to use Stack and it’s cool url-map.

First we are going to create our base application. To do this we’re going to implement the simplest Kernel in the world, that’s answers with “Hello” to every request:

use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class MyKernel implements HttpKernelInterface
{
    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
    {
        return new Response("Hello");
    }
}

Stack needs HttpKernelInterface and Silex\Application implements this interface, so we can change our Silex applications to return the instance instead to run the application:

// app/api.php
use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from API";
    });

return $app;
// app/blog.php
use Silex\Application;

$app = new Application();
$app->get('/', function () {
        return "Hello from API";
    });

return $app;

And now we will attach those two Silex applications to our Kernel:

use Symfony\Component\HttpFoundation\Request;

$app = (new Stack\Builder())
    ->push('Stack\UrlMap', [
            "/blog" => include __DIR__ . '/app/blog.php',
            "/api" => include __DIR__ . '/app/api.php'
        ])->resolve(new MyKernel());

$request = Request::createFromGlobals();

$response = $app->handle($request);
$response->send();

$app->terminate($request, $response);

And that’s all. I don’t know what you think but with Stack one big window just opened in my mind. Cool, isn’t it?

You can see this working example in my github

Working with AngularJS and Silex as Resource provider

This days I’m playing with AngularJS. Angular is a great framework when we’re building complex front-end applications with JavaScript. And the best part is that it’s very simple to understand (and I like simple things indeed). Today we are going to play with Resources. Resources are great when we need to use RestFull resources from the server. In this example we’re going to use Silex in the backend. Let’s start.

First of all we must realize that resources aren’t included in the main AngularJS js file and we need to include angular-resource.js (it comes with Angular package). We don’t really need resources. We can create our http services with AngularJS without using this extra js file but it provides a very clean abstraction (at least for me) and I like it.

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular-resource.min.js"></script>

We’re going to create a simple application with CRUD operations in the table. In the example we will use one simple SqlLite database (included in the github repository)

CREATE TABLE main.messages (
  id INTEGER PRIMARY KEY  NOT NULL ,
  author VARCHAR NOT NULL ,
  message VARCHAR NOT NULL );

Our main (and only one) html file:

<!DOCTYPE html>
<html ng-app="MessageService">
<head>
    <title>Angular Resource Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular-resource.min.js"></script>
    <script src="js/services.js"></script>
    <script src="js/controllers.js"></script>
</head>
<body ng-controller="MessageController">

<h2>Message list <a href="#" ng-click="refresh()">refresh</a></h2>
<ul>
    <li ng-repeat="message in messages">
        <a href="#" ng-click="deleteMessage($index, message.id)">delete</a>
        #{{message.id}} - {{message.author}} - {{message.message}}
        <a href="#" ng-click="selectMessage($index)">edit</a>
    </li>
</ul>

<form>
    <input type="text" ng-model="author" placeholder="author">
    <input type="text" ng-model="message" placeholder="message">

    <button ng-click="add()" ng-show='addMode'>Create</button>
    <button ng-click="update()" ng-hide='addMode'>Update</button>
    <button ng-click="cancel()" ng-hide='addMode'>Cancel</button>
</form>
</body>
</html>

As we can see we will use ng-app=”MessageService” defined within the js/services.js file:

angular.module('MessageService', ['ngResource']).factory('Message', ['$resource', function ($resource) {
    return $resource('/api/message/resource/:id');
}]);

And our controller in js/controllers.js:

function MessageController($scope, Message) {

    var currentResource;
    var resetForm = function () {
        $scope.addMode = true;
        $scope.author = undefined;
        $scope.message = undefined;
        $scope.selectedIndex = undefined;
    }

    $scope.messages = Message.query();
    $scope.addMode = true;

    $scope.add = function () {
        var key = {};
        var value = {author: $scope.author, message: $scope.message}

        Message.save(key, value, function (data) {
            $scope.messages.push(data);
            resetForm();
        });
    };

    $scope.update = function () {
        var key = {id: currentResource.id};
        var value = {author: $scope.author, message: $scope.message}
        Message.save(key, value, function (data) {
            currentResource.author = data.author;
            currentResource.message = data.message;
            resetForm();
        });
    }

    $scope.refresh = function () {
        $scope.messages = Message.query();
        resetForm();
    };

    $scope.deleteMessage = function (index, id) {
        Message.delete({id: id}, function () {
            $scope.messages.splice(index, 1);
            resetForm();
        });
    };

    $scope.selectMessage = function (index) {
        currentResource = $scope.messages[index];
        $scope.addMode = false;
        $scope.author = currentResource.author;
        $scope.message = currentResource.message;
    }

    $scope.cancel = function () {
        resetForm();
    }
}

Now the backend part. As we said before we will use Silex. We’re going to use also RouteCollections to define our routes (you can read about it here). So our Silex application will be:

<?php
require_once __DIR__ . '/vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\RouteCollection;
use Silex\Application;

$app = new Silex\Application();

$app['routes'] = $app->extend('routes', function (RouteCollection $routes, Application $app) {
        $loader     = new YamlFileLoader(new FileLocator(__DIR__ . '/config'));
        $collection = $loader->load('routes.yml');
        $routes->addCollection($collection);

        return $routes;
    }
);

$app->register(
    new Silex\Provider\DoctrineServiceProvider(),
    array(
        'db.options' => array(
            'driver' => 'pdo_sqlite',
            'path'   => __DIR__ . '/db/app.db.sqlite',
        ),
    )
);

$app->run();

We define our routes in the messageResource.yml

getAll:
  path: /resource
  defaults: { _controller: 'Message\MessageController::getAllAction' }
  methods:  [GET]

getOne:
  path: /resource/{id}
  defaults: { _controller: 'Message\MessageController::getOneAction' }
  methods:  [GET]

deleteOne:
  path: /resource/{id}
  defaults: { _controller: 'Message\MessageController::deleteOneAction' }
  methods:  [DELETE]

addOne:
  path: /resource
  defaults: { _controller: 'Message\MessageController::addOneAction' }
  methods:  [POST]

editOne:
  path: /resource/{id}
  defaults: { _controller: 'Message\MessageController::editOneAction' }
  methods:  [POST]

And finally our Resource controller:

<?php
namespace Message;

use Silex\Application;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class MessageController
{
    public function getAllAction(Application $app)
    {
        return new JsonResponse($app['db']->fetchAll("SELECT * FROM messages"));
    }

    public function getOneAction($id, Application $app)
    {
        return new JsonResponse($app['db']
            ->fetchAssoc("SELECT * FROM messages WHERE id=:ID", ['ID' => $id]));
    }

    public function deleteOneAction($id, Application $app)
    {
        return $app['db']->delete('messages', ['ID' => $id]);
    }

    public function addOneAction(Application $app, Request $request)
    {
        $payload = json_decode($request->getContent());;

        $newResource = [
            'id'      => (integer)$app['db']
                ->fetchColumn("SELECT max(id) FROM messages") + 1,
            'author'  => $payload->author,
            'message' => $payload->message,
        ];
        $app['db']->insert('messages', $newResource);

        return new JsonResponse($newResource);
    }

    public function editOneAction($id, Application $app, Request $request)
    {
        $payload = json_decode($request->getContent());;
        $resource = [
            'author'  => $payload->author,
            'message' => $payload->message,
        ];
        $app['db']->update('messages', $resource, ['id' => $id]);

        return new JsonResponse($resource);
    }
}

And that’s all. Our prototype is working with AngularJS and Silex as REST provider. We must take care about one thing. Silex and AngularJS aren’t agree in one thing about REST services. AngularJS removes the trailing slash in some cases. Silex (and Symfony) returns HTTP 302 moved temporaly when we’re trying to access to the resource without the trailing slash but when we’re working with mounted controllers we will obtain a 404 page not found (bug/feature?). That’s because my REST service is /api/message/resource/:id instead of /api/message/:id. If I chose the second one, when angular tries to create a new resource, it will POST /api/message instead of POST /api/message/. We’re using mounted routes in this example:

messages:
  prefix: /message
  resource: messageResource.yml

With one simple Silex application (without mounted routes) in one file it doesn’t happen (we will see HTTP 302 and a new request with the trailing slash). Because of that I use this small hack to bypass the problem.

You can see the full code of the example in my github account

How to configure Symfony’s Service Container to use Twitter API

Keeping on with the series about Symfony’s Services container (another posts here and here), now we will use the service container to use Twitter API from a service.

To use Twitter API we need to handle http requests. I’ve written several post about http request with PHP (example1, example2), but today we will use one amazing library to build clients: Guzzle. Guzzle is amazing. We can easily build a Twitter client with it. There’s one example is its landing page:

<?php
$client = new Client('https://api.twitter.com/{version}', array('version' => '1.1'));
$oauth  = new OauthPlugin(array(
    'consumer_key'    => '***',
    'consumer_secret' => '***',
    'token'           => '***',
    'token_secret'    => '***'
));
$client->addSubscriber($oauth);

echo $client->get('/statuses/user_timeline.json')->send()->getBody();

If we are working within a Symfony2 application or a PHP application that uses the Symfony’s Dependency injection container component you can easily integrate this simple script in the service container. I will show you the way that I use to do it. Let’s start:

The idea is simple. First we include guzzle within our composer.json and execute composer update:

    "require": {
        "guzzle/guzzle":"dev-master"
    }

Then we will create two files, one to store our Twitter credentials and another one to configure the service container:

# twitter.conf.yml
parameters:
  twitter.baseurl: https://api.twitter.com/1.1

  twitter.config:
    consumer_key: ***
    consumer_secret: ***
    token: ***
    token_secret: ***
# twitter.yml
parameters:
  class.guzzle.response: Guzzle\Http\Message\Response
  class.guzzle.client: Guzzle\Http\Client
  class.guzzle.oauthplugin: Guzzle\Plugin\Oauth\OauthPlugin

services:
  guzzle.twitter.client:
    class: %class.guzzle.client%
    arguments: [%twitter.baseurl%]
    calls:
      - [addSubscriber, [@guzzle.twitter.oauthplugin]]

  guzzle.twitter.oauthplugin:
    class: %class.guzzle.oauthplugin%
    arguments: [%twitter.config%]

And finally we include those files in our services.yml:

# services.yml
imports:
- { resource: twitter.conf.yml }
- { resource: twitter.yml }

And that’s all. Now we can use the service without problems:

<?php

namespace Gonzalo123\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction($name)
    {
        $twitterClient = $this->container->get('guzzle.twitter.client');
        $status = $twitterClient->get('statuses/user_timeline.json')
             ->send()->getBody();

        return $this->render('AppBundle:Default:index.html.twig', array(
            'status' => $status
        ));
    }
}

Handling several DBAL Database connections in Symfony2 through the Dependency Injection Container with PHP

(This post is the second part of my previous post: Handling several PDO Database connections in Symfony2 through the Dependency Injection Container with PHP. You can read it here)

OK. We can handle PDOs connections inside a Symfony2 application, but what happens if we prefer DBAL. As we know DBAL is built over PDO and adds a set of “extra” features to our database connection. It’s something like PDO with steroids.

If we read the documentation, we will see how to use DBAL:

<?php
$config = new \Doctrine\DBAL\Configuration();
//..
$connectionParams = array(
    'dbname' => 'mydb',
    'user' => 'user',
    'password' => 'secret',
    'host' => 'localhost',
    'driver' => 'pdo_mysql',
);
$conn = DriverManager::getConnection($connectionParams, $config);

As we can see to obtain a DBAL connection we use a factory method in DriverManager class. We can easily implements it in our service container:

# databases.yml
parameters:
  doctrine.dbal.configuration: Doctrine\DBAL\Configuration
  doctrine.dbal.drivermanager: Doctrine\DBAL\DriverManager

  database.db1:
    driver: pdo_sqlite
    memory: true
  database.db2:
    driver: pdo_pgsql
    dbname: testdb
    user: username
    password: password
    host: 127.0.0.1

services:
  dbal_configuartion:
    class: %doctrine.dbal.configuration%
  db1:
    factory_class: %doctrine.dbal.drivermanager%
    factory_method: getConnection
    arguments: [%database.db1%]
  db2:
      factory_class: %doctrine.dbal.drivermanager%
      factory_method: getConnection
      arguments: [%database.db2%]

But if we run again our example Symfony will throws us one error:

RuntimeException: Please add the class to service “db1″ even if it is constructed by a factory since we might need to add method calls based on compile-time checks.

If we use this service container configuration outside Symfony2 application it works (remember we can use Symfony’s Dependency Injection Container outside Symfony application as a component. Example here). But if we want to use it with Symfony2 we need to set the “class”, even here when we only need the static constructor, so we change it to:

# databases.yml
parameters:
  doctrine.dbal.configuration: Doctrine\DBAL\Configuration
  doctrine.dbal.drivermanager: Doctrine\DBAL\DriverManager

  database.db1:
    driver: pdo_sqlite
    memory: true
  database.db2:
    driver: pdo_pgsql
    dbname: testdb
    user: username
    password: password
    host: 127.0.0.1

services:
  dbal_configuartion:
    class: %doctrine.dbal.configuration%
  db1:
    class: %doctrine.dbal.drivermanager%
    factory_class: %doctrine.dbal.drivermanager%
    factory_method: getConnection
    arguments: [%database.db1%]
  db2:
    class: %doctrine.dbal.drivermanager%
    factory_class: %doctrine.dbal.drivermanager%
    factory_method: getConnection
    arguments: [%database.db2%]

And that’s all. We can use DBAL instead of PDO in our database connections.

UPDATE:

After publishing this post someone comment me Doctrine allows us to do it “out of the box” within Symfony with its DoctrineBundle:

https://github.com/doctrine/DoctrineBundle/blob/master/Resources/doc/configuration.rst#doctrine-dbal-configuration

Handling several PDO Database connections in Symfony2 through the Dependency Injection Container with PHP

I’m not a big fan of ORMs, especially in PHP world when all dies at the end of each request. Plain SQL is easy to understand and very powerful. Anyway in PHP we have Doctrine. Doctrine is a amazing project, probably (with permission of Symfony2) the most advanced PHP project, but I normally prefer to work with SQL instead of Doctrine.

Symfony framework is closely coupled to Doctrine and it’s very easy to use the ORM from our applications. But as I said before I prefer not to use it. By the other hand I have another problem. Due to my daily work I need to connect to different databases (not only one) in my applications. In Symfony2 we normally configure the default database in our parameters.yml file:

# parameters.yml
parameters:
    database_driver: pdo_pgsql
    database_host: localhost
    database_port: 5432
    database_name: symfony
    database_user: username
    database_password: password

Ok. If we want to use PDO objects with different databases, we can use something like that:

# parameters.yml
parameters:
  database.db1.dsn: sqlite::memory:
  database.db1.username: username
  database.db1.password: password

  database.db2.dsn: pgsql:host=127.0.0.1;port=5432;dbname=testdb
  database.db2.username: username
  database.db2.password: password

And now create the PDO objects within our code with new \PDO():

$dsn      = $this->container->getParameter('database.db1.dsn');
$username = $this->container->getParameter('database.db1.username');
$password = $this->container->getParameter('database.db1.password')

$pdo = new \PDO($dsn, $username, $password);

It works, but it’s awful. We store the database credentials in the service container but we aren’t using the service container properly. So we can do one small improvement. We will create a new configuration file called databases.yml and we will include this new file within the services.yml:

# services.yml
imports:
- { resource: databases.yml }

And create our databases.yml:

# databases.yml
parameters:
  db.class: Gonzalo123\AppBundle\Db\Db

  database.db1.dsn: sqlite::memory:
  database.db1.username: username
  database.db1.password: password

  database.db2.dsn: pgsql:host=127.0.0.1;port=5432;dbname=testdb
  database.db2.username: username
  database.db2.password: password

services:
  db1:
    class: %db.class%
    calls:
      - [setDsn, [%database.db1.dsn%]]
      - [setUsername, [%database.db1.username%]]
      - [setPassword, [%database.db1.password%]]
  db2:
    class: %db.class%
    calls:
      - [setDsn, [%database.db2.dsn%]]
      - [setUsername, [%database.db2.username%]]
      - [setPassword, [%database.db2.password%]]

As we can see we have created two new services in the dependency injection container called db1 (sqlite in memory) and db2 (one postgreSql database) that use the same class (in this case ‘Gonzalo123\AppBundle\Db\Db’). So we need to create our Db class:

<?php

namespace Gonzalo123\AppBundle\Db;

class Db
{
    private $dsn;
    private $username;
    private $password;

    public function setDsn($dsn)
    {
        $this->dsn = $dsn;
    }

    public function setPassword($password)
    {
        $this->password = $password;
    }

    public function setUsername($username)
    {
        $this->username = $username;
    }

    /** @return \PDO */
    public function getPDO()
    {
        $options = array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION);
        return new \PDO($this->dsn, $this->username, $this->password, $options);
    }
}

And that’s all. Now we can get a new PDO object from our service container with:

$this->container->get('db1')->getPDO();

Better, isn’t it? But it’s still ugly. We need one extra class (Gonzalo123\AppBundle\Db\Db) and this class creates a new instance of PDO object (with getPDO()). Do we really need this class? the answer is no. We can change our service container to:

# databases.yml
parameters:
  pdo.class: PDO
  pdo.attr_errmode: 3
  pdo.erromode_exception: 2
  pdo.options:
    %pdo.attr_errmode%: %pdo.erromode_exception%

  database.db1.dsn: sqlite::memory:
  database.db1.username: username
  database.db1.password: password

  database.db2.dsn: pgsql:host=127.0.0.1;port=5432;dbname=testdb
  database.db2.username: username
  database.db2.password: password

services:
  db1:
    class: %pdo.class%
    arguments:
      - %database.db1.dsn%
      - %database.db1.username%
      - %database.db1.password%
      - %pdo.options%
  db2:
    class: %pdo.class%
    arguments:
      - %database.db2.dsn%
      - %database.db2.username%
      - %database.db2.password%
      - %pdo.options%

Now we don’t need getPDO() and we can get the PDO object directly from service container with:

$this->container->get('db1');

And we can use something like this within our controllers (or maybe better in models):

<?php

namespace Gonzalo123\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction($name)
    {
        // this code should be out from controller, in a model object.
        // It is only an example
        $pdo = $this->container->get('db1');
        $pdo->exec("CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY, title TEXT, message TEXT)");
        $pdo->exec("INSERT INTO messages(id, title, message) VALUES (1, 'title', 'message')");
        $data = $pdo->query("SELECT * FROM messages")->fetchAll();
        //

        return $this->render('AppBundle:Default:index.html.twig', array('usuario' => $data));
    }
}

How to call shell programs as functions with PHP

I’m a big fan of Symfony’s Process Component. I’ve used intensively this component within a project and I noticed that I needed a wrapper to avoid to write again and again the same code. Suddenly a cool python library came to my head: sh. With python’s sh we can call any program as if it were a function:

from sh import ifconfig
print(ifconfig("wlan0"))

Outputs:

wlan0   Link encap:Ethernet  HWaddr 00:00:00:00:00:00
        inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
        inet6 addr: ffff::ffff:ffff:ffff:fff/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:0 errors:0 dropped:0 overruns:0 frame:0
        TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:1000
        RX bytes:0 (0 GB)  TX bytes:0 (0 GB)

So I decided to develop something similar in PHP. This library is not exactly the same than python one. Python’s sh allows more cool things such as non-blocking processes, baking, … not available in my PHP one’s, but at least I can call shell programs as functions in a simple way (and that’s was my scope). Let’s start.

One simple example of Process:

use Symfony\Component\Process\Process;

$process = new Process('-latr ~');
$process->setTimeout(3600);
$process->run();

echo $process->getOutput();

With sh library we can do:

use Sh/Sh;

$sh  = new Sh();
echo $sh->ls('-latr ~');

You can check the source code in github, but it’s very simple one. Basically it’s a parser that creates the command line string, and another class that calls to the parser and sends the output to Process component. Whit the magic function __call we can use shell commands as functions.

The command’s arguments can be one string ‘-latr ~’ or one array ['-latr', '~']. You can see more example in the unit tests here

Symfony/Process also allows us to get feedback in real time:

use Symfony\Component\Process\Process;

$process = new Process('ls -lsa');
$process->run(function ($type, $buffer) {
    if ('err' === $type) {
        echo 'ERR > '.$buffer;
    } else {
        echo 'OUT > '.$buffer;
    }
});

Sh uses this feature, so we can do things like that:

$sh->tail('/var/log/messages', function ($buffer)  {
    echo $buffer;
});

We can see more examples here:

<?php
error_reporting(-1);
include __DIR__ . '/../vendor/autoload.php';
use Sh\Sh;

echo Sh::factory()->runCommnad('notify-send', ['-t', 5000, 'title', 'HOLA']);
$sh  = new Sh();
echo $sh->ifconfig("eth0");
echo $sh->ls('-latr ~');
echo $sh->ls(['-latr', '~']);
$sh->tail('-f /var/log/apache2/access.log', function ($buffer)  {
    echo $buffer;
});

As I said before the library is in github and also you can use with composer:

require: "gonzalo123/sh": "dev-master"

Updated!

Now Sh library supports chained arguments (baking)

// chainable commands (baking)
$sh->ssh(array('myserver.com', '-p' => 1393))->whoami();
// executes: ssh myserver.com -p 1393 whoami

$sh->ssh(array('myserver.com', '-p' => 1393))->tail(array("/var/log/dumb_daemon.log", 'n' => 100));
// executes: ssh myserver.com -p 1393 tail /var/log/dumb_daemon.log -n 100
});

Combining Zend Framework2 and Symfony2 components with Composer to build PHP projects

Zend Framework 2 is finally stable. I must admit that I’m not a big fan of ZF (or even Symfony2) as a full stack framework. I normally prefer to use micro frameworks, but those two frameworks (ZF2 and SF2) are great as component libraries. Today we are going to build a simple console application (using symfony/console component) to list the database tables (using zendframework/zend-db‘s Metadata). Let’s start.

First we need our composer.json file. We can find our Symfony components at Packaist (that’s means we don’t need to do anything special in the composer.json file), but Zend Framework2 has its own repository. No problem, it’s properly described in the documentation:

{
    "repositories": [
        {
            "type": "composer",
            "url": "http://packages.zendframework.com/"
        }
    ],
    "require": {
        "symfony/console":"dev-master",
        "zendframework/zend-db":"2.0.*"
    },
    "autoload":{
        "psr-0":{
            "":"lib/"
        }
    }
}

Now we run composer install (as always) and we already have our components in vendor folder and the autoloader will properly include the files on demand. So we can work in our console application without any problem.

<?php
namespace GonzaloDb;

// file: lib/GonzaloDb/SchemeCommand.php

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

use Zend\Db\Sql\Sql;
use Zend\Db\Adapter\Adapter;
use Zend\Db\Metadata\Metadata;

class SchemeCommand extends Command
{
    protected function configure()
    {
        $command = $this->setName('GonzaloDb:listTables')->setDescription('list all tables');
        $command->addArgument('host', InputArgument::REQUIRED, 'DB Host');
        $command->addArgument('port', InputArgument::REQUIRED, 'DB Port');
        $command->addArgument('database', InputArgument::REQUIRED, 'DB name');
        $command->addArgument('username', InputArgument::REQUIRED, 'Username');
        $command->addArgument('password', InputArgument::REQUIRED, 'Password');

        $command->addOption('listFields', NULL, InputOption::VALUE_NONE, 'list table Fields');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $adapterParameter = array(
            'driver'   => 'PDO_Pgsql',
            'host'     => $input->getArgument('host'),
            'port'     => $input->getArgument('port'),
            'database' => $input->getArgument('database'),
            'username' => $input->getArgument('username'),
            'password' => $input->getArgument('password')
        );

        $adapter = new Adapter($adapterParameter);

        $metadata   = new Metadata($adapter);
        $tableNames = $metadata->getTableNames();
        foreach ($tableNames as $tableName) {
            $output->writeln("Table: <info>$tableName</info>");
            if ($input->getOption('listFields')) {
                $table = $metadata->getTable($tableName);

                foreach ($table->getColumns() as $column) {
                    $output->writeln('  <comment>' . $column->getName() . '</comment> -> ' . $column->getDataType());
                }
            }
        }
    }
}

We also can use unit tests within console applications:

<?php

// file: tests/SchemeCommandTest.php
/*
CREATE TABLE users(
  userid character varying(50),
  name character varying(100),
  email character varying(50),
    CONSTRAINT users_pkey PRIMARY KEY (userid)
);
 */
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use GonzaloDb\SchemeCommand;

class SchemeCommandTest extends \PHPUnit_Framework_TestCase
{
    private $command;

    public function setUp()
    {
        $application = new Application();
        $application->add(new SchemeCommand());

        $this->command = $application->find('GonzaloDb:listTables');
    }

    public function testListTables()
    {
        $commandTester = new CommandTester($this->command);
        $commandTester->execute(
            array(
                 'command'  => $this->command->getName(),
                 'host'     => '127.0.0.1',
                 'port'     => 5432,
                 'database' => 'mydb',
                 'username' => 'username',
                 'password' => 'password',
            )
        );
        $this->assertRegExp('/Table: users/', $commandTester->getDisplay());
        $this->assertNotRegExp('/name -> character varying/', $commandTester->getDisplay());
    }

    public function testListTablesAndFields()
    {
        $commandTester = new CommandTester($this->command);
        $commandTester->execute(
            array(
                 'command'      => $this->command->getName(),
                 'host'         => '127.0.0.1',
                 'port'         => 5432,
                 'database'     => 'mydb',
                 'username'     => 'username',
                 'password'     => 'password',
                 '--listFields' => TRUE
            )
        );
        $this->assertRegExp('/Table: users/', $commandTester->getDisplay());
        $this->assertRegExp('/name -> character varying/', $commandTester->getDisplay());
    }
}

And that’s all. Zend Framework2 increases or toolbox as developers and with the power of Composer we can start building applications very fast. I like it :)

Follow

Get every new post delivered to your Inbox.

Join 963 other followers