Prototype Quickly in Laravel with PHP’s Built-In Server and SQLite

Learn how to speed up Laravel development using the built-in PHP server and SQLite.

If you are a seasoned Laravel developer, you know the usual project setup drill that involves creating a new project, a fresh database, and adding a virtual host entry to Apache.

If you are starting from scratch, the Apache and MySQL installation can take some time and slow things down for you.

However, I will show you how you can jump start your Laravel development without Apache and MySQL.

During the course of this article, you will learn how to:

  1. Use the PHP server by itself.
  2. Run your Laravel application with the PHP server.
  3. Integrate SQLite into your Laravel application.

The PHP Web Server

As of version 5.4.0, PHP provides a built-in webserver that can be used to run your PHP applications without setting up any webserver software. Under controlled environments, this works well for testing and demonstration but be advised, it is not intended to replace a fully functional web server.

If you are interested in the technical details, you can have a look at PHP's documentation

Using the Built-in PHP Server

Let's execute a simple PHP script to understand how this works.

Fire up your code editor and create an index.php file.

<?php
phpinfo();
?>

In the terminal, move to the location where you just created your index.php file and summon the PHP server.

$ cd /Volumes/Work/PHP/Server_Example/public_html
$ php -S localhost:8000
PHP 5.5.31 Development Server started at Wed Apr 20 20:46:29 2016
Listening on http://localhost:8000
Document root is /Volumes/Work/PHP/Server_Example/public_html
Press Ctrl-C to quit.

In your browser, navigate to http://localhost:8000 and you should see the ever famous, nicely formatted PHP's running configuration page.

Let's throw in a little old-fashioned routing into the equation and see how things go.

Create another file named router.php

switch ($_SERVER["REQUEST_URI"]) {
    case "/about":
        echo "<p style=\"text-align:center;\">This is the about page</p>";
        break;
    case "/portfolio":
        echo "<p style=\"text-align:center;\">This is the portfolio page</p>";
        break;
    case "/contact":
        echo "<p style=\"text-align:center;\">This is the contact page</p>";
        break;
    default:
        echo "<p style=\"text-align:center;\">This is the index page</p>";       
}

This script uses a simple switch statement to echo content based on the URL. You can navigate to these URLs by appending /about, /portfolio, and /contact to http://localhost:8000. Any URL that does not match will fire the default case and show the index page's content.

Execute the PHP server again but this time, also specify router.php as the routing file.

$ php -S localhost:8000 router.php 
PHP 5.5.31 Development Server started at Wed Apr 20 21:55:52 2016
Listening on http://localhost:8000
Document root is /Volumes/Work/PHP/Server_Example/public_html
Press Ctrl-C to quit.

This exercise in routing shows you can do pretty much anything based on the URL that is requested by the client.

Do frameworks employ this neat trick to fire the requested controller and action?

Using the Server with Laravel

I wish professional software development was as simple as throwing a phpinfo page to the built in PHP server. Most of the time, you work with frameworks that have a number of files. You can easily get confused with which file to execute with the PHP server.

Do you simply run it at the root of your project and hope for the best?

Luckily, Laravel has Artisan's serve command that executes your application and spares you the headache.

To run your Laravel application with the PHP server, simply execute the following command at the root of your project.

$ php artisan serve
Laravel development server started on http://localhost:8000/

Artisan's serve command uses localhost, 8000, and development as the default host, port, and environment respectively. You can specify a different host, port, and environment using command line parameters.

$ php artisan serve --host="www.scotch.io" --port=3000 --env="development"
Laravel development server started on http://www.scotch.io:3000/

In case you specify a host other than localhost, you should have it's entry in your /etc/hosts file.

Here is how it should look like in case of the above host as a command line parameter.

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             localhost

# entry for command line host parameter
127.0.0.1       www.scotch.io

Artisan's Serve Command - The Deep Dive

Let's peek under the hood to figure out how the serve command works.

The serve command actually executes the server.php file which is at the root of your project.

<?php

/**
 * Laravel - A PHP Framework For Web Artisans
 *
 * @package  Laravel
 * @author   Taylor Otwell <taylorotwell@gmail.com>
 */

$uri = urldecode(
    parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
);

//echo $uri;
//echo __DIR__.'/public'.$uri;

// This file allows us to emulate Apache's "mod_rewrite" functionality from the
// built-in PHP web server. This provides a convenient way to test a Laravel
// application without having installed a "real" web server software here.
if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
    return false;
}

require_once __DIR__.'/public/index.php';

Other than simple URL parsing, the interesting bit is the if block. It simply makes sure that the url is not root / and a static asset has not been requested in which case it will simply serve the asset.

If the if conditional fails, the index.php file in the public directory is executed which simply creates the Laravel app, invokes a Kernel instance and passes it the request to handle.

<?php

/**
 * Laravel - A PHP Framework For Web Artisans
 *
 * @package  Laravel
 * @author   Taylor Otwell <taylorotwell@gmail.com>
 */

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels nice to relax.
|
*/

require __DIR__.'/../bootstrap/autoload.php';

/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/

$app = require_once __DIR__.'/../bootstrap/app.php';

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send();

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

Notice the Request::capture() method, that is where all the magic to create the request happens.

Enter SQLite

Since it is nice to have the built-in PHP server to quickly spin an application, you would wonder if there also a way to skip the MySQL installation.

Lucky for us, there is.

If you are not familiar with SQLite, here is a short description from the official website.

SQLite is an in-process library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine.

What this means is the database runs off from a single file on your storage. If you have the required libraries, you can communicate with the stored file just like you would normally talk to a database server.

SQLite is an open source project so there are plugins available for popular languages such as PHP, Ruby, Python, and Java.

Using SQLite with Laravel

Laravel supports SQLite databases out of the box. With a little configuration, you can create applications that do not require a back-end database server.

The first step in your configuration will be to create a SQLite database file named database.sqlite. I will create it inside the database directory which is at the root of your project. Ofcourse you can create your SQLite database anywhere but it is nice to keep things neat and in one place.

Execute the following commands at the root of your project.

$ cd database
$ touch database.sqlite

The next step is to set the database related environment variables in the .env file at the root of your project.

DB_CONNECTION=sqlite
DB_DATABASE=/Volumes/Work/PHP/Laravel-Sandbox/database/database.sqlite

The DB_CONNECTION and DB_DATABASE are the only variables required to configure SQLite for your project.

Though you have only set the DB_CONNECTION and DB_DATABASE variables, you will also notice a bunch of other database related variables such as DB_HOST and DB_PORT. You can ignore them for now as we will revisit them later to see how easy it is to switch back to MySQL.

The final step is to set the configuration in the database configuration file.

Add the following sqlite key to the connections array in your config/database.php file.

'sqlite' => [
    'driver' => 'sqlite',
    'database' => env('DB_DATABASE', database_path('database.sqlite')),
    'prefix' => '',
],

Notice the database_path function which is a helper provided by Laravel to construct a path to a file which resides inside the database directory. It is used to specify a default path in case the environment variable DB_DATABASE is not set.

Your application is ready to use SQLite as the backend database.

Running the Users Table Migration

As a test to make sure SQLite has been setup correctly, you are going to execute the users table migrations that are packaged with Laravel.

In your terminal, execute the following commands.

$ php artisan migrate:install --env=local
Migration table created successfully.

$ php artisan migrate --env=local
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table

All migrations were run successfully and the respective tables were created.

Here's the look at all the tables in our SQLite table:

Laravel Artisan Migrate SQLite Table

Here are the migrations, password_resets and users tables:

Laravel Artisan Migrate Migrations Table Laravel Artisan Migrate Password Resets Table Laravel Artisan Migrate Users Table

I am using Navicat for SQLite on OSX to view the contents of the SQLite database. You can download Navicat for your OS and follow the installation instructions. Once you are done with the installation, simply run Navicat and open the SQLite database file.

Switching Back to MySQL

If at any point during your project, you feel SQLite is not just cutting it out for you, you can switch to MySQL within a matter of seconds.

First, set the DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, and DB_PASSWORD variables in your .env file.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<YOUR-DATABASE-NAME>
DB_USERNAME=<YOUR-DATABASE-USERNAME>
DB_PASSWORD=<YOUR-DATABASE-PASSWORD>

Next, add the following mysql key to the connections array in your config/database.php file.

'mysql' => [
    'driver' => 'mysql',
    'host' => env('DB_HOST', 'localhost'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix' => '',
    'strict' => false,
    'engine' => null,
],

And you are done!

MySQL vs SQLite - A Brief Comparision

You can skim through countless articles and comparisions that conclude why MySQL is better than SQLite and vice versa but there is always a trade-off involved. As they say, use the right tools for the job as there is no one-size fits all in the field of Computer Sciences.

The table below compares both databases and will help you make the right call when embarking on your next project.

SQLite MySQL
There is almost zero setup effort involved. All you need are the SQLite libraries. Deployment effort is minimal. The installation requires configuration so you should know your way around all the configuration variables involved. Deployment will require a similar execise in configuration.
It is suitable for standalone applications that run under single user setup like desktop and mobile applications. It is suitable for multiple users and highly concurrent applications.
When it comes to optimization, you cannot do much more than it's already amazing performance. There are a lot of options available for optimization if you wish to tinker with your setup.
No administration expertise required. All you need to do is backup your database file. Database administration is a vast area, so much so that some people make a career out of it.
You cannot manage user access and privileges as there are no user management features available. You can control user authentication and authorization at a very granular level.

Using SQLite for Production Servers

Before I comment on this, I would like to quote an excerpt from the official SQLite website.

SQLite works great as the database engine for most low to medium traffic websites (which is to say, most websites). The amount of web traffic that SQLite can handle depends on how heavily the website uses its database. Generally speaking, any site that gets fewer than 100K hits/day should work fine with SQLite. The 100K hits/day figure is a conservative estimate, not a hard upper bound. SQLite has been demonstrated to work with 10 times that amount of traffic.

The SQLite website (https://www.sqlite.org/) uses SQLite itself, of course, and as of this writing (2015) it handles about 400K to 500K HTTP requests per day, about 15-20% of which are dynamic pages touching the database. Each dynamic page does roughly 200 SQL statements. This setup runs on a single VM that shares a physical server with 23 others and yet still keeps the load average below 0.1 most of the time.

As you can see, the argument mostly focuses on the number of users your application is engaged with. However, modern web application development is much more complex than just taking into account the traffic it serves.

For a start, most of the web applications are deployed with a separate database user that is granted only as much privileges on the database as are required by the application. SQLite would fail this test alone as stated previously, there are no user management features available.

The Final Verdict

In this tutorial, you saw how easy it is to get Apache and MySQL out of the equation and quickly start prototyping your Laravel application with the built-in PHP server and SQLite.

Just as you would not use the PHP server in a production environment, you should not use SQLite in a production environment because of the limitations already discussed.

This is a fast way to start tinkering away with a Laravel application. Then once you feel your application is ready for the bigger leagues, go ahead and switch over to MySQL.

I hope you found this tutorial interesting and knowledgeable. Until my next piece, happy coding!

Noman Ur Rehman

I am a full stack, freelance web developer who specializes in Laravel, Rails, and Amazon Web Services. I love Regular Expressions and discussing ideas.