Web Development

CakePHP 3+ .htaccess for troublesome servers

The Ideal .htaccess for CakePHP, with File Compression and Expires headers.

Enable either mod_gzip or mod_deflate for compression.

<IfModule mod_rewrite.c>
	RewriteEngine On	
	Options +FollowSymLinks
	RewriteCond %{REQUEST_FILENAME} !-d
	RewriteCond %{REQUEST_FILENAME} !-f
	# enable symbolic links
	RewriteCond %{REQUEST_FILENAME} !-l
	RewriteRule ^(.+) index.php [L]

<ifModule mod_gzip.c>
# mod_gzip_on Yes
# mod_gzip_dechunk Yes
# mod_gzip_item_include file .(html?|txt|css|js|php|pl|ctp)$
# mod_gzip_item_include handler ^cgi-script$
# mod_gzip_item_include mime ^text/.*
# mod_gzip_item_include mime ^application/x-javascript.*
# mod_gzip_item_exclude mime ^image/.*
# mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*

<IfModule mod_deflate.c>
        # Insert filter
        SetOutputFilter DEFLATE

        # Netscape 4.x has some problems...
        BrowserMatch ^Mozilla/4 gzip-only-text/html

        # Netscape 4.06-4.08 have some more problems
        BrowserMatch ^Mozilla/4\.0[678] no-gzip

        # MSIE masquerades as Netscape, but it is fine
        # BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

        # NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
        # the above regex won't work. You can use the following
        # workaround to get the desired effect:
        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html

        # Don't compress images
        SetEnvIfNoCase Request_URI \
        \.(?:gif|jpe?g|png)$ no-gzip dont-vary

        # Make sure proxies don't deliver the wrong content
        Header append Vary User-Agent env=!dont-vary

<IfModule mod_expires.c>
	ExpiresActive On
	ExpiresByType image/jpg "access 1 year"
	ExpiresByType image/jpeg "access 1 year"
	ExpiresByType image/gif "access 1 year"
	ExpiresByType image/png "access 1 year"
	ExpiresByType text/css "access 1 month"
	ExpiresByType text/html "access 1 month"
	ExpiresByType application/pdf "access 1 month"
	ExpiresByType text/x-javascript "access 1 month"
	ExpiresByType application/x-shockwave-flash "access 1 month"
	ExpiresByType image/x-icon "access 1 year"
	ExpiresDefault "access 1 month"


Web Development

Create SEO Friendly urls with this Slugify PHP Method

	 * slugify
	 * @param string $str
	 * @return mixed
	 * Converts nasty URLs to clean, SEO friendly ones
	public function slugify($str) {
	    $clean = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $str);
		$clean = strtolower(trim($clean, '-'));
		$clean = preg_replace("/[\/_|+ -]+/", '-', $clean);
		return $clean;


Web Development

CakePHP3 User Authorisation with Cake Bake

Create Users Table:

`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`role` varchar(20) DEFAULT NULL,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,

In Terminal, Cake bake the MVC

bin/cake bake model users && 
bin/cake bake controller users && 
bin/cake bake template users &&
bin/cake bake controller --prefix admin users && 
bin/cake bake template --prefix admin users

Load Auth component in App Controller Initialize method:

public function initialize()
    $this->loadComponent('Auth', [
    'loginRedirect' => [
    'controller' => 'Users',
    'action' => 'index',
    'prefix' => 'admin'
    'logoutRedirect' => [
    'controller' => 'Pages',
    'action' => 'display',

Set up password hashing to encrypt the password by going to Model->Entity->User.php

Add the PasswordHasher library after the namespace

use Cake\Auth\DefaultPasswordHasher;

Add the password hasher method:

protected function _setPassword($password)
    return (new DefaultPasswordHasher)->hash($password);

Add BeforeFilter, Login and Logout method to App Controller

public function beforeFilter(Event $event)
    // Allow users to register and logout.
    // You should not add the "login" action to allow list. Doing so would
    // cause problems with normal functioning of AuthComponent.

public function login() {
  if ($this->request->is('post')) {
       $user = $this->Auth->identify();

if ($user) {
    return $this->redirect($this->Auth->redirectUrl());
$this->Flash->error(__('Invalid username or password, try again'));

public function logout()
    return $this->redirect($this->Auth->logout());

Create the file login.ctp in Template->Users

<section id="content">

<div class="row">

<div class="large-6 large-centered columns text-center">

<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<legend><?= __('Please enter your username and password') ?></legend>
<?= $this->Form->input('username') ?>
<?= $this->Form->input('password') ?>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>



Temporarily allow the add method to function without being logged in by addinf the following in Controller->UsersController.php

public function beforeFilter(Event $event) {

Visit which should show an add user form, fill this in with your details.

Now that we have created a user, remove public access to the add user url in Controller->UsersController.php, remove the line “$this->Auth->allow(‘add’);”.

Web Development

Admin Controller and View with CakePHP3 bake

Example Commands

bin/cake bake model pages &&
bin/cake bake controller --prefix admin pages &&
bin/cake bake template --prefix admin pages

bin/cake bake model settings &&
bin/cake bake controller --prefix admin settings &&
bin/cake bake template --prefix admin settings

bin/cake bake model articles &&
bin/cake bake controller --prefix admin articles &&
bin/cake bake template --prefix admin articles