Blog List

William

How-to Install PHP 7.x, NGINX 1.9.x & Laravel 5.x

Step 1: Get a Server!

UPDATE: Directions updated for Ubuntu 16.04 from DigitalOcean.

This example was originally written for Ubuntu 14.04.3 provided by DigitalOcean and ServerHub.

Provision a new droplet, vps, server, whatever you’re using and once you have the login details, login to SSH!


When you’re at the root terminal copy/paste the commands below to get everything configured


 

Step 2: Add the PHP 7 & NGINX 1.9.x Repositories

Run the following commands, as root, to install the PHP 7 and Nginx 1.9.x repositories to your sources.list, add the key, update apt-get and install.

add-apt-repository ppa:ondrej/php

If you're missing add-apt-repository, like some plain systems are, install it and then add-apt-repository ppa:ondrej/php

apt-get install software-properties-common
apt-get install python-software-properties

then

echo 'deb http://nginx.org/packages/mainline/ubuntu/ trusty nginx' >> /etc/apt/sources.list
echo 'deb-src http://nginx.org/packages/mainline/ubuntu/ trusty nginx' >> /etc/apt/sources.list
wget -q -O- http://nginx.org/keys/nginx_signing.key | sudo apt-key add -

apt-get update
apt-get -y install nginx php7.0 php7.0-mysql php7.0-fpm php7.0-mbstring php7.0-xml php7.0-curl

After everything is installed you’ll need to configure both PHP 7 and Nginx 1.9.x to work together and to work with Laravel 5.2, it’s not to hard.

 

Step 3: Configure NGINX

The default config for Nginx isn’t that great, so let’s go ahead and move it then create a new one:

Please note: The config is written with a heredoc, if you copy/paste just the config be sure to remove the escaped $ (the \$).

mv /etc/nginx/conf.d/default.conf /etc/nginx/default.conf-bkup
cat <<EOF > /etc/nginx/conf.d/default.conf
server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /var/www/html/public;
    index index.php index.html index.htm;

    server_name localhost;
    charset   utf-8;

    gzip on;
    gzip_vary on;
    gzip_disable "msie6";
    gzip_comp_level 6;
    gzip_min_length 1100;
    gzip_buffers 16 8k;
    gzip_proxied any;
    gzip_types
        text/plain
        text/css
        text/js
        text/xml
        text/javascript
        application/javascript
        application/x-javascript
        application/json
        application/xml
        application/xml+rss;

    location / {
        try_files \$uri \$uri/ /index.php?\$query_string;
    }

    location ~ \.php\$ {
        try_files \$uri /index.php =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)\$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|svg|woff|woff2|ttf)\$ {
      expires 1M;
      access_log off;
      add_header Cache-Control "public";
    }

    location ~* \.(?:css|js)\$ {
      expires 7d;
      access_log off;
      add_header Cache-Control "public";
    }

    location ~ /\.ht {
        deny  all;
    }

}
EOF

Adjust settings like root and server_name for your desired project.

Now that you have a working config let’s update PHP 7 to work with Nginx 1.9.x.

 

Step 4: Configure PHP 7

For FPM we need to fix_pathinfo.

echo ‘cgi.fix_pathinfo=0’ >> /etc/php/7.0/fpm/php.ini
Restart Services 
mkdir -p /var/www/html
/etc/init.d/nginx restart
/etc/init.d/php7.0-fpm restart

That’s it for your basic web-server, Laravel 5.2 ready - now do some restarting and let’s install Laravel!
 

Optional: Install MySQL

I wasn't going to cover this but its so simple. I tend to stick my databases on remote servers and don't often do this on my web-servers, but you're more then welcome to.

apt-get -y install mysql-client mysql-server
mysql_secure_installation

 

Step 5: Installing Composer & Laravel

cd ~
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
cd /var/www/html
rm -f index.nginx-debian.html 
composer create-project laravel/laravel .

Then set permissions

chown -R www-data:www-data /var/www/html
chmod -R 775 /var/www/html/storage

That's it! Laravel is ready to go in /var/www/html - check your web-servers ip/hostname in a browser and if you're like me you'll see:

Conclusion

That’s all it takes to get a new server setup and running with PHP 7, Nginx 1.9.x, MySQL and Laravel 5.2.

Spend some time to optimize your nginx and fpm configs, 1gb ram tends to crap out at around 30 concurrents with this default setup. Don't forget to secure your setup as well!

 


William

Simple Laravel 5.1 Bootstrap 3 Login Form

The next step after I add RBAC is to actually make use of it, seed some defaults, apply the Laravel Example templates and get to testing.

After that, we always "make it look pretty", so lets...

Make It Look Pretty

I've designed 100's of login forms, advanced, basic, it's whatever the project needs. In this case I just want a really clean Bootstrap 3 login form. It doesn't need to do anything special, it just needs to be proper code.

Googling for "bootstrap 3 login form" lead me to a lot of examples. Most were custom Bootstrap 3, not default. Even Bootstraps examples weren't proper (no form-groups). 

I wanted something proper and default. So a really simple login Bootstrap Login Form for Laravel 5.1 is what I made.

Public Layout

I wrap all my auth features into a public layout, this is just a really generic wrapper for bootstrap and jquery. It requires the Html functions to be installed.

Create resources/views/layouts/public.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="keywords" content="@yield('keywords')">
    <meta name="author" content="@yield('author')">
    <meta name="description" content="@yield('description')">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <meta name="csrf-token" content="{{{ csrf_token() }}}">

    <title>@yield('title', 'My Website')</title>

    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"></script>
    <script src="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"></script>
    <link rel="stylesheet" property="stylesheet" href="assets/css/app.css">
    @yield('styles')
    @yield('head')
</head>
<body>
    @section('header')
    @show

    @yield('content')
 

    @section('footer')
    @show

  <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
  <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
  <script src="assets/js/app.js"></script>
  @yield('scripts')
</body>
</html>

Login Form 

Now create resources/views/auth/login.blade.php

@extends('layouts.public')

@section('content')
<div class="container-fluid">
  <div class="row">
    <div class="col-sm-4 col-sm-offset-4">
      <h2>Please sign in</h2>

      <form method="post" action="{{ url('/auth/login') }}">
        {!! csrf_field() !!}

        <div class="form-group">
          <label for="exampleInputEmail1">E-mail address</label>
          <input type="email" class="form-control" id="exampleInputEmail1" placeholder="E-mail" name="email" value="{{ old('email') }}" required>
        </div>

        <div class="form-group">
          <label for="exampleInputPassword1">Password</label>
          <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" name="password" required>
        </div>

        <div class="checkbox">
            <label>
              <input type="checkbox" name="remember"> Remember me
            </label>
        </div>

        <div class="form-group">
          <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
        </div>

        <p class="text-center">
          <a class="btn btn-link" href="{{ url('/password/email') }}">Forgot Your Password?</a>
        </p>

        @if (count($errors) > 0)
          <div class="alert alert-danger">
            <strong>Whoops!</strong> There were some problems with your input.<br><br>
            <ul>
              @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
              @endforeach
            </ul>
          </div>
        @endif

      </form>
    </div>
  </div>
</div>
@endsection

That's It!

I'm not going to tell you how to implement authentication or the views or anything. This is just an example form and layout you can use. Pretty plug in play if you read the docs.

Conclusion

It's easy to add a basic auth system to Laravel 5.1. In around an hour I had a RBAC package integrated and was properly restricting access to my routes. Making a simple login form, that others can easily change, is required for my project so I hope this helped you.

Update

Of course Laravel 5.0 had some decent views already, gg taking it out.

Update v2

Laravel 5.2 has some really good views for this, saving lot's of time. I've updated the example to not use the {{Html}} tags, hope it helps

 

 


William

Laravel Validaton: All Your Base Are Belong To Us

We all use Laravels Validation feature to ensure we have the required input and it matches some sort of rule. The available rules cover plenty of situations but they fail to cover one of the most important rules, input Sanitization.

TL;DR

A typical validator

Laravels Auth system comes with a simple User model that provides validation of the users details before it's inserted into your database. We see it like:

return Validator::make($data, [
    'name' => 'required|max:255',
    'email' => 'required|email|max:255|unique:users',
    'password' => 'required|min:6|confirmed',
]);

These rules will ensure the data we need is there and of the desired length and type. 

That's it, we're done! Nothing else to check, required and max made sure our data is safe, right?

But wait, there's more

Don't go yet, come back and clam your prize. A dirty database.

That's a really cool user name there isn't it?

Since you only required the name and made sure it was 255 chars or less the "user" was allowed to input anything they wanted, in this case a pretty 'hello world' alert loop that crashes Firefox.

Buy now and we'll double your order

Double up your dirty database with any type of unescaped output of the users name and let the magic begin.

If as in magic you mean things users will exploit.

The User Auth example escapes all of the strings with {{ }} before displaying to the user so there wont be much magic going on with that example.

If you defined a variable, even escaped, within a <script> or html <=""> tag your ticket to the magic show is valid, so watch out. Even escaped outputs can trigger XSS and other attacks when used improperly.

It's 2016, you probably have an API

Did you do any validation on the output from the API? Most APIs for Laravel allow you to transform your data, if you didn't sanitize your output in the transformation then what the user provided is sent to your frontend. 

Did you sanitize the output in your frontend? Well if you didn't, congrats, your entrance to the magic show has been granted. Be prepared to be amused.

Hurry, while supplies last

You can easily close the door on exploits and dirty databases by properly validating and sanitizing your users input.

Whitelisting, mmmm.

If you validate user input against a whitelist you ensure you get only the data you want. A simple alpha_num or regexp can often do the trick.

This works great when you need to allow HTML or need a very specific type of value.

It's not very practical for all of your fields.

For those generic fields that can accept almost anything (like utf8 and unicode) another solution may work better for you. Sanitizing

Sanitizing the users input will help prevent the user from inserting possible exploits and mucking up your database.

It's not as fool proof as a whitelist but it is the most recommended method I've seen over the years.

Many people sanitize their inputs with htmlspecialchars, some like strip_tags but I prefer HTMLPurifier.

Note: 'mews/purifier' does allow some HTML in the inputs by default, you can adjust this in its config.

Your order has shipped

Unbox it and start putting it together. The inputs are yours so you'll need to decide what method to choose.

composer require daylerees/sanitizer
composer require mews/purifier

app/Http/routes.php

<?php
Route::get('/', function () {

    $validator = app('validator')->make(request()->all(), [
               'title' => 'filter:clean|required|max:255',
               'body' => 'required',
    ]);
    
    return $validator->fails() ? $validator->errors() : 'pass';
});

app/Providers/AppServiceProvider.php

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{

    public function boot()
    {
        app('validator')->extend('filter', function ($attribute, $value, $parameters, $validator) {
            $data = [$attribute => $value];
            app('sanitizer')->sanitize([$attribute => $parameters], $data);
            $replace = array_merge($validator->getData(), [$attribute => $data[$attribute]]);
            request()->replace($replace);
            $validator->setData($replace);
            return true;
        });
    }

    public function register()
    {
        app()->register('Rees\Sanitizer\SanitizerServiceProvider');
        app()->register('Mews\Purifier\PurifierServiceProvider');
    }
}

Don't return this item to the store, we can help

If you can't tell what's going on, no worries. 

The ServiceProvider is extending the validator class with a 'filter' option that can be accessed in your validation rules:

'title' => 'filter:clean|required|max:255',

You can use multiple filters:

'title' => 'filter:clean,htmlspecialchars|required|max:255',

You can create custom filters:

app('sanitizer')->register('sanitize_string', function ($field) {
    return htmlspecialchars($field);
});

$validator = app('validator')->make(request()->all(), [
           'title' => 'filter:sanitize_string|required|max:255',
           'body' => 'required',
]);

You can use it any way Dayle intended with his Sanitizer package.

Conclusion

Sanitizing inputs in Laravel is far from a new topic. It's been talked about recently and at one point even had some code started. 

found plenty of articles talking about it, new and old, but they all had some extra steps or classes, nothing short and to the point.

I don't want to define more rules. I want to sanitize when I validate and in the same manner as validation.

The ideas from #42 lead me to using the Sanitizer package with Validator, a simple combination that allows me to do pretty much anything I want with my inputs.

 

 

 

 


William

A Simple PHP SSH Wrapper for Background Commands

TL;DL

Just check out the fucking gist.

I can read a little..

A long time ago I never ran background commands. Everything I did was in that instance and omg was it slow.

My main software does a lot of systems tasks, many of them are instant, but some really do take ages - 20-30mins to run - so we can't expect a web-server, php - or a user ffs, to wait for that.

So wtf did you do?

I put that in a SCREEN. Made life much easier, pretty easy to run, log, inject into and monitor. It's so simple it really only takes a few lines of bash scripting to make it happen.

Now with my software we do all the remote connections with sockets so I never needed it with SSH. But these days the software automatically installs itself using the PHP-SSH2 extension, it's pretty easy to use and automated an entire process for us.

I started once again with instant execution and once I tossed in a 'yum update' and installed java, gd that age old issue was back.

Doing it with PHP-SSH2

I had alread written a simple class to manage ssh login, logout and execution, it was easy to add a couple more functions to run and monitor a screen.

If you've read anything on asked.io you'll know I'm not about to tell you what the fuck I did, ffs that'd take ages. Learn by example is how I roll, the example is this - maybe it has some shit that helps you - maybe it doesn't. 

<?php

class SSH{
  var $host='';
  var $port='';
  var $user='';
  var $pass='';
  var $connection='';
  var $sudo='';
  var $authed=false;

  public function __construct($host, $port, $user, $pass){
    $this->host=$host;
    $this->port=$port;
    $this->user=$user;
    $this->pass=$pass;

    if($user != 'root') $this->sudo="echo '$pass' | sudo -S ";
    
    $this->Connect();
    $this->Auth();
  }

  public function __destruct(){
    $this->Execute('exit');
  }

  public function Connect(){
    $this->connection = ssh2_connect($this->host, $this->port);
  }

  public function Auth(){
    if(!$this->connection) return false;
    $this->authed = ssh2_auth_password($this->connection, $this->user, $this->pass);
  }

  public function Execute($command, $return=false){
    if(!$this->authed) return false;
    $stream=ssh2_exec($this->connection, $this->sudo.$command); 
    stream_set_blocking( $stream, true ); 
    if($return) $cmd = fread($stream, 8096);
    fclose($stream); 
    if($return) return trim($cmd);
  }

  public function Screen($command, $screen){
    $screenlog="/root/.screenrc.watch$screen";
    $screencontent= "logfile /root/screenwatch$screen.log\nlog on";

    $this->Execute("printf '$screencontent' > $screenlog", true);
    return $this->Execute("screen -c $screenlog -mdLS screenwatch$screen bash -c \"$command\"", true);
  }

  public function Watch($screen){
    $screenStatus=$this->Execute("screen -wipe > /dev/null ; screen -list | grep screenwatch$screen | awk -F . '{ print $1 }' | sed -e s/.//", true);
    $screenLog=$this->Execute("cat ~/screenwatch$screen.log", true);

    return array((int) $screenStatus, $screenLog);
  }
}
?>

 



William

Quick Start Guide: Laravel 5, vue.js & Bootstrap 3

Vue.js has been getting a lot of attention lately so I've decided to give it another look in a new application I'm building. Vue.js is fast, small and easy to use, so why not give it a shot!

Since I'm a Laravel kinda guy I needed to configure vue with L5 and I always use Bootstrap, so that was needed as well. 

 

Did I say Laravel?

I did! So if you don't have a project, make one!

composer create-project --prefer-dist laravel/laravel .

 

Configure: package.json

Edit the package.json file in your projects folder and make it read:

{
  "private": true,
  "devDependencies": {
    "gulp": "^3.8.8"
  },
  "dependencies": {
    "bootstrap-sass": "^3.0.0",
    "laravel-elixir": "^4.0.0",
    "vue": "^1.0.18",
    "vue-resource": "^0.7.0"
  }
}

 

Install

Don't have npm? Install node.

npm install --global gulp
npm install

 

Edit: resources/assets/sass/app.scss

Uncomment the @import.

@import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap

 

Create: resources/assets/js/app.js

You'll be storing your vue.js, or any other js, here.

import Vue from 'vue'

new Vue({
  el: 'body',
  data: {
  message: 'Hello Vue World!'
  }
})

 

Append: gulpfile.js

Add the mix for scripts and set versioning up.

elixir(function(mix) {
    mix.sass('app.scss');
});

elixir(function(mix) {
    mix.browserify('app.js');
});

elixir(function(mix) {
    mix.version(['css/app.css', 'js/app.js']);
});

Gulp it

Compile all your crap into one css and one js file :D

gulp

 

Edit: resources/views/welcome.blade.php

Add the css in the <head></head> tag.

<link rel="stylesheet" href="{{ elixir('css/app.css') }}">

Add the js before the </body> tag

<script src="{{ elixir('js/app.js') }}"></script>

After the .title div add the div for your message.

<div class="title">Laravel 5</div>
<div id="app">
  @{{ message }}
</div>

 

Test it

php artisan serv

Load http://localhost:8000 and you'll see `Hello Vue World!`

Conclusion

5mins later you now have vue.js, bootstrap and laravel all configured. This guide won't go into any details because that's up to you to figure out. You now have a working base to develop as you desire, so enjoy!

 

 


William

Using Bootstrap 3 Less or SCSS with Elixir

I recently wrote an article about How-to setup Laravel 5, VueJs, and Bootstrap 3 and was asked:

My how-to didn't cover anything about that so here I will discuss how-to enable and modify Bootstrap 3 variables with Laravel 5 and Elixir.

Step 1: Create a project

In your terminal:

composer create-project --prefer-dist laravel/laravel .


Step 2: Install Gulp

Don't have npm? Install node.
In your terminal:

npm install --global gulp
npm install


Step 3: Less or SCSS?

The choice is yours. Bootstrap 3 is compiled with Less, not SCSS, but SCSS is included by default in Laravel 5s gulpfile.js - I prefer Less over SCSS.

Bootstrap 3 SCSS

Edit: resources/assets/sass/app.scss
Make it read:

@import "_variables.scss"
@import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap

Create: resources/assets/sass/_variables.scss
Define what variables you would like to adjust, ie:

$brand-primary: #000;

 

Bootstrap 3 Less

Install bootstrap:
In your terminal:

npm install bootstrap


Create: resources/assets/less/app.less
Make it read:

@import "node_modules/bootstrap/less/bootstrap.less";
@import "variables.less";

Create: resources/assets/less/variables.less
Define what variables you would like to adjust, ie:

@brand-primary: #000;

Edit: gulpfile.js
Change:

elixir(function(mix) {
    mix.sass('app.scss');
});

To:

elixir(function(mix) {
    mix.less('app.less');
});


Step 4: Compile


Now that you've enabled the less or scss versions you need to compile everything into app.css.
In your terminal:

gulp

 

Step 5: Link to your stylesheet

Edit your template and in the head tag add:

<link rel="stylesheet" href="{{ asset('css/app.css') }}">

Make some changes to check if your variables worked, like adding a class="text-primary" somewhere.

 

Step 6: Test

Make some changes to check if your variables worked, like adding a class="text-primary" somewhere.
I edited resources/views/weclome.blade.php and changed the title tag for a quick test:

<div class="title bg-primary">Laravel 5</div>

Load up your test server and see if it works.
 

php artisan serv

Load up your browser and you'll see:

Making Changes

I suggest looking at the less source and searching for the features you want to adjust.

Editing a navbar? You'll want to adjust colors and maybe the navbar.

If we look at navbar.less we'll see what it takes to build a Bootstrap 3 nav. Find what you want to edit - and make the changes.
For example making changes to the navbar-default:

.navbar-default {
  background-color: #fff;
  border-color: #ccc;
}

Ideally you'd define #fff and #ccc as @brand-white and @brand-grey in your variables.css but this is just a quick example.

Follow the same nesting, folders and file names and @import your own classes to adjust how Bootstrap is rendered. 

When using Less your @includes are after the Bootstrap include, when using SCSS they go before.

These steps work for SCSS as well, just adapt .less to .scss and the way you define variables.

Don't forget to compile your changes with gulp, you can use gulp watch and browserify to help as well.


Conclusion


Trying to modify Bootstrap 3 CSS is a huge pain. Trying to modify it with Less, plain and simple. Find what you want, copy/paste/edit/save, bam - you've made it look like what you want.

I cut my Bootstrap 3 template development time in half by switching to Less and compiling in my changes. I also was able to create highly optimized versions of Bootstrap that only utilized exactly what I needed with little effort.

I am not certain why Laravel 5 ships with Bootstrap 3 SCSS, it's a port - and not how Bootstrap is compiled. I would suggest using what Bootstrap 3 uses and that's Less. 

 


William

Laravel 5.2 Creating a New User

I recently started a Analytics program in Laravel 5.2 and was very pleased to find the auth system back in play and extreamly easy to use.

It didn't seem to come with any database seeders or commands to add users but seeding is nothing magical and the docs even had a great example.

Creating a user in Laravel 5 with a Seed File

Not to hard, you could use the docs example - or if you're like me - you just want a quick copy/paste to add a user with the details you've defined, so here it is:

UserSeeder, add a user to the users table.

Create a seed file in database/seeds, like database/seeds/UserSeeder.php.

<?php

use Illuminate\Database\Seeder;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('users')->insert([
            'name' => 'admin',
            'email' => '[email protected]',
            'password' => bcrypt('password'),
        ]);
    }
}

Update your autoload

composer dumpautoload

Run artisan to add the new user to your database

php artisan db:seed --class=UserSeeder

 

Conclusion

I'm super happy the auth system is back in 5.2, it looks good - works well - just needed to seed a user and I'm logged in. It'd be nice to write an article with a seed command, so maybe later!



William

100 PageSpeed GTMetrix Pingdom Scores with Laravel

 

 

Want to get a 100 Page Speed Insight Score?

How about GTMetrix & Pingdom?

Sure, why not?!
 

This article will help boost your Laravel based web-sites ratings if you follow a few simple steps.

 

 



The Testing Tools

We'll be using the following tools for testing.

developers.google.com/speed/pagespeed/insights/

gtmetrix.com

tools.pingdom.com/fpt/

Test your site before you begin and make note of your base line scores.

 

 

 

Picking a Design

If a high score is your priority your design may need some re-working. Heavy css and javascript will need refactoring to be smaller, certain features like Google Maps and other 3rd party tools could cause errors and many other things could make it more difficult to increase your rank.

Try picking a template that is well coded, doesn't use many plugins and has good css/js. I used Clean Blog for this example because it was simple and well made.

Placing it on my gzip/cached enabled Nginx server..

You can see it scored well on GTMetrix

But not so good on Mobile Page Speed Insights

 

Eliminate render-blocking JavaScript and CSS in above-the-fold content

Minify JavaScript

 

 

Easy fixes - if we do a few things.

 

We want to fix these errors and any errors on your template. The first place to start is the web-server.

 


 

Configure The Web-server

Your web-server controls gzip and cache settings.

Both are required for a high ranking score.

 

 

Read my guide for a complete Nginx, PHP 7 and Laravel 5 setup.

 

(You can install the Google Page Speed Module for Apache or Nginx, it will resolve most of your issues without reading anything else in this article, so go grab a beer)

 

Run Apache? Use this .htaccess   Nginx? Use this default.conf 

 

No matter the web-server the two things you need to do are...


 

Caching

Enable caching on js/css/images for at least 7 days.

 

Gziping

All files need to be gziped, enable it and add the correct mime types.

 

These two settings are an easy way to boost your Page Speed Score!

 

 


 

Configure Laravel

Minify html, css, javascript & cache 3rd party resources .

 

 

Minify CSS/JS

You can use Elixir to minify and combine your css/js. 

If you don't want to use Elixir you'll need to manually minify and combine your css/js (or use another method).

 

Minify HTML

You can use my package to automatically minify your HTML at a high level to pass validation.

There are a few other html minifier options for Laravel 5 but none would pass validation.
 

Cache 3rd Party Resources

Google Analytics sets a low cache time and Page Speed Insights requires a long one. Temporarily caching this script has not known to cause any problems.

You can use my package to have access to /cache/analytics.js that caches the script locally per client. Read more about it here

 

 


 

Tune-up the Template

Once the template is done, do some more!

 

So you have that fancy template, great! Now you need to put it  in Laravel. You already have Laravel installed so go get started!
 

First things first

Copy Assets

1) Copy the templates js/css asset folders into resources/assets/.

2) Copy the templates fonts folder into public/

3) Download all 3rd party resources like jquery & bootstrap into your resources/fonts folders.

 

When all of your assets are copied to resources create your gulpfile to combine them.

 

gulpfile.js

Review all the css and js that you can combine into 1 script, doing something like I did for Clean Blog you can combine and minify them easily.

elixir(function(mix) {
    mix.styles([
        'bootstrap.css',
        'clean-blog.css',
        'font-awesome.css',
    ], 'public/assets/css');
    mix.scripts([
        'jquery.min.js',
        'bootstrap.min.js',
        'clean-blog.js',
    ], 'public/assets/js/');
});

Then when you're ready to combine & minify them run:

gulp --production

 

 

Now we that we have minified css & js we need to update the code!

 

 

Update the HTML

Remove all the CSS link tags that you combined into all.css and replace it with the following.

<style><?php include app_path() . '/../public/assets/css/all.css' ?></style>

This will inline the style to help prevent content blocking errors. If you receive blocking errors try to combine your resources into two files and include one in the body.

Replace all the <script> tags that you combined with gulp to one script tag with a src of /assets/css/all.js

<script src="/assets/js/all.js"></script>

 

Optimize CSS

Remove any comments and extra stuff you don't use. Try to get the css as minimal and clean as possible so gulp will minify it the best it can.

Remove any fonts that have ? in the url() as this will error.

 

 

Optimize Images

Head on over to compressor.io and optimize all of your images, sure it's a pain, but it's worth it. If you're using a CMS, awesome, go install some plugin to do it for you.

 

 

Optimize Fonts

Optimizing fonts can save a ton of bandwidth and that results in a faster loading site. With Clean Blog I didn't bother to spend the 45mins to download google fonts and update the css and I couldn't find the automated script to do it, so I just took them out.

Here are my font pointers

  • Host all fonts locally
  • Provide a woff2 format for all fonts, place it first in your list
  • Second in list woff then down the line of all you wish to support
  • Google fonts? View the CSS, download the url() links as the fonts name and update the CSS to use locally

 

 



Walla! 100/100/100/100 

(Except for YSlow)

 

Why a 98 on Yslow? No CDN!

Since we can't control CDNs we don't always get something approved for these tests. Even s3 doesn't trigger as a CDN on YSlow so I generally disregard this error. Sure it's nice to offload things like jquery and bootstrap but you can't know for a fact the user will have them cached or the cdn will respond fast enough - so for high ranks this is actually good.

 

 



Conclusion

I've been getting high raking sites for a while now - I usually build them with it in mind and go back at the end to tune them up completly. It is very difficult to get every page on your site 100 and you will certainly drive yourself crazy. We accept anything over 95 as passing and are happy to see a lot of our sites at 98 and 100s. I'll continue to try and get the highest rank I can without going overboard.