Category Archives: php

Securing your PHP REST API with OAuth

Problem:

There are many considerations to make when building and securing a public-facing API, but I wanted to look at one issue in particular: Making sure that only authenticated clients can access it.

Ideally, we want to make one request to the server and get back one response. In order to have a simpler application flow, we want to avoid the added complexity of managing access tokens.

  1. Client sends a request for data along with their authentication details
  2. Server sends data back to the authenticated client

This flow will be familiar if you have used Amazon Web Services (AWS) before, as they use a similar "signed-message" solution.

Solution:

Use a simple version of the OAuth 1.0 standard which is known as "2-legged" authentication. In this system, no access tokens are used. Authentication is performed using a public and private key system. These public and private keys are known by the client (consumer) and the server (provider).

Things to note:

  • The private key (the secret) is NEVER passed over the wire
  • The private key is used in combination with HMAC to hash the request data being sent to the API
  • The server uses its own copy of the private key to verify the request is authentic
  • You should use SSL to encrypt traffic between your consumer and provider

My solution uses PHP OAuth library by Andy Smith (MIT licence) for the heavy lifting.

Here are two simple examples for the provider and consumer sides:

Provider side

In this example, the list of valid consumer keys and secrets are hardcoded, but you probably want to store these in a DB somewhere. The provider will return "true" if it is a valid authenticated request, or otherwise it will spit out and error message "Exception: ...".

		$server = new OAuthServer(new DataApi_OAuthDataStore());
		$server->add_signature_method( new OAuthSignatureMethod_HMAC_SHA1() );

		$request = OAuthRequest::from_request();

		try {
			if ( $server->verify_request($request) ) {
				echo json_encode(true);
			}
		}
		catch (Exception $e) {
			echo json_encode("Exception: " . $e->getMessage());
		}

		class DataApi_OAuthDataStore extends OAuthDataStore {
			function lookup_consumer($consumer_key) {
				$consumer_secrets = array( 'thisisakey'		=> 'thisisasecret',
										   'anotherkey'		=> 'f3ac5b093f3eab260520d8e3049561e6',
										 );

				if ( isset($consumer_secrets[$consumer_key])) {
					return new OAuthConsumer($consumer_key, $consumer_secrets[$consumer_key], NULL);
				}
				else {
					return false;
				}
			}

			function lookup_token($consumer, $token_type, $token) {
				// we are not using tokens, so return empty token
				return new OAuthToken("", "");
			}

			function lookup_nonce($consumer, $token, $nonce, $timestamp) {
				// @todo lookup nonce and make sure it hasn't been used before (perhaps in combination with timestamp?)
				return NULL;
			}

			function new_request_token($consumer, $callback = null) {

			}

			function new_access_token($token, $consumer, $verifier = null) {

			}
		}

Consumer side

	require_once dirname(__FILE__) . '/../library/OAuth/OAuth.php';

	// this is sent with each request, and doesn't matter if it is public
	$consumer_key = 'thisisakey';

	// this should never be sent directly over the wire
	$private_key  = 'thisisasecret';

	// API endpoint
	$url = 'https://example.com/v1/oauth';

	// the custom paramters you want to send to the endpoint
	$params = array( 'foo' => 'bar',
					 'bar' => 'foo',
					 );

	$consumer = new OAuthConsumer($consumer_key, $private_key);
	$request  = OAuthRequest::from_consumer_and_token($consumer, NULL, 'GET', $url, $params);

	$sig = new OAuthSignatureMethod_HMAC_SHA1();

	$request->sign_request($sig, $consumer, null);

	$opts = array(
		'http' => array(
			'header' => $request->to_header()
		)
	);

	$context = stream_context_create($opts);

	$url = $url . '?' . http_build_query($params);

	echo "Making request: " . $url . PHP_EOL;
	echo "Authorization HTTP Header: " . $request->to_header() . PHP_EOL;
	echo "Response: " . file_get_contents($url, false, $context) . PHP_EOL;

Using the samples above should give you a head-start when creating your own authenticated API.

View the sample code on GitHub.

Any questions? Please use the comments section below!

P.S. - Looking for reliable hosting for your PHP projects? I recommend Clook:

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

Fixing Laravel artisan migration timeout issues

A quick tip if you are getting timeout issues when creating new Laravel migrations:

$ php artisan migrate:make create_users_table --table=users --create
Created Migration: 2013_06_25_100053_create_users_table
Generating optimized class loader

[Symfony\Component\Process\Exception\RuntimeException]
The process timed-out.

Open up the vendor/symfony/process/Symfony/Component/Process/Process.php
file within your Laravel application and change the constructor from:

    public function __construct($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array())

to this:

    public function __construct($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = null, array $options = array())

This removes the timeout, and will prevent the error from happening.

Looking for reliable hosting for your Laravel projects? I recommend Clook Internet.

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

Learning Laravel 4 - Essential resources

I'm going to be working on a Laravel 4 project soon, so I've been reading up on it. Here are a few key resources I've used for getting up to speed:

Looking for a reliable host for your Laravel projects? I recommend Clook Internet.

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

Simple development hosts on Mac

This tutorial will show you how you can easily set up new virtual hosts on the stock Mac Apache install, perfect for testing and developing small PHP projects. Once you have done this, new projects can be set up by just creating new directories -- no adding hosts to /etc/hosts or adding new Apache configuration will be required.

We are going to use ~/Sites/ as the base directory, and we'll be able to dynamically serve from any directories under this. The name of the directory that you use will form part of the URL that you will use.

So, for example, if you created the following under ~/Sites/

mkdir -p ~/Sites/siteone/htdocs
mkdir -p ~/Sites/sitetwo/htdocs
mkdir -p ~/Sites/anothersite/htdocs

Then you will be able to access content from htdocs under the following URL's

Notice how we are using the .localhost TLD for this. RFC 2606 specifies that .localhost is reserved for local testing purposes.

So, how do we get to this setup? There are two parts:

1. Set up .localhost proxying

First of all, we need to make sure that any requests to a .localhost domain are routed to the local loopback device. For this, we will use the Automatic Proxy Configuration facilities of OS X.

We need to create the following Proxy Configuration File:

function FindProxyForURL(url, host)
{
	if (dnsDomainIs(host, ".localhost")) {
		return "PROXY localhost";
	}
 
	return "DIRECT";
}

Save the file as localhost.pac and place it in your ~/Sites/ directory.

Now, open up your System Preferences and go into Network. Select your network in the left hand pane, and click the 'Advanced...' button on right. Click the 'Proxies' tab and check 'Automatic Proxy Configuration'. In the 'Proxy Configuration File', enter the URL to your file, for example http://localhost/~username/localhost.pac.

Click on 'OK' and then 'Apply'.

2. Set up Apache VirtualHost

Edit the Apache configuration file for your user which is stored under /etc/apache2/users/.conf, and add the following:

<VirtualHost *:80>
    VirtualDocumentRoot "/Users/<username>/Sites/%1/htdocs"
    ServerName subdomains.localhost
    ServerAlias *.localhost
</VirtualHost>

Restart Apache with sudo apachectl restart

3. Test!

mkdir -p ~/Sites/mysite/htdocs
echo 'Hello World!' > ~/Sites/mysite/htdocs/index.html

Visit http://mysite.localhost/ in your browser, and you should see "Hello World!"

Find this useful? You may be interested in my e-book, which is about creating the perfect PHP development environment on your Mac. Sign up to my mailing list to get more information:


References

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

Setting up a perfect PHP development environment on your Mac

generations

Note 22nd Jan 2014: I no longer have the time or enthusiasm for this book, so the project has been abandoned, sorry! The page is left here for archive purposes only.
---

One of my most popular blog posts has been the instructions on installing the PHP mcrypt extension on Mac OS X. I recall needing mcrypt for a phpMyAdmin installation, and thought the install instructions would be useful for others. It was: to date, the page has had 19,174 views!

The popularity of this post got me thinking -- how exactly are people using Mac OS X for PHP development?

I've been using OS X for development for many years now, and I've built up a lot of knowledge about how to create an environment that's a pleasure, rather than a chore, to use. A lot of this knowledge I am taking for granted, but I am sure it will be of use to others.

I'm putting this knowledge into my first e-book.

Here's an example of what topics I'll be covering:

Part I - Native

Where I look at options for working on smaller projects, or projects where your deployment environment is unknown.

  1. Configuring Apache
  2. Adding PHP modules
  3. Adding PECL modules
  4. Installing and running MySQL, PostGreSQL and MongoDB
  5. Installing and configuring phpMyAdmin
  6. Installing and configuring MAMP

Part II - Virtualization

For working with medium - large projects where your deployment environment is known.

  1. Installing Vagrant
  2. Setting up your first virtualized PHP environment
  3. Puppet provisioning
  4. Vital development tools
  5. Part III - Specific environments

    If you are developing for a specific framework or tool, this chapter will help.

    1. Installing a test instance of Magento
    2. Create a WordPress plugin and theme development environment
    3. Create an environment for Zend Framework or CodeIgniter applications

    Are you interested in finding out more? If so, please add your e-mail address to the list and I'll keep you updated on the progress of the e-book.

    Also, if you have any subjects that you would covered, please add a comment to the page.

    Glen Scott

    I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

    More Posts

    Follow Me:
    TwitterFacebookLinkedIn

HTML5, character encodings and DOMDocument loadHTML and loadHTMLFile

Extreme HTML Verschachteling

Whilst working on a script for my GetProThemes app recently, I came across a problem with PHP's loadHTML and loadHTMLFile methods.

The problem

I noticed that when using loadHTMLFile to parse an HTML document, the character encoding -- UTF-8 in this case -- was not being taken into consideration. Because of this, there was some mojibake after I extracted some content from the document. Here is an example of the problem:

$i18n_str = 'Iñtërnâtiônàlizætiøn';

$html = <<<EOS
<!doctype html>
<head>
  <meta charset="UTF-8">
  <title>html 5 document</title>
 </head>
 <body>
<h1 id="title">$i18n_str</h1>
</body>
</html>
EOS;

$dom = new DOMDocument();
$dom->loadHTML( $html );
echo $dom->getElementById( 'title' )->textContent;

// output: Iñtërnâtiônà lizætiøn

After some digging into the PHP source code, I discovered this function, along with loadHTML, uses Libxml for determining the character set of the HTML document automatically. It uses a function named htmlCheckEncoding for this purpose. What this function does is to look for a meta tag declaring the character set. Unfortunately, it only looks for the HTML4 style declaration:


<META http-equiv="Content-Type" content="text/html; charset=UTF-8">

This means that if your source document is HTML5, it will not pick up the newer meta tag declaration which has this form:


<meta charset="utf-8">

It seems that this glitch has been fixed in version 2.8.0 of Libxml, but if you are stuck with an older version then I have created a workaround.

The solution

I have created a drop-in replacements for the loadHTML/loadHTMLFile methods which will automatically convert an HTML5 character set declaration, if it exists, into an HTML4 character set declaration and thus allowing Libxml to parse the document correctly.

Fixing the above example is trivial:

require_once 'DOMDocumentCharset.php';

$i18n_str = 'Iñtërnâtiônàlizætiøn';

$html = <<<EOS
<!doctype html>
<head>
  <meta charset="UTF-8">
  <title>html 5 test</title>
 </head>
 <body>
<h1 id="title">$i18n_str</h1>
</body>
</html>
EOS;
		
$dom = new DOMDocumentCharset();
$dom->loadHTMLCharset( $html );
echo $dom->getElementById( 'title' )->textContent;

// output: Iñtërnâtiônàlizætiøn

So, the fix involves:

1. Including the DOMDocumentCharset class
2. Instantiating DOMDocumentCharset rather than DOMDocument
3. Calling the new loadHTMLCharset method

The class will only activate the workaround if the installed Libxml version is less than 2.8.0, so upgrading Libxml will not break this code.

The source code can be found on GitHub: dom-document-charset

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

An App in a Day

One thing I've really enjoyed about freelancing is the freedom to work on pet projects. When I have not been working with my paying clients, these projects have kept me busy. The trouble is, I seem to have many -- twenty at the last count -- in a perpetual state of "in progress".

So, today I had some free time and set myself a challenge -- develop and launch a useful web app in 24 hours. I decided to develop a browser for professionally-designed WordPress themes.

This challenge also allowed me to play around with some new technologies. In this case, I chose to use jQuery Masonry for the front-end Pinterest-like display.

GetProThemes screenshot

The app consists of two main parts:

1. A feed processing script that pulls in popular theme information from Mojo Themes and ThemeForest and saves them into a DB. This script is run via cron to update the themes on a weekly basis.

2. Some frontend logic that pulls out these themes and displays a preview graphic for users to click on.

In the end, I spent around eight hours on the development.

I registered a domain name, set up the hosting, added Google Analytics and affiliate referral codes and uploaded the files. The site can be found here:

GetProThemes.com

It's been a fun day, and I'll be very interested to hear if the site is useful to anyone!

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

Coming soon: A handy new application for freelancers, contractors and small businesses

Technical Services 7

Over the last few months, I've been working with Webwings to develop a new web application which we hope will save freelancers, contractors and small businesses a lot of time.

Development has been swift and pain-free thus far, due in part to the choice of CodeIgniter as the framework. It's proven to be an excellent base on which to iterate and incrementally build our product.

We have been alpha testing with a select group of users, and have received very positive feedback. We are aiming to get a beta release out within the next couple of months. If you are interested in participating in this, please leave a comment at the bottom of this page, and I will be in touch.

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

Securing your CodeIgniter passwords with bcrypt

Safe

I've applied a small modification to the Portable PHP password hashing framework, so it can be easily used in CodeIgniter projects. An example of using it to authenticate users:

$this->load->library( 'PasswordHash' );

    $query = $this->db->query("
        SELECT
            `user_id`,`password` AS `hash`
        FROM
            `user`
        WHERE   
            `username` = ". $this->db->escape($username) ."
        LIMIT
            1
    ");

    // check to see whether username exists
    if ( $query->num_rows() == 1 ) {
        $row = $query->row();

        if ( $this->passwordhash->CheckPassword( $password, $row->hash ) ) {
            return $row->user_id;
        }
    }

To generate a hashed password:

    $this->load->library( 'PasswordHash' );

    $password = ( isset( $_POST['password'] ) ? $_POST['password'] : '' );

    if ( $password ) {
        $hash = $this->passwordhash->HashPassword( $password );

        if ( strlen( $hash ) < 20 ) {
            exit( "Failed to hash new password" );
        }
    }

For more details, please check out the repository on GitHub: github.com/glenscott/passwordhash-ci

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn

Compiling PHP extensions using Xcode 4.3 and above

Prior to version 4.3 of Xcode, Apple bundled a load of command line tools with it that are used to compile native binaries, including PHP extensions. However, as of version 4.3, these tools are not bundled by default. Therefore, if you require these tools you need to take one of two actions:

1. If you already have Xcode 4.3 installed, go into the Components tab of the Download preferences panel and make sure Command Line Tools are selected

Xcode CLI tools installation

OR

2. Download and install the command line tools as an independent package from either;

a. Apple (requires Apple ID)
b. GitHub

Once you have the command line tools installed, you are able to compile native binaries.

If you found this post useful, it would be great if you could Like my Facebook page using the button in the sidebar. Thanks!

Glen Scott

I’m a freelance software developer with more than 10 years’ professional experience in web development. I specialise in creating tailor-made, web-based systems that can help your business run like clockwork. I am the Managing Director of Yellow Square Development and the founder of FreelanceDevLeads, a service that sources quality freelance leads for developers.

More Posts

Follow Me:
TwitterFacebookLinkedIn