Skip to content

Commit

Permalink
Initial checkin
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy Raines committed Apr 14, 2017
1 parent 211038b commit c956b2c
Show file tree
Hide file tree
Showing 14 changed files with 394 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitattributes
@@ -0,0 +1 @@
php filter=lfs diff=lfs merge=lfs -text
13 changes: 13 additions & 0 deletions .gitignore
@@ -0,0 +1,13 @@
# PHP
/vendor/
.php_cs.cache

# Serverless directories
.serverless

# NPM
node_modules/

# Editors / OS
*.swp
.DS_Store
1 change: 1 addition & 0 deletions LICENSE
@@ -1,6 +1,7 @@
MIT License

Copyright (c) 2017 Andy Raines
Copyright (c) 2016 Robert Anderson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
45 changes: 44 additions & 1 deletion README.md
@@ -1,2 +1,45 @@
# serverless-php
PHP for AWS Lambda via Serverless Framework
PHP for AWS Lambda via Serverless Framework using Symfony components for
dependency injection.

This repository is set up with [Git LFS](https://git-lfs.github.com/) for the
php executable, so make sure you have it installed and supported.

## Prerequisites
* [Serverless](https://serverless.com/)
* [Node](https://nodejs.org)
* [Composer](https://getcomposer.org/)

## Deploying to AWS
```
composer install -o --no-dev
serverless deploy
```

## Running locally
```
serverless invoke local -f hello
```

## Running on AWS
```
serverless invoke -f hello
```

# Rebuilding PHP Binary
The PHP binary can be built with any flags you require and at any version.

## Prerequisites
* [Docker](https://www.docker.com/)

## Compiling
```
sh buildphp.sh
```

## Altering compile flags etc
Edit `buildphp.sh` and `dockerfile.buildphp` to alter it.

# Thanks
* [Robert Anderson](https://github.com/ZeroSharp/serverless-php) for the
inspiration and base for this project
19 changes: 19 additions & 0 deletions buildphp.sh
@@ -0,0 +1,19 @@
#!/bin/sh

# This script builds a docker container, compiles PHP for use with AWS Lambda,
# and copies the final binary to the host and then removes the container.
#
# You can specify the PHP Version by setting the branch corresponding to the
# source from https://github.com/php/php-src

PHP_VERSION_GIT_BRANCH=php-7.1.2

echo "Build PHP Binary from current branch '$PHP_VERSION_GIT_BRANCH' on https://github.com/php/php-src"

docker build --build-arg PHP_VERSION=$PHP_VERSION_GIT_BRANCH -t php-build -f dockerfile.buildphp .

container=$(docker create php-build)

docker -D cp $container:/php-src-$PHP_VERSION_GIT_BRANCH/sapi/cli/php .

docker rm $container
20 changes: 20 additions & 0 deletions composer.json
@@ -0,0 +1,20 @@
{
"name": "araines/serverless-php",
"description": "Boilerplate project for Serverless Framework and PHP",
"type": "project",
"autoload": {
"psr-4": {
"Raines\\Serverless\\": "src"
}
},
"require": {
"monolog/monolog": "^1.22",
"php": "^7.0",
"psr/log": "^1.0",
"symfony/config": "^3.2",
"symfony/dependency-injection": "^3.2",
"symfony/yaml": "^3.2"
},
"require-dev": {
}
}
34 changes: 34 additions & 0 deletions config/services.yml
@@ -0,0 +1,34 @@
parameters:
logging_level: !php/const:Monolog\Logger::INFO

services:
logger:
class: Monolog\Logger
arguments:
- 'handler'
calls:
- [pushHandler, ['@logging.handler']]

logging.formatter:
class: Monolog\Formatter\LineFormatter
arguments:
- '%%message%% %%context%% %%extra%%'

logging.handler:
class: Monolog\Handler\StreamHandler
arguments:
- 'php://stderr'
- '%logging_level%'
calls:
- [setFormatter, ['@logging.formatter']]

# Define your own handlers and other services here
handler.hello:
class: Raines\Serverless\HelloHandler
arguments:
- '@logger'

# handler.example:
# class: Acme\ExampleHandler
# arguments:
# - '@logger'
43 changes: 43 additions & 0 deletions dockerfile.buildphp
@@ -0,0 +1,43 @@
# Compile PHP with static linked dependencies
# to create a single running binary

FROM amazonlinux

ARG PHP_VERSION

RUN yum install \
autoconf \
automake \
libtool \
bison \
re2c \
libxml2-devel \
openssl-devel \
libpng-devel \
libjpeg-devel \
curl-devel -y

RUN curl -sL https://github.com/php/php-src/archive/$PHP_VERSION.tar.gz | tar -zxv

WORKDIR /php-src-$PHP_VERSION

RUN ./buildconf --force

RUN ./configure \
--enable-static=yes \
--enable-shared=no \
--disable-all \
--enable-json \
--enable-libxml \
--enable-mbstring \
--enable-phar \
--enable-soap \
--enable-xml \
--with-curl \
--with-gd \
--with-zlib \
--with-openssl \
--without-pear \
--enable-ctype

RUN make -j 5
32 changes: 32 additions & 0 deletions handler.js
@@ -0,0 +1,32 @@
'use strict';

var child_process = require('child_process');

module.exports.handle = (event, context, callback) => {

var response = '';
var php = './php';

// When using 'serverless invoke local' use the system PHP binary instead
if (typeof process.env.PWD !== "undefined") {
php = 'php';
}

var proc = child_process.spawn(php, ["handler.php", JSON.stringify(event)]);

proc.stdout.on('data', function (data) {
response += data.toString()
});

proc.stderr.on('data', function (data) {
console.log(`${data}`);
});

proc.on('close', function(code) {
if (code !== 0) {
return callback(new Error(`Process error code ${code}: ${response}`));
}

callback(null, JSON.parse(response));
});
};
22 changes: 22 additions & 0 deletions handler.php
@@ -0,0 +1,22 @@
<?php

$loader = require __DIR__ . '/vendor/autoload.php';

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

// Set up service container
$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/config'));
$loader->load('services.yml');

// Get event object
$event = json_decode($argv[1], true) ?: [];

// Get the handler service and execute
$handler = $container->get(getenv('HANDLER'));
$response = $handler->handle($event);

// Send data back to shim
printf(json_encode($response));
3 changes: 3 additions & 0 deletions php
Git LFS file not shown
116 changes: 116 additions & 0 deletions serverless.yml
@@ -0,0 +1,116 @@
# Welcome to Serverless!
#
# This file is the main config file for your service.
# It's very minimal at this point and uses default values.
# You can always add more config options for more control.
# We've included some commented out config examples here.
# Just uncomment any of them to get that config option.
#
# For full config options, check the docs:
# docs.serverless.com
#
# Happy Coding!

service: php-hello-world # NOTE: update this with your service name

# You can pin your service to only deploy with a specific Serverless version
# Check out our docs for more details
# frameworkVersion: "=X.X.X"

provider:
name: aws
runtime: nodejs6.10

# you can overwrite defaults here
# stage: dev
# region: us-east-1

# you can add statements to the Lambda function's IAM Role here
# iamRoleStatements:
# - Effect: "Allow"
# Action:
# - "s3:ListBucket"
# Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] }
# - Effect: "Allow"
# Action:
# - "s3:PutObject"
# Resource:
# Fn::Join:
# - ""
# - - "arn:aws:s3:::"
# - "Ref" : "ServerlessDeploymentBucket"
# - "/*"

# you can define service wide environment variables here
# environment:
# variable1: value1

# you can add packaging information here
#package:
# include:
# - include-me.js
# - include-me-dir/**
# exclude:
# - exclude-me.js
# - exclude-me-dir/**
package:
exclude:
- '*'
- '**'
include:
- config/**
- handler.js
- handler.php
- php
- src/**
- vendor/**

functions:
hello:
handler: handler.handle
environment:
HANDLER: handler.hello # This is the service name which will be used (from services.yml)
events:
- http:
path: hello
method: get

# The following are a few example events you can configure
# NOTE: Please make sure to change your handler code to work with those events
# Check the event documentation for details
# events:
# - http:
# path: users/create
# method: get
# - s3: ${env:BUCKET}
# - schedule: rate(10 minutes)
# - sns: greeter-topic
# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000
# - alexaSkill
# - iot:
# sql: "SELECT * FROM 'some_topic'"
# - cloudwatchEvent:
# event:
# source:
# - "aws.ec2"
# detail-type:
# - "EC2 Instance State-change Notification"
# detail:
# state:
# - pending

# Define function environment variables here
# environment:
# variable2: value2

# you can add CloudFormation resource templates here
#resources:
# Resources:
# NewResource:
# Type: AWS::S3::Bucket
# Properties:
# BucketName: my-new-bucket
# Outputs:
# NewOutput:
# Description: "Description for the output"
# Value: "Some output value"
15 changes: 15 additions & 0 deletions src/Handler.php
@@ -0,0 +1,15 @@
<?php

namespace Raines\Serverless;

interface Handler
{
/**
* Handle the Lambda event.
*
* @param array $event The event information array.
*
* @return mixed Response for the lambda. Must be json encodeable.
*/
public function handle(array $event);
}

0 comments on commit c956b2c

Please sign in to comment.