Loading...
Loading...
Loading...
Loading...

How to Build a Superfast PHP Server in Minutes with Icicle

View: 794    Dowload: 0   Comment: 0   Post by: hanhga   Category: Php&mySql   Fields: Other

Event-based programming is a strange topic for PHP developers. In a language as procedural; events are little more than function calls. Nothing happens between events, and all meaningful code is still blocking.

Languages like JavaScript show us what PHP could be like if event loops were at the center. Some folks have taken these insights and coded them into event loops and HTTP servers. Today we’re going to create an HTTP server, in PHP. We’ll connect it to Apache to serve static files quickly. Everything else will pass through our PHP HTTP server, based on Icicle.

Icicles illustration

Configuring Apache

When browsers request existing files, it’s best to serve them without involving the PHP interpreter. Apache is fast and efficient at serving these files, so let’s configure it to handle all static file requests:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*) http://%{SERVER_NAME}:9001%{REQUEST_URI} [P]

You can place this code inside a virtual host entry.

These mod_rewrite directives tell Apache to send requests to missing files to a different port. In other words: when a browser requests example.com/robots.txt, Apache will first look to see if the file exists. If so, Apache will return it without spinning up the PHP interpreter. If not, Apache will send the request to http://example.com:9001/robots.txt.

A Simple HTTP Server

Icicle ships with an event loop. We can wrap an HTTP server around that, so new requests come to us in the form of events. Much of this process is abstracted away, but let’s take a look at an example anyway. To begin, let’s download icicleio/http:

composer require icicleio/http

This installed version 0.1.0 for me. If you’re having trouble getting my examples to work, you may have a newer version. Try installing this specific version.

This will allow you to run the following code:

// server.php

require __DIR__ . "/vendor/autoload.php";

use Icicle\Http\Message\RequestInterface;
use Icicle\Http\Message\Response;
use Icicle\Http\Server\Server;
use Icicle\Loop;
use Icicle\Socket\Client\ClientInterface;

$server = new Server(
    function(RequestInterface $request, ClientInterface $client) {
        $response = new Response(200);
        $response = $response->withHeader(
            "Content-Type", "text/plain"
        );

        yield $response->getBody()->end("hello world");
        yield $response;
    }
);

$server->listen(9001);

Loop\run();

Handling Different Routes

This is the most basic HTTP server one can create. It receives all requests and replies “hello world”. To make it more useful, we would need to incorporate some kind of router. League\Route seems like a good candidate:

composer require league/route

Now we can split up individual requests, and send more meaningful responses:

// server.php

use League\Route\Http\Exception\MethodNotAllowedException;
use League\Route\Http\Exception\NotFoundException;
use League\Route\RouteCollection;
use League\Route\Strategy\UriStrategy;

$server = new Server(
    function(RequestInterface $request, ClientInterface $client) {
        $router = new RouteCollection();
        $router->setStrategy(new UriStrategy());

        require __DIR__ . "/routes.php";

        $dispatcher = $router->getDispatcher();

        try {
            $result = $dispatcher->dispatch(
                $request->getMethod(),
                $request->getRequestTarget()
            );

            $status = 200;
            $content = $result->getContent();
        } catch (NotFoundException $exception) {
            $status = 404;
            $content = "not found";
        } catch (MethodNotAllowedException $exception) {
            $status = 405;
            $content = "method not allowed";
        }

        $response = new Response($status);
        $response = $response->withHeader(
            "Content-Type", "text/html"
        );

        yield $response->getBody()->end($content);
        yield $response;
    }
);

We’ve pulled in League\Route, and enabled the UriStrategy. It’s one of four different methods for determining which route belongs to which request. League\Route is often used alongside Symfony requests and responses. We’ll need to feed the request method and path/target to the dispatcher.

If a route is matched, we get a Symfony\HttpFoundation Response, so we get the body content withgetContent. If there isn’t a matching route, or an allowed method for a matching route, then we return the appropriate errors. So what does routes.php look like?

$router->addRoute("GET", "/home", function() {
    return "hello world";
});

Rendering Complex Views

Strings are fine for simple pages. But when we start to build more complex applications, we may need a better tool. How about we use League\Plates? It’s a template engine that adds things like layouts and template inheritance on top of plain PHP.

composer require league/plates

Then we’ll create a layout template, for all the views in our site to inherit from:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>
            <?php print $this->e($title); ?>
        </title>
    </head>
    <body>
        <?php print $this->section("content"); ?>
    </body>
</html>

This is from templates/layout.php.

The e method escapes HTML entities. The section method will be where the page content gets rendered:

<?php $this->layout("layout", ["title" => "Home"]); ?>
<p>
    Hello, <?php print $this->e($name); ?>
</p>

The above is from templates/home.php.

Finally, we change our /home route to return a rendered template instead of a simple string:

$router->addRoute("GET", "/home", function() {
    $engine = new League\Plates\Engine(
        __DIR__ . "/templates"
    );

    return $engine->render("home", [
        "name" => "Chris"
    ]);
});

The above is from routes.php.

Of course, we could create a shortcut function, to save us having to create the engine each time:

function view($name, array $data = []) {
    static $engine = null;

    if ($engine === null) {
        $engine = new League\Plates\Engine(
            __DIR__ . "/templates"
        );
    }

    return $engine->render($name, $data);
}

The above is from helpers.php.

… and if we include that (or add it to the Composer autoload definition), then our /home route becomes :

$router->addRoute("GET", "/home", function() {
    return view("home", [
        "name" => "Chris"
    ]);
});

Conclusion

We’ve managed to cobble together a reasonable application framework, using Icicle\Http and a couple of League libraries. Hopefully this has shown you that life outside of Apache (or Nginx) is possible. And that’s just the beginning…

I was able to get the following stats (while running Chrome and iTunes, on a 13” Macbook Pro Retina 2014)

Concurrency Level:    100
Time taken for tests: 60.003 seconds
Complete requests:    11108
Failed requests:      0
Total transferred:    3810044 bytes
HTML transferred:     2243816 bytes
Requests per second:  185.12 [#/sec] (mean)
Time per request:     540.182 [ms] (mean)
Time per request:     5.402 [ms] (mean, across all concurrent requests)
Transfer rate:        62.01 [Kbytes/sec] received

I imagine those figures will fluctuate as you add more complexity, and they don’t mean anything when compared to popular frameworks. The point is that this little event-based HTTP server can serve 11.1k requests in a minute, without failures. If you’re careful to avoid memory leaks, you can create a stable server out of this!

That’s exciting, isn’t it?

What are your thoughts about this setup? Have you played with Icicle yet? Let us know!

Edit: Aaron Piotrowski, the author of Icicle chimed in with some extra info on why the benchmark above may have been flawed (also discussed in the comments). Here are his (much more impressive) results. He says:

Concurrency Level:      100
Time taken for tests:   5.662 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      2650000 bytes
HTML transferred:       2020000 bytes
Requests per second:    1766.04 [#/sec] (mean)
Time per request:       56.624 [ms] (mean)
Time per request:       0.566 [ms] (mean, across all concurrent requests)
Transfer rate:          457.03 [Kbytes/sec] received

“I was able to get the following stats (while running iTunes, Chrome, and several other programs on a 3.4 GHz i7 iMac) using the command ab -n 10000 -c 100 http://127.0.0.1:9001/home:

How to Build a Superfast PHP Server in Minutes with Icicle

Event-based programming is a strange topic for PHP developers. In a language as procedural; events are little more than function calls. Nothing happens between events, and all meaningful code is still blocking.

Posted on 29-02-2016 

Comment:

To comment you must be logged in members.

Files with category

  • Twitter-like Hashtag Function in PHP

    Twitter-like Hashtag Function in PHP

    View: 116    Download: 0   Comment: 0

    Category: Php&mySql     Fields: none

    If you ever want a function to hashtag and style words within a string which has '#' next to it like twitter. This piece of code will help

  • PSITS Automated Voting System

    PSITS Automated Voting System

    View: 138    Download: 10   Comment: 0

    Category: Php&mySql     Fields: none

    A free sourcecode for PSITS Automated Voting System develop in PHP programming language. The purposed of the system is to automate the process of voting and maintain the quality of data

  • PHP-University Application System

    PHP-University Application System

    View: 135    Download: 13   Comment: 0

    Category: Php&mySql     Fields: none

    Greeting from Malawi the warm heart of Africa. I developed this university registration system project just to share with the people who can make use of the project like this and at the same time for others like students who can learn from it. This...

  • School Event Management System in PHP/MSQLi

    School Event Management System in PHP/MSQLi

    View: 125    Download: 0   Comment: 2

    Category: Php&mySql     Fields: none

    This School Event Management System can create school events such as Volleyball games, Basketball, Cultural presentation, Election of school officers etc . During school election Instead of having a compile list of candidates and voters this system...

  • Resort Reservation System with PayPal/Credit Card/Debit Card Payment

    Resort Reservation System with PayPal/Credit Card/Debit Card Payment

    View: 117    Download: 0   Comment: 0

    Category: Php&mySql     Fields: none

    This reservation system has the ability to help its customers find available rooms, cottages and even function hall for their convenience . And in here, they will also have the idea of the room rates where they can quickly reserve for their family...

  • Activity log

    Activity log

    View: 125    Download: 0   Comment: 0

    Category: Php&mySql     Fields: none

    Simple program to track user's activity log-in time and online/offline status.

  • Electricks - eCommerce

    Electricks - eCommerce

    View: 119    Download: 0   Comment: 0

    Category: Php&mySql     Fields: none

    Electricks is an e-commerce website built using PHP, Bootstrap and some jQuery plugins. It has all the major functionalities of a typical e-shop. This project was used to present in Southern Luzon State University - Lucban. Feel free to use this code...

  • Simple Email App Using PHP

    Simple Email App Using PHP

    View: 102    Download: 1   Comment: 0

    Category: Php&mySql     Fields: none

    Creating a simple PHP script using mail function for sending out emails.

 
File suggestion for you
File suggestion for you
File suggestion for you
File suggestion for you
Loading...
Loading...
Loading...
Loading...
File top downloads
File top downloads
File top downloads
File top downloads
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Codetitle - library source code to share, download the file to the community
Copyright © 2018. All rights reserved. codetitle Develope by Vinagon .Ltd