Using Auth0 with Symfony

Auth0 provide a 3rd party authentication service, as they point out this can have a lot of benefits (along with a few drawbacks). They have written a great tutorial on integrating Auth0 with the PHP Symfony framework here:

https://auth0.com/blog/creating-your-first-symfony-app-and-adding-authentication/

Do many people have experience using Auth0 to handle their authentication? I’ve never used them and am naturally sceptical about tying my platform to a 3rd party supplier I will have to pay. However it’s so frequent seeing a lot of expensive developer time wasted on an inferior inhouse solutions so is this worth a try?

Advertisements

Setup PHP Dev Environment on Mac OS X Sierra – Apache, MySQL & PHPMyAdmin

Getting the development environment right at the start is vitally important to productive application development. Here we will setup a flexible “LAMP” development environment on the latest Mac Os X, El Capitan. We will focus on keeping the development platform flexible and stable, centrally managing all system & application dependencies. Within a few minutes, we will hopefully have advanced PHP web applications serving up pages, but with the ability to integrate extra system components specific to your application.

System (optional)

Apple’s native development IDE is XCode, it’s not great for PHP but provides handy tools and installing it kind of tells Apple your computer’s being used for software development and to unlock related features. If you’re starting on a completely fresh system, it’s a good idea to install Apple’s Xcode tools. Open up the Terminal App, e.g. cmd + space then: terminal  and type:

sudo xcode-select --install
sudo xcodebuild -license

You will have to agree to some terms & conditions but prevents later problems using common tools like Git.

Install Apache and PHP7 (or other versions)

Install the amazing and free open-source Homebrew  package management system which will make open-source software development far more manageable. If you’re not yet convinced by Homebrew, check out its popularity on GitHub. Install Homebrew as such:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

As of writing, the most recent version of PHP is 7.0, although Mac already has PHP and Apache inbuilt, we will install it using Homebrew to better manage all development services & dependencies – they’ll be all in one place, managed using a standard set of commands. Allowing us to easily upgrade & downgrade PHP, also since Apache (the web server / engine) keeps changing between MacOS releases, we will use Homebrew to manage and keep it consistent.

Fist stop the default Apache service, in the terminal type:

 sudo apachectl stop
 sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 2>/dev/null
 brew install httpd24 --with-privileged-ports
 brew install php71
[short wait to download files]
 brew services start homebrew/apache/httpd24

This should take a minute or less and Homebrew is usually really good at providing helpful and clean output info, errors and ways to fix them. For example, it may give you info about where the php.ini file is, (e.g. /usr/local/etc/php/7.0/php.ini ) or suggest the following command to automatically start PHP7 at login:

 brew services start homebrew/php/php70

As mentioned, helpful and clean output info is one of Homebrew’s real strong points, always read what it outputs!

Verify PHP7 installation (optional)

These are a few really useful commands to check everything is working, or diagnose any problems:

Format:   command
                     output

    php -v

PHP 7.0.8 (cli) (built: Jun 23 2016 16:32:40) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

    which php
/usr/local/bin/php

    ls -l /usr/local/bin/php
lrwxr-xr-x  1 maltronic  admin  36 30 Aug 19:20 /usr/local/bin/php -> /usr/local/Cellar/php70/7.0.8/bin/php

     php -i | grep php.ini
Configuration File (php.ini) Path => /usr/local/etc/php/7.0
Loaded Configuration File => /usr/local/etc/php/7.0/php.ini

If for any reason there’s a problem you can manually point php to the desired version. First, check what Kegs are have installed in your Cellar using:

brew list

If no version of php appears, try “tapping” homebrew to enable it to pick up more software kegs then installing php7 like so:

brew tap homebrew/dupes
brew tap homebrew/versions
brew tap homebrew/homebrew-php
brew install php70

You can link to whichever installed PHP version you like, say you wanted to use PHP 5.6 (and have installed it using brew install php56 then create a symbolic link to /usr/local/bin/php:

ln -s /usr/local/Cellar/php56/5.6.23/bin/php /usr/local/bin/php

Enable Debugging (optional)

Stop haphazardly print variables to the screen and become a real pro developer, use debugging! It’s so easy and better for fixing bugs. To install Xdebug and enable IDE debugging using popular IDEs like Netbeans and PHPStorm, install with homebrew:

brew install php70-xdebug

Install MySQL

Although MariaDB is slowly replacing MySQL in open source circles, either can be installed, as such:

brew install mysql

Just replace “mysql” with “mariadb” (for rest of article). The Homebrew MySQL/MariaDB server should now be running, this can be verified with:

brew services list

Typing just brew services lists the Homebrew’s service manager commands. If mysql isn’t already running, type brew services start mysql

Configure Apache

We will keep on using the preinstalled Apache server but edit the Apache config file to enable the PHP7 module. Use Mac’s inbuilt nano editor or another text editor (like Sublime Text):

sudo nano /etc/apache2/httpd.conf

Add the following line:

  LoadModule php7_module /usr/local/opt/php70/libexec/apache2/libphp7.so

Press ctrl + x to quit.

Now, every site we add will be a new VirtualHost in Apache, one of potentially many web applications running on your computer. Whilst you can edit the /etc/hosts file to enable local domain names, a quick and reliable technique is to use different ports to distinguish websites. First, make sure Apache is checking for Virtual Hosts and that there’s no # commenting out the file:

sudo nano /etc/apache2/httpd.conf

Go right to the bottom of the file (ctrl + v is PAGE DOWN) and ensure the following line does not have a # infront, it should look like the middle line below:

...

Include /private/etc/apache2/other/*.conf

...
(i.e. no #, although the * is ok)


Now edit Apache’s VirtualHost config file, using the nano editor command:

sudo nano /etc/apache2/extra/httpd-vhosts.conf

And add a VirtualHost config for your website:

Listen 81

DocumentRoot "/Users/maltronic/my_php_project/web"
ServerName "local.my_php_project"
ErrorLog "/var/log/apache2/my_php_project-error.log"



Options Indexes FollowSymLinks
AllowOverride All
Require all granted

Where the directory (“web” above) is the base directory that will appear on your website (i.e. where index.php or an equivalent would sit).

Now, finally, we restart the Apache server to apply our changes:

sudo apachectl restart

Some errors may appear (especially in regards to domain names), these generally don’t matter although if there’s an obvious problem stated you should fix it and re-run the restart command.

Install PHPMyAdmin

As usual, install PHPMyAdmin using Homebrew:

brew install phpmyadmin

And as usual, Homebrew will give some info on any final steps, which in my case means:

sudo nano /etc/apache2/httpd.conf

Then adding to the bottom of the file (ctrl + v is page down in nano):

Alias /phpmyadmin /usr/local/share/phpmyadmin

Options Indexes FollowSymLinks MultiViews
AllowOverride All

Require all granted


Order allow,deny
Allow from all

Install Composer (optional)

Composer is a near universally adopted PHP package manager that enables your PHP applications to use 3rd party libraries and manage their dependencies (very similar to Homebrew but for your PHP application (on any OS), rather than Mac Operating System).

It’s not needed yet, but most professional and open-source projects use it. For consistency let’s install it using Homebrew:

brew install composer

As usual, look at the screen output for any errors and info.

That’s It

Try loading PHPMyAdmin in a web browser at:

http://localhost/phpmyadmin

By default the MySQL admin user is: root (with no password).

You now have a fully functioning and extremely flexible LAMP development environment. From here you can easily add additional services like Redis, Memcache, RabbitMQ, other databases and whatever else you would like to use in your project


This guide gets updated based on reader comments. Any problems, please comment below or share on social media if you found this guide useful!

Using Twig’s default() filter to avoid “Variable some_var does not exist”

References to undefined variables are a common cause of web pages not displaying when using Twig. A simple mention of an undefined variable can cause 500 errors:

{{ some_var }}

Variable some_var does not exist in..

Whilst turning strict_variables off in the twig config will obviously hide the error and is best for production, during development hiding errors can ultimately making spotting bugs harder. A better solution is using Twig’s default() filter like so:

{{ some_var|default("") }}

This will print the variable if it exists or nothing if it is not defined.
For if statements and loops, there are 3 choices:

  1. The default() filter:
  2. {% if some_var|default(false) %}some text{% endif %}
  3. The fine grain but hideously verbose control of defined:
  4. {% if some_var is defined and some_var %}some text{% endif %}
  5. The empty filter:
  6. {% if some_var is not empty %}some text{% endif %}

There are also lots of other useful tests, filters and functions that Twig provides out of the box, check out their documentation pages for more info. Hope this helps. Please like and share if it does 🙂

Checkout Specific Git Branches in Composer.json

Composer allows different branches of a Git repository to be checked out for use as a third party library. To do so first add the git repository to your composer.josn file:

 "repositories": [
     {
         "type": "vcs",
         "url": "git@bitbucket.org:org/repo.git"
     }
 ]

 

Now the repository is known, add the branch to the composer.json require section:

"require": {
    "org/repo": "dev-branch1"
}

 

You can even choose a specfic commit:

"require": {
    "org/repo": "dev-branch1#ec457d0a974c48d5685a7efa03d137dc8bbde7e3"
}

 

Examples

As explained on the getcomposer.org website, login details can be provided to access private repositories. For example, using ssh:

{
    "require": {
        "org/repo": "dev-branch1"
    },
    "repositories": [
        {
            "type": "composer",
            "url": "ssh2.sftp://bitbucket.org",
            "options": {
                "ssh2": {
                    "username": "composer",
                    "pubkey_file": "/home/username/.ssh/id_rsa.pub",
                    "privkey_file": "/home/username/.ssh/id_rsa"
                }
            }
        }
    ]
}

 

Or using an SSL certificate key:

{
    "require": {
        "org/repo": "dev-branch1"
    },
    "repositories": [
        {
            "type": "vcs",
             "url": "https://bitbucket.org:org/repo.git",
            "options": {
                "ssl": {
                    "local_cert": "/home/username/.ssl/composer.pem"
                }
            }
        }
    ]
}

 

Or using HTTP Basic authentication:

{
    "require": {
        "org/repo": "dev-branch1"
    },
    "repositories": [
        {
            "type": "vcs",
            "url": "https://username:password@bitbucket.org/com/repo.git"
        }
    ]
}

 

This provides fairly good SSL encrypted security, although it’s a good idea to remove the username & password credentials from the Git repository and instead place them in a file named auth.json within the COMPOSER_HOME directory, as such:

{
    "https://bitbucket.org": {
        "http-basic": {
            "bitbucket.org": {
                "username": "username",
                "password": "password"
            }
        }
    }
}

 

You can also specify HTTP headers directly, which enables our preferred method for stateless authentication, JWT (Java Web Tokens):

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://bitbucket.org/com/repo.git",
            "options":  {
                "http": {
                    "header": [
                        "authorization: authenticated.jwt.token"
                    ]
                }
            }
        }
    ]
}

 

Conclusion

As can be seen from the above examples, Composer enables a flexible range of options in regards to the selection and integration of Git repositories along with their respective branches and versions.

Make mysql databases default to UTF8

By default MySQL databases are created with one of the latin charsets – as if globalization never happened – and just asking for future internationalization and charset issues. UTF8 is the generally accepted way forward (for now) and there are few occasions that it isn’t the best charset to use.

Ideally, some sort of framework config system will take care of this but otherwise for existing MySQL databases, you can find out their current charset by entering the MySQL terminal and typing:

SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name = "myDatabase";

The problem is changing the character set of an in-use databases can be troublesome and you have to remember to specify UTF8 as the charset every time you create a new database. Also many database tools (e.g. PHP’s Doctrine) do not currently support creating a database with a non-default charset.

The best solution is to set the default charset to UTF8 straight after installing mysql and avoid the problems before the occur. This can be done simply by modifying /etc/mysql/my.cnf (note my.conf may be located elsewhere) and adding the following lines to the [mysqld] section:

collation-server = utf8_general_ci
character-set-server = utf8

Then restart the MySQL service:

sudo service mysql restart

Now new databases will now be created using the UTF8 character by default.

Automating timestamps with Doctrine ORM

The Doctrine ORM includes a robust Event system enabling timestamp fields to be set automatically without any explicit methods calls during object instantiation. This also works great when utilising the many smart RESTful design patterns for Symfony, Laravel and other frameworks which can implement Doctrine.

For efficiency, Doctrine doesn’t currently default to look for event hooks so the following annotation must be added to the Entity class:

[code language=”php”]
* @ORM\HasLifecycleCallbacks()
[/code]

The following columns will be utilised (either add to Database manually, using the relevant Doctrine console commands, or even better, a Doctrine Migration):

[code language=”php”]
/**
* @var \DateTime
*
* @ORM\Column(name="created", type="datetime")
*/
private $created;

/**
* @var \DateTime
*
* @ORM\Column(name="updated", type="datetime", nullable=true)
*/
private $updated;

/**
* @var \DateTime
*
* @ORM\Column(name="deleted", type="datetime", nullable=true)
*/
private $deleted;
[/code]

These functions provide the event listening (using annotations):

[code language=”php”]
/**
* Triggered on insert

* @ORM\PrePersist
*/
public function onPrePersist()
{
$this->created = new \DateTime("now");
}

/**
* Triggered on update

* @ORM\PreUpdate
*/
public function onPreUpdate()
{
$this->updated = new \DateTime("now");
}

/**
* Triggered on update

* @ORM\PreRemove
*/
public function onPreRemove()
{
$this->deleted = new \DateTime("now");
}
[/code]

Now, all Product objects which get persisted to the Doctrine Entity Manager will have the correct timestamp set when created, updated or deleted.

The complete Entity class (with added id & name fields for testing) is as follows:

After creating, persisting and flushing a new instance, the created timetamp gets automatically set. After selecting the previous row, changing the name and flushing, the updated timestamp gets automatically set. After selecting the previous row and deleting it, a deleted timestamp get automatically set.

Please note, the deleted timestamp assumes your database is retaining the data in a “deleted” state, using triggers or other such database functionality to handle Doctrine’s instruction to delete the row. If you are not using this, either ignore the code or remove it.

Switching databases in Symfony upon application events

We’re big fans of the PHP Symfony2 framework and Doctrine2 ORM but a recent project involved a REST API for a multi-client system where each client wanted their database fully separated from each other, but we only knew which client database to connect to once a user had logged in (so no easy config.yml and parameters.yml configuration).

The login gets handled via Java Web Tokens using the excellent Lexik JWT Authentication bundle. So the first call to /auth/login_check with a username and password retrieves a token along with a id of the client (added using the onAuthenticationSuccessResponse listener documented here. Subsequent requests supply a HTTP Authorization header with the token and a custom “client” header specifying the id of the client (also documented in the above link).

This gave us stateless authentication for our API, but we still had to actually switch the Doctrine dbal connection to point to the right database. The solution (inspired by this Stack Overflow question) involved an onKernelRequest() event listener to switch the database from a base database (holds login / authentication data and is referenced in the default connection settings – or whichever connection you’re overriding – of your config.yml file) to the desired database and update the tokenStorage object accordingly. As a tip though, it’s best to keep the base and individual databases schematically identical as possible for reasons explained later.

First create the Event Listener:

Then add this to the services.yml file:

Then add the client databases to the end of the parameters-dist.yml file:

The security.yml file looks something like:

Conclusion:
This solution works fairly well in providing multi-database connectivity based on a site event (in this case user login) with the occasional bit of peering underneath’s Symfony’s hood. As mentioned above, keeping the base database schematically identical (i.e. same table structure, differing data) to your individual databases is very highly advisable. Some Symfony logic occurs before the onKernalRequest event gets fired (looking at your forms) so functionality limitations can otherwise occur there. Also parsers like the Nelmio Api Documentation bundle typically build pre-authentication (so whilst the base database is still selected).

Doctrine Migrations can also be enabled with a little tinkering (I may write a new post on how to do this if there is demand) but again, it helps if the schemas are identical (although isn’t vital).