PHP Webpages using Amazon Lambda and Serverless

Submitted by nigel on Sunday 5th November 2017

My previous blog Running PHP on Amazon Lambda with Serverless showed how to create a simple PHP Lambda function using the serverless-php repo. Now we need to extend that to actually serve webpages. This tutorial goes through the steps of creating a small website with a simple PHP page served to the end user. By default AWS Lambda returns JSON objects to the browser - so we will need to fix that as we go along. 

In my previous blog we created a simple Lambda Function that we called demo. The starting point of this tutorial is to go through all the steps we did last time but instead of using demo as the name, we will use webpages. 

Ready to go
Function List

If you've correctly followed my previous blog instructions but substituted demo for webpages, and you've deployed correctly, you should see it listed in the AWS dashboard like mine above. 

Ok let the fun begin. The JavaScript shim handler.js requires no changes. 

The handler.php requires a small change. We are going to be passing escaped characters between PHP and JavaScript by JSON, so to ensure the unescaping is handled correctly in the JS, we need to add the JSON_HEX_QUOT  parameter to the PHP json_encode() function. Below I've pasted a diff output between the original from serverless-php repo and Webpages so you can see my change.

Nigels-MacBook-Pro:serverless-php-webpages nigel$ diff handler.php ../serverless-php-demo/handler.php
26c26
< printf(json_encode($response, JSON_HEX_QUOT));
---
> printf(json_encode($response));

Next you need to change the WebpagesHandler class to return in the headers the text/html value, and in the body section you'll need a HTML payload to render. I've created a very simple page which will display a title and the text Yippee! when we've got it working :)

src/WebpagesHandler.php

<?php

namespace Raines\Serverless;

class 
WebpagesHandler implements Handler
{
    
/**
     * {@inheritdoc}
     */
    
public function handle(array $eventContext $context)
    {
        
$logger $context->getLogger();
        
$logger->notice('Got event'$event);

        return [
            
'headers' => [
                
'Content-Type' => 'text/html'
            
],
            
'statusCode' => 200,
            
'body' => '<html><!doctype html><head><link rel="shortcut icon" href="#"><title>Landing Page</title></head><body><h1>Landing Page</h1><p>Yippee!</p></body></html>',
        ];
    }
}
?>
Now we can deploy the normal way and we should be good to go.
Nigels-MacBook-Pro:serverless-php-webpages nigel$ sls deploy
There are now three options for you to test out your web app.
1. AWS Lambda Console
Webpages Lambda Console

To run from the Lambda console, click on your function from the Functions list, then add a Test - I called mine MyTestEvent which passes three key/value pairs. Then click on Test. You will see output similar to my screenshot above. 

Webpages CloudWatch List
Webpages CloudWatch Log

If you click on Logs you will be redirected in a new tab to Cloudwatch and you'll see a list of log streams similar to my experience (first screenshot above). Then click on the top most log and you'll see the console output for your most recent invocation. This is ideal should you have placed console.log() traces in your code - you will see the output here. You can also see the output to the PHP $logger->notice() call in WebpagesHandler.php

2. AWS API Gateway
API Gateway Dashboard
API Gateway GET
API Gateway GET Execute

If you navigate to the Amazon API Gateway dashboard you should see your function listed (see mine in the first screenshot). Click on the webpages instance. Then click on GET under /webpages and you'll see the second screenshot. Now click on the TEST Lightning Bolt icon and the execution pane will be displayed. Scroll down and click TEST again. Your output should be similar to my third screenshot above. You should see a status 200 success like I do. 

3. Browser
API Gateway Browser

Of course you can also point a web browser to your unique URL although you won't get any logging information with this approach. It will however prove whether you have a broken layout! 

It looks like it's worked!