Category: php

  • CSRF token package

    Working on older projects (as i tend to do), I often get various requirements for security enhancements.

    A few days ago, somebody apparently ordered a security test of a site I was working on, so yesterday i got the report:
    3 HIGH security errors, one being that we had no CSRF tokens on the forms.

    gah…

    I started searching for a nice CSRF token package, but the cool ones from Symfony etc used a lot of internal things and this project i worked on, didn’t really use a nice framework (it’s old – but upgraded through the years it’s been in service.. no main framework though)

    So I got my hands dirty and created a new package to handle this 🙂

    The package is called jimmiw/csrf and is available on github and packagist.

    To install it, write:

    composer install jimmiw/csrf

    And you are good to go. Read the README.md file for more info about how to use the package.

    Please note, that it’s already in version 2!… I guess I released it a bit fast yesterday and then today I changed the API…
    Anyways, the unit test proves that it works 🙂

  • Laravel AWS SDK credentials using .env and configs

    Every now and then, I need to integrate with an Amazon web service (aws). I like the whole IAM user way of doing this, so that is usually my preferred choice.

    However, every time i need to setup a connection in a project (using mostly Laravel these days), I forget how I did it last time.

    If you ever struggle with remembering as well, or simple think the documentation on their AWS SDK for PHP is a bit rubbish, then this is my little guide to setting up your clients for connections.

    The steps are as following:

    • Log in to their AWS console on aws.amazon.com
    • Open the IAM service and create a new user. Follow their guide if necessary. Basically just follow the wizard, then click create user and go back and permissions under the “Permission” tab, for the service you need (e.g. AmazonSNSFullAccess for SNS)
    • Add their composer library to your project:
      composer require aws/aws-sdk-php

    After composer gets done, you need to open your Laravel project in the editor (This guide also “works” for other php libraries, but I am just using Laravels .env and config settings)

    Open up .env located in your application root and add a few settings:

    AWS_SNS_KEY=
    AWS_SNS_SECRET=
    AWS_SNS_REGION=
    AWS_SNS_VERSION=latest

    I like to have different IAM users for different services, that is why I am adding the _SNS_ in my settings. Remember to fill them out with your credentials from your newly created IAM user.

    Next step is to create an new aws.php file in config/ folder.
    This will hold your AWS settings, so they can be accessed using the config method.

    Add the following contents to config/aws.php:

    <?php
    
    return [
        'sns' => [
            'region' => env('AWS_SNS_REGION'),
            'version' => env('AWS_SNS_VERSION'),
            'credentials' => [
                'key' => env('AWS_SNS_KEY'),
                'secret' => env('AWS_SNS_SECRET'),
            ],
        ],
    ];
    

    By adding the ‘sns’ key, your settings available under aws.sns.xx

    Let us build a quick unit test to see if we can access our service.
    Create a new file called /test/Integration/Aws/SnsTest.php

    <?php
    
    namespace Tests\Integration\Aws;
    
    use Aws\Sns\SnsClient;
    use Tests\TestCase;
    
    class SnsTest extends TestCase
    {
        public function testAwsConnection()
        {
            $client = new SnsClient([
                'region' => config('aws.sns.region'),
                'version' => config('aws.sns.version'),
                'credentials' => config('aws.sns.credentials'),
            ]);
    
            $topics = $client->listTopics();
            self::assertNotNull($topics);
        }
    }
    

    We create a new SnsClient, passing an array of settings.
    If you have a look at their documentation, they have a 'profile' => 'default'

    Do not add that, as it will tell the client to find the credentials to use, in your local ~/.aws/credentials file.

    Using the credentials key, will read the credentials from your aws.sns.credentials (which points to AWS_SNS_KEY and AWS_SNS_SECRET).

    Run the unit test and profit!

    vendor/bin/phpunit tests/Integration/Aws/SnsTest.php

  • Using a Zend view helper inside a partial

    When rendering a page using one or more partials, I often need to call a helper to do some extra stuff for me.

    One caveat I found was, that the view variables was not available in my helper.

    After some research it seems that the partial acts as the new view.
    So in order to access the views variables, you need to pass them to your partial.

    <?php echo $this->partial('partial-path/partial', array('variable1', $this->variable1, ...)); ?>
  • Handle different environments with PHP

    Being both a Rails and PHP developer, I’m often lacking a few things when I’m switching from Rails to PHP.

    One of the things I miss the most, is the different environments that Rails has, which makes testing, developing, staging and production environments easy.
    However, I found a way to do this in PHP as well, without using frameworks like Zend, CakePHP etc.

    Getting started

    There are basically two things you need to do, in order to get this setup to work properly.

    Configure your server (apache)

    First we need to configure the apache server (If you are using nginx, look at their documentation for help).

    The magic lies in using the SetEnv function in the apache server.
    This functions makes a variable available in the $_SERVER object in PHP, which is what we are using to differentiate between the environments.

    Virtual hosts

    If you are using virtual hosts, then simply add it with in the section.

    An example configuration with a “test” environment could be:

    <VirtualHost *:80>
      ServerName my_site.test.dk
      DocumentRoot /var/www/my_site.test.dk
    
      SetEnv APPLICATION_ENV test
    
      <Directory /var/www/my_site.test.dk>
        Options Indexes FollowSymLinks -MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
      </Directory>
    
      ErrorLog /var/log/apache2/my_site.test.dk.error.log
    
      # Possible values include: debug, info, notice, warn, error, crit,
      # alert, emerg.
      LogLevel warn
    
      CustomLog /var/log/apache2/access.log combined
    </VirtualHost>
    

    Using the apache.conf / httpd.conf

    On my mac the file is called httpd.conf, but on the ubuntu linux servers I’m managing it’s called apache.conf.

    Anyways, just head to the bottom of the file located here:
    Linux: /etc/apache/apache.conf
    Mac: /etc/apache/httpd.conf

    And add the following line:

    SetEnv APPLICATION_ENV "development"
    

    Exchange “development” with the environment you are configuring (In my setup, production = no value)

    Configure your application

    Now we need to use the variable passed to the $_SERVER object, in order to see what environment we are “in”, and configure the application accordingly.

    In most projects I have an environment.inc.php file, which has the following structure:

    <?php
    
    // initializing the configuration array (mostly to avoid null warnings)
    $envConfiguration = array();
    
    // the environment configuration for the development environment (local machine)
    if(isset($_SERVER['APPLICATION_ENV']) && $_SERVER['APPLICATION_ENV'] == 'development') {
      $envConfiguration = array(
        'db_password' => '12345',
        'db_user' => 'root',
        'db_host' => '127.0.0.1',
        'db_name' => 'my_dev_db'
      );
    }
    // the environment configuration for the unit testing environment (local machine)
    if(isset($_SERVER['APPLICATION_ENV']) && $_SERVER['APPLICATION_ENV'] == 'unittest') {
      $envConfiguration = array(
        'db_password' => '12345',
        'db_user' => 'root',
        'db_host' => '127.0.0.1',
        'db_name' => 'my_unittest_db'
      );
    }
    // add more environments here... E.g. staging, test etc
    
    // Not having the APPLICATION_ENV variable set, forces the application to
    // use PRODUCTION settings!
    // The reason for this is, that I don't always have control of the production
    // servers, while I have control over the staging and test servers. 
    // (You can of course have a production value set
    else {
      // production environment settings here.
      $envConfiguration = array(
        'db_password' => 'some_strong_password',
        'db_user' => 'some_production_user',
        'db_host' => '127.0.0.1',
        'db_name' => 'production_database'
      );
    }
    ?>
    

    Pretty simple ye?

    What we are doing is simply checking if the APPLICATION_ENV variable is set in the $_SERVER object, and if it is, we test what it is.

    The reason I’m checking if the APPLICATION_ENV isset, is because it gives a lot of warnings if the variable is not set (which would be in production for my setup).

    What about unit testing? (phpunit)

    Well, I have an answer there as well.

    Since the $_SERVER variable is not available in unit tests, we simply create it ourselves and set the APPLICATION_ENV to “unittest”.

    Being both a Rails and PHP developer, I’m often lacking a few things when I’m switching from Rails to PHP.

    One of the things I miss the most, is the different environments that Rails has, which makes testing, developing, staging and production environments easy.
    However, I found a way to do this in PHP as well, without using frameworks like Zend, CakePHP etc.

    Getting started

    There are basically two things you need to do, in order to get this setup to work properly.

    Configure your server (apache)

    First we need to configure the apache server (If you are using nginx, look at their documentation for help).

    The magic lies in using the SetEnv function in the apache server.
    This functions makes a variable available in the $_SERVER object in PHP, which is what we are using to differentiate between the environments.

    Virtual hosts

    If you are using virtual hosts, then simply add it with in the section.

    An example configuration with a “test” environment could be:

    <VirtualHost *:80>
      ServerName my_site.test.dk
      DocumentRoot /var/www/my_site.test.dk
    
      SetEnv APPLICATION_ENV test
    
      <Directory /var/www/my_site.test.dk>
        Options Indexes FollowSymLinks -MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
      </Directory>
    
      ErrorLog /var/log/apache2/my_site.test.dk.error.log
    
      # Possible values include: debug, info, notice, warn, error, crit,
      # alert, emerg.
      LogLevel warn
    
      CustomLog /var/log/apache2/access.log combined
    </VirtualHost>
    

    Using the apache.conf / httpd.conf

    On my mac the file is called httpd.conf, but on the ubuntu linux servers I’m managing it’s called apache.conf.

    Anyways, just head to the bottom of the file located here:
    Linux: /etc/apache/apache.conf
    Mac: /etc/apache/httpd.conf

    And add the following line:

    SetEnv APPLICATION_ENV "development"
    

    Exchange “development” with the environment you are configuring (In my setup, production = no value)

    Configure your application

    Now we need to use the variable passed to the $_SERVER object, in order to see what environment we are “in”, and configure the application accordingly.

    In most projects I have an environment.inc.php file, which has the following structure:

    <?php
    
    // initializing the configuration array (mostly to avoid null warnings)
    $envConfiguration = array();
    
    // the environment configuration for the development environment (local machine)
    if(isset($_SERVER['APPLICATION_ENV']) && $_SERVER['APPLICATION_ENV'] == 'development') {
      $envConfiguration = array(
        'db_password' => '12345',
        'db_user' => 'root',
        'db_host' => '127.0.0.1',
        'db_name' => 'my_dev_db'
      );
    }
    // the environment configuration for the unit testing environment (local machine)
    if(isset($_SERVER['APPLICATION_ENV']) && $_SERVER['APPLICATION_ENV'] == 'unittest') {
      $envConfiguration = array(
        'db_password' => '12345',
        'db_user' => 'root',
        'db_host' => '127.0.0.1',
        'db_name' => 'my_unittest_db'
      );
    }
    // add more environments here... E.g. staging, test etc
    
    // Not having the APPLICATION_ENV variable set, forces the application to
    // use PRODUCTION settings!
    // The reason for this is, that I don't always have control of the production
    // servers, while I have control over the staging and test servers. 
    // (You can of course have a production value set
    else {
      // production environment settings here.
      $envConfiguration = array(
        'db_password' => 'some_strong_password',
        'db_user' => 'some_production_user',
        'db_host' => '127.0.0.1',
        'db_name' => 'production_database'
      );
    }
    ?>
    

    Pretty simple ye?

    What we are doing is simply checking if the APPLICATION_ENV variable is set in the $_SERVER object, and if it is, we test what it is.

    The reason I’m checking if the APPLICATION_ENV isset, is because it gives a lot of warnings if the variable is not set (which would be in production for my setup).

    What about unit testing? (phpunit)

    Well, I have an answer there as well.

    Since the $_SERVER variable is not available in unit tests, we simply create it ourselves and set the APPLICATION_ENV to “unittest”.

    Here is a sample unittest include file, which should be included at the very top of your unittest.
    Let’s call this file unitTestConfiguration.inc.php and put it in a folder called tests

    <?php
    
    // includes the phpunit framework
    require_once 'PHPUnit/Framework.php';
    
    // constructs the SERVER variable to set the environment to unittest.
    $_SERVER = array(
      'APPLICATION_ENV' => 'unittest',
      'SERVER_NAME' => 'localhost',
      'REQUEST_URI' => ''
    );
    // SERVER_NAME and REQUEST_URI is not needed, but nice to have
    
    // includes our environment file (remember to add a unittest section there!
    include('config/environment.inc.php');
    
    // includes the database file, which reads the $envConfiguration variable
    // (which is set in the environment.inc.php file) and connects to the database
    include('config/db.inc.php');
    
    // sets the default timezone (Because strftime will throw a warning in PHP5+)
    date_default_timezone_set("Europe/Copenhagen");
    
    ?>
    

    When creating your unit test, simply do the following:

    <?php
    
    // includes the unit test configuration (including the PHPUnit framework)
    include('tests/unitTestConfiguration.inc.php');
    
    class EnvironmentTest extends PHPUnit_Framework_TestCase {
      /**
       * A small test to see if our environment is actually set.
       * (You don't need this test in your test files, this is 
       * just for the scope of this post!)
       */
      function testEnvironment() {
        $this->assertTrue(isset($_SERVER['APPLICATION_ENV']));
        $this->assertTrue($_SERVER['APPLICATION_ENV'] == 'unittest');
      }
    }
    ?>
    

    To run the unit test, simply open a terminal / command / cmd (or what ever you are using), and go to the project folder.
    There you should run the following command:

    phpunit tests/environmentTest.php
    

    On my machine that gives the following output:

    $ phpunit tests/environmentTest.php 
    PHPUnit 3.4.14 by Sebastian Bergmann.
    
    .
    
    Time: 0 seconds, Memory: 5.75Mb
    
    OK (1 test, 2 assertions

     variable is not available in unit tests, we simply create it ourselves and set the APPLICATION_ENV to “unittest”.

    Here is a sample unittest include file, which should be included at the very top of your unittest.
    Let’s call this file unitTestConfiguration.inc.php and put it in a folder called tests

    <?php 
    // includes the phpunit framework
    require_once 'PHPUnit/Framework.php';
    // constructs the SERVER variable to set the environment to unittest.
    $_SERVER = array(
    'APPLICATION_ENV' => 'unittest',
    'SERVER_NAME' => 'localhost',
    'REQUEST_URI' => ''
    );
    // SERVER_NAME and REQUEST_URI is not needed, but nice to have
    // includes our environment file (remember to add a unittest section there! include('config/environment.inc.php');
    // includes the database file, which reads the $envConfiguration variable
    // (which is set in the environment.inc.php file) and connects to the database include('config/db.inc.php');
    // sets the default timezone (Because strftime will throw a warning in PHP5+)
    date_default_timezone_set("Europe/Copenhagen"); ?>

    When creating your unit test, simply do the following:

    <?php 
    // includes the unit test configuration (including the PHPUnit framework) include('tests/unitTestConfiguration.inc.php');

    class EnvironmentTest extends PHPUnit_Framework_TestCase {
    /**
    * A small test to see if our environment is actually set.
    * (You don't need this test in your test files, this is
    * just for the scope of this post!)
    */
    function testEnvironment() {
    $this->assertTrue(isset($_SERVER['APPLICATION_ENV']));
    $this->assertTrue($_SERVER['APPLICATION_ENV'] == 'unittest');
    }
    }

    To run the unit test, simply open a terminal / command / cmd (or what ever you are using), and go to the project folder.
    There you should run the following command:

    phpunit tests/environmentTest.php
    

    On my machine that gives the following output:

    $ phpunit tests/environmentTest.php  
    PHPUnit 3.4.14 by Sebastian Bergmann. .
    Time: 0 seconds, Memory: 5.75Mb OK (1 test, 2 assertions

    Files for this post: 2011-01-08_php_testing_article.zip