Pragmatism in the real world

Getting started with Serverless PHP

I’ve been interested in Apache OpenWhisk for a little while now and recently submitted a new feature to add PHP support to the project. As OpenWhisk is a serverless environment, most users do not run their own copy and instead use a commercial provider with IBMs Bluemix available now along with Adobes I/O Runtime and RedHat coming soon. As a result, my contribution, isn’t practically useful until it’s in production with a provider.

Fortunately, and remarkably quickly, IBM have added support for PHP to the Bluemix “IBM Cloud Functions” platform, so now we can use PHP to develop serverless applications and deploy them into the wild! This is a rebranding, so you’ll see this referred to as “Bluemix OpenWhisk” around the web too.

Let’s look at how to write a simple PHP serverless function.

Getting started

You need a Bluemix account, so go to bluemix.net and create one.

You then need to set up an organisation – it has to be unique, so pick something that works for you; mine is called “19FT”. You also need to select a region: OpenWhisk is available in the US South and United Kingdom regions. Finally, you need to create a space; mine’s called “dev” and I also have a “live”.

To interact with an OpenWhisk installation, we need the wsk CLI tool. IBM would prefer you to use their special “Bluemix CLI” tool, but I prefer the stock wsk one as it works with my local installations and all the tutorials you’ll find on the web.

To install wsk:

  • Go to https://console.ng.bluemix.net/openwhisk/
  • Click “Download Cloud Functions CLI” and then click “Looking for the wsk CLI?” at the bottom of the page
  • Follow the steps on this page:
    • Download the CLI and then unzip it and place it onto your path (e.g. copy it to /usr/local/bin).
    • Check it works by running wsk help in your terminal. You should see usage information.
    • Copy the wsk property set command that’s shown in step 2 and run it in your terminal to set up the authorisation.
    • Test it by running wsk action invoke /whisk.system/utils/echo -p message hello --result

You should now have a working wsk command line tool. wsk is remarkably helpful. Add -h to any command and it’ll give you help.

If you’re only ever going to use the IBM Cloud Functions offering, you can use the IBM Cloud Functions CLI by installing the Bluemix CLI and then installing the Cloud Functions plugin for it. Then, whenever you see wsk in this article or any other tutorial, use bx wsk instead. As I say, I think IBM would prefer you to do this, but I’m not clear what the benefits are for someone who just uses their OpenWhisk product.

Hello World in PHP

In OpenWhisk, we call each function an “action”. A PHP action is a function called main that takes an associative array of parameters ($args) and returns an associative array. This is Functions As A Service, so we don’t need to worry about anything else other than the code that does the work.

Here’s Hello World:

<?php
function main(array $args) : array
{
    $name = $args["name"] ?? "stranger";
    return [
        "greeting" => "Hello $name!"
    ];
}

The PHP runtime on OpenWhisk is PHP 7.1, so we get all the new PHP features :) This function doesn’t do very much, so I expect you can work out what it does!

Save this file as hello.php.

Upload to OpenWhisk

To upload our action to OpenWhisk, we use the wsk tool from the command line:

$ wsk action update hello hello.php

This creates an action called hello in the default package. Packages are a useful way to group related actions and other OpenWhisk artefacts.

List our actions

To list our actions:

$ wsk action list
actions
/19FT_dev/hello                                                   private php:7.1

In this case, I have one action, hello, which is in the default package which is private (i.e. not shared) and uses the kind php:7.1. The kind is the runtime that will be used to execute the action. As the PHP version number is encoded in the kind, we’ll be able to add new runtimes that support PHP 7.2, 7.3, etc. OpenWhisk also supports Swift, NodeJS, Python, Java & arbitrary Docker containers in addition to PHP.

Running the action

There are many ways to run the action. The first way is to use the wsk tool’s action invoke command:

$ wsk action invoke --result hello
{
    "greeting": "Hello stranger!"
}

The result parameter tells the command to wait until the action completes before returning and only show the result of the action, ignoring all the metadata. If you want to see the metadata too, then use --blocking instead.

Behind the scenes, this is an API call, so you can also use curl:

$ AUTH=$(wsk property get --auth | awk '{printf("%s", $3)}' | openssl base64 | tr -d "\n")
$ curl -X POST -H "Authorization: Basic $AUTH" \
https://openwhisk.eu-gb.bluemix.net/api/v1/namespaces/_/actions/hello?blocking=true

This uses your private authentication key in the Authorization header, so don’t share this as anyone who knows the key can change your actions and create new ones!

Web actions

One of the more common uses of serverless actions is as web hook receivers to handle things as diverse as GitHub notifications, Slack commands and Alexa skills. In all these cases, you register a URL that the service will call when it needs to. Any OpenWhisk action can be configured as a “Web Action” which provides a public URL without having to worry about configuring API Gateways and what not. To do this, you pass --web true to the update command:

$ wsk action update hello --web true

You can also combine, so if you’re changing the source file, you can do:

$ wsk action update hello hello.php --web true

To find out the public URL of your action, run:

$ wsk action get hello --url
ok: got action hello
https://openwhisk.eu-gb.bluemix.net/api/v1/web/19FT_dev/default/hello

This endpoint expects you to send back status code, headers and a body. If you just want to send back the result of your action as JSON, add .json to the end and OpenWhisk will set status code to 200 and set the content-type header for you.

We can use curl to access our hello action like this:

$ curl https://openwhisk.eu-gb.bluemix.net/api/v1/web/19FT_dev/default/hello.json
{
  "greeting": "Hello stranger!"
}

This is a very convenient way to run an action and is the most common way to register one as a web hook callback on systems such as Slack or Amazon’s Alexa.

Parameters

On the command line, we can use the --param argument to pass parameters to our action:

$ wsk action invoke --result hello --param name Rob
{
    "greeting": "Hello Rob!"
}

For web actions, any parameters passed on the query string or POSTed (form encoded or JSON) are available to you in the $args array. Hence we can do:

$ curl https://openwhisk.eu-gb.bluemix.net/api/v1/web/19FT_dev/default/hello.json?name=World
{
  "greeting": "Hello World!"
}

or as a form POST:

$ curl -X POST -d name=Rob https://openwhisk.eu-gb.bluemix.net/api/v1/web/19FT_dev/default/hello.json
{
  "greeting": "Hello Rob!"
}

or even as a JSON-encoded POST:

$ curl -X POST -H "Content-Type: application/json" -d '{"name": "OpenWhisk"}' \
https://openwhisk.eu-gb.bluemix.net/api/v1/web/19FT_dev/default/hello.json
{
  "greeting": "Hello OpenWhisk!"
}

In all cases, $args['name'] in our PHP contains the parameter from the HTTP call.

Fin

This was a quick summary of how you can get going with PHP on OpenWhisk. If you want to delve deeper, have a look my FTime repository which demonstrates how to respond to a Slack command with a PHP OpenWhisk application.

3 thoughts on “Getting started with Serverless PHP

  1. Thanks for the starter post. I've not looked into OpenWhisk or serverless code much. But after reading your article, and a bit on OpenWhisk, it looks pretty compelling. Thanks Rob.

  2. Some of the openwhisk web action things have changed, the response now needs to be in a "body" field of the response array. Guess how I found that out? :) Thanks for the post!

Comments are closed.