PHP Runtime Layer for AWS Lambda

Overview

PHP Layer For AWS Lambda

Ever wanted to run PHP websites in AWS Lambda? It's your lucky day! This Lambda Runtime Layer runs the PHP 7.3/7.1 webserver in response to AWS API Gateway or AWS Application Load Balancer requests.

And, if you're looking for a great way to build serverless apps of all kinds, be sure to check out Stackery!

This is an early iteration of the PHP runtime Layer which is not yet ready for production. Please feel free to use this Layer to learn about the Lambda Layers feature and begin experimenting with PHP functions. We welcome feedback and stay tuned for the production-ready version coming soon.

Current Layer Version ARN

When creating/updating a Lambda function you must specify a specific version of the layer. This readme will be kept up to date with the latest version available. The latest available Lambda Layer Version ARNs for PHP 7.3 and 7.1 are:

arn:aws:lambda:<region>:887080169480:layer:php73:3

arn:aws:lambda:<region>:887080169480:layer:php71:10

See Releases for release notes.

Usage

General Usage

The layer runs the PHP 7.* PHP webserver in /var/task, the root directory of function code packages:

$ php -S localhost:8000 '<handler>'

The Lambda Function Handler property specifies the location of the the script executed in response to an incoming API Gateway or Application Load Balancer request.

Configuration Files

There are three locations where PHP configuration may be located:

  • Files in layer code packages located under /etc/php-${PHP_VERSION}.d/
  • Files in function code package located under /php-${PHP_VERSION}.d/
  • php.ini located at the root of the function code package

Replace ${PHP_VERSION} with '7.3', or '7.1' according to your preferred runtime.

Extensions

The following extensions are built into the layer and available in /opt/lib/php/${PHP_VERSION}/modules:

PHP 7.3 Layer:

bz2.so
calendar.so
ctype.so
curl.so
dom.so
exif.so
fileinfo.so
ftp.so
gettext.so
iconv.so
json.so
mbstring.so
mysqli.so
mysqlnd.so
pdo_mysql.so
pdo_pgsql.so
pdo.so
pdo_sqlite.so
pgsql.so
phar.so
posix.so
shmop.so
simplexml.so
sockets.so
sqlite3.so
sysvmsg.so
sysvsem.so
sysvshm.so
tokenizer.so
wddx.so
xmlreader.so
xml.so
xmlwriter.so
xsl.so

PHP 7.1 Layer:

bz2.so
calendar.so
ctype.so
curl.so
dom.so
exif.so
fileinfo.so
ftp.so
gettext.so
iconv.so
json.so
phar.so
posix.so
shmop.so
simplexml.so
sockets.so
sysvmsg.so
sysvsem.so
sysvshm.so
tokenizer.so
wddx.so
xml.so
xmlreader.so
xmlwriter.so
xsl.so
zip.so

These extensions are not loaded by default. You must add the extension to a php.ini file to use it:

extension=json.so

Extensions can be built using the lambci/lambda:build-nodejs8.10 Docker image. It is recommended that custom extensions be provided by a separate Lambda Layer with the extension .so files placed in /lib/php/${PHP_VERSION}/modules/ so they can be loaded alongside the built-in extensions listed above.

SAM Example

Let's create an AWS SAM PHP application. We suggest using Stackery to make this super simple. It automates all the scaffolding shown below. But you may also choose to roll your own application from scratch.

First, install AWS SAM CLI. Make sure to create a SAM deployment bucket as shown in Packaging your application

Next, create a basic SAM application:

$ mkdir my-php-app
$ cd my-php-app

Create a template.yaml file with the following SAM infrastructure:

AWSTemplateFormatVersion: 2010-09-09
Description: My PHP Application
Transform: AWS::Serverless-2016-10-31
Resources:
  phpserver:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub ${AWS::StackName}-phpserver
      Description: PHP Webserver
      CodeUri: src/php
      Runtime: provided
      Handler: index.php
      MemorySize: 3008
      Timeout: 30
      Tracing: Active
      Layers:
        - !Sub arn:aws:lambda:${AWS::Region}:887080169480:layer:php73:3
      Events:
        api:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: ANY

Lastly, let's write our script. Put this in index.php:

Hello World! You've reached <?php print($_SERVER['REQUEST_URI']); ?>

You should now have a directory structure like:

.
├── template.yaml
└── src
    └── php
        └── index.php

We're ready to deploy! Run the following commands:

$ sam package \
    --template-file template.yaml \
    --output-template-file serverless-output.yaml \
    --s3-bucket <your SAM deployment bucket created above>

$ sam deploy \
    --template-file serverless-output.yaml \
    --stack-name my-first-serverless-php-service \
    --capabilities CAPABILITY_IAM

Development

Build the layers by:

  1. Installing a Docker environment
  2. Running make

This will launch Docker containers that will build php73.zip and php71.zip.

If you are behind a proxy server, just set the environment variable http_proxy before invoking make, eg.:

	$ export http_proxy=http://myproxy.acme.com:8080
	$ make php73.zip

Debugging Layer Builds

Run:

	$ docker run --rm -it -v `pwd`:/opt/layer lambci/lambda:build-nodejs8.10 /bin/bash

If you are on Windows, run this instead:

	> docker run --rm -it -v %cd%:/opt/layer lambci/lambda:build-nodejs8.10 /bin/bash

then manually execute the commands in the build.sh file.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Comments
  • Value of PHP_SELF when router script is in task subdirectory

    Value of PHP_SELF when router script is in task subdirectory

    In our projects the index.php is typically in a src folder inside the task. We've set the handler as src/index.php and this successfully executes with the PHP layer.

    However, when PHP's built-in web server is run and the router is supplied in a sub-directory (e.g. php -S 0:8080 src/index.php), the value of PHP_SELF becomes the path of the URL called, rather than /src/index.php/foo/bar etc.

    If you run the code from the root (e.g. php -S 0:8080 index.php) this problem does not exist.

    I'm not sure if this behaviour is intentional or not, and that ultimately it could be a PHP issue rather than the layer, but currently it breaks the behaviour of popular routing engines such as Slim as they attempt to strip PHP_SELF from the path before evaluating routes and, therefore, fall over when it's value is actually the path.

    Just wondering if anyone else had any better insight on this problem?

    On way it could be resolved, and how I'm tempted to fix it up in our codebase for now, is to tweak the behaviour of bootstrap so that it can detect a subdirectory in _HANDLER and change to that path to run the script from PWD.

    opened by andybee 19
  • Multibyte support / mbstring extension

    Multibyte support / mbstring extension

    Many libraries depend on this, and is usually part of a default PHP install.

    It can be circumvented using the https://github.com/symfony/polyfill-mbstring library, but preferably it should be in by default.

    And congrats and thanks for a nice PHP runtime lambda layer, very easy to use!

    opened by Sarke 10
  • SimpleXML not loading

    SimpleXML not loading

    Hello, I have the following in php.ini:

    extension=simplexml.so

    However, it's not showing in phpinfo();.

    To make sure php.ini is working, I tried loading another extension (e.g., extension=json.so), and it shows in phpinfo();

    Any ideas how to make simplexml.so work? Thanks.

    Note: I'm using layer:php73:2

    opened by zkwbbr 8
  • Application load balancer requests

    Application load balancer requests

    Is version 5 of the layer expected to handle requests reaching lambda via the ALB? I keep getting 502 for such attempts. Cloud trail records a request but it appears that the error is generated in the layer, even before it reaches my application code. When I use application gateway, the request is making it all the way into the lambda function.

    opened by gszeszko 7
  • Domain masked by PHP internal server use

    Domain masked by PHP internal server use

    If you try and call $SERVER['HTTP_HOST'] to derive the requested host when running the Lambda function behind API Gateway or an Application Load Balancer, you receive localhost rather than the originating request's Host.

    I presume this is because internally we're calling PHP's development HTTP server with a http://localhost/ URL.

    This sort of comes back to a question in #11 about where the aim of the project lies in terms of PHP support in Lambda. If we aim to simulate an HTTP-driven hosting environment, we should fix this. If we're merely seeking to execute "any" PHP script in a Lambda fashion, then this doesn't necessarily need fixing. But then we should probably seek to expose the event object etc.?

    I've presumed from the approach of writing HTTP headers etc. back out in the response, we're aiming for the HTTP-like execution of PHP within the function.

    opened by andybee 7
  • fix PHP Post

    fix PHP Post

    Hi, Testing in our environment we found a bug when sending the content-length Header via ALB. The curl call stucks which i think it's a bug: https://stackoverflow.com/questions/9340734/php-curl-data-not-posted-if-headers-are-set

    I Managed to fix by making the header on-the fly with the actual sent body. For this i changed the order where we call the CURLOPT_HTTPHEADER to after the $body variable is defined.

    opened by atrope 7
  • Adding custom extensions

    Adding custom extensions

    I'm trying to add my own custom extensions. For example, I'm trying to add PDO. I've created a layer using this file: extensions-layer-1.zip

    I've added extension=pdo.so to my php.ini file.

    I'm loading the PDO extension layer after the PHP layer, but it's not showing up when I dump the list of enabled extensions.

    I have no idea how to use your specified Docker image to build a php extension correctly, so I nabbed the pdo.so file from an EC2 instance I spun up. I suspect this is probably the problem, but I'm not sure where to go from here. Suggestions?

    opened by colinpizarek 7
  • $_POST not populated on HTTP POST

    $_POST not populated on HTTP POST

    I've noticed that $_POST is not populated when sending fields (using HTTP POST) to a simple function given the sample template.

    Related to #13, what is the specific aim of this project? If we are aiming to provide a fully functioning web-server, then this should be supported. If not, then this perhaps should be down to the implementing developer to expect some payload and parse it appropriately.

    For example, developers from a REST background would expect a JSON body within a POST, but some PHP apps use application/x-www-form-urlencoded via HTML forms.

    I see in bootstrap the body of the request is being sent to the PHP webserver, however, I can't see it with var_dump(file_get_contents('php://input')); - Any Ideas? We could then provide a snippet of processing for JSON or Form Data.

    opened by martysweet 6
  • php warnings/errors attached to output

    php warnings/errors attached to output

    Whenever there are php warnings/notice/errors generated by the executing script/handler they are prepanded to the output generated by the script. These messages are formatted as html which really messes up the output (which at least in my case is json). Because that output is streamed first, the calls to the header() function generate their own warnings since that call may not follow actual output data. Furthermore, it appears that the returned html code in that case is always 200 ok, regardless of what the script actually returned.

    opened by gszeszko 5
  • [PHP 7.3] fixed issue with installing remi repo and added missing PHP extensions

    [PHP 7.3] fixed issue with installing remi repo and added missing PHP extensions

    This PR, fixes issue #38

    In the end, it was a small fix. When building the php73.zip there were errors in installing remi repo, and it all came down to the order we installed epel and remi, reverting those instructions fixed the problem.

    In term of adding the missing extensions required by Symfony 4, I only had to add php-xml and php-process to the list of php packages to be installed.

    I tested and deployed the generated layer. phpinfo can be seen here (this page will be deleted once we merge this PR).

    Side note: I did not explore, but I wonder why do we need to install httpd as part of building the image?! In my case, I'm using API Gateway to handle the requests and fire the lambda. I might be missing something but I do not think we need apache.

    opened by titomiguelcosta 4
  • mysqli extension not loading

    mysqli extension not loading

    I'm using version 7.3 and tried adding mysqli.so extension to php.ini, but it simply won't load. On the other hand, pdo_mysql.so is loading correctly.

    Any idea what may be wrong?

    Regards,

    opened by daveatpeta 4
  • php: error while loading shared libraries: libxml2.so.2: cannot open shared object file: No such file or directory

    php: error while loading shared libraries: libxml2.so.2: cannot open shared object file: No such file or directory

    Hi Guys I am trying to use php lambda layer to run my php script on lambda

    Here's my python code

    def lambda_handler(event, context):
        print(event["body"])
        result = subprocess.run(
            ['php', 'test.php', str(event['body'])],
            capture_output=False
        )
        print(result.stdout)
        return {
            'statusCode': 200,
            'body': json.dumps('Hello from Lambda!')
        }
    

    But I am getting below error when executing this function

    php: error while loading shared libraries: libxml2.so.2: cannot open shared object file: No such file or directory
    
    opened by deepaksinghcs14 1
  • PDO : Uncaught PDO exception: could not find driver

    PDO : Uncaught PDO exception: could not find driver

    I used this layer to create a PHP lambda API. I then tried to create a PDO and connect it to a MySQL database. I got the following error "Uncaught PDOException: could not find driver in /var/task/index.php"

    My php.ini file contains the following: extension=json.so extension=mysql.so extension=pdo_mysql.so extension=pdo.so extension=php_pdo_mysql.dll extension=pdo_mysql.dll

    Here is my index.php code for creating the DB $conn = null;

    $conn = new PDO('mysql:host=' . $host . ';dbname=' . $db_name, $username, $password); $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    opened by StephenKirwin 2
  • request fails with LambdaResponseTooLarge

    request fails with LambdaResponseTooLarge

    We have logic in our code that will write the response to S3 and redirect the client to the S3 URL if the content length is > 900,000. We have requests that are failing but yet that do not exceed the 900,000. I have added debug logs in the boostrap code as follows:

    $totalResponseLength = strlen(print_r($response, true)); printf("Total response length: %d\n", $totalResponseLength);

    For the request in question, the output was Total response length: 892878 which clearly is under 900,000 but yet when the lambda execution finishes, some 100K+ is added to the response length which fails the request with LambdaResponseTooLarge.

    So my question is where is the 100K+ of addition bytes coming from

    opened by johnnikho 0
  • Add a runtime for general trigger event

    Add a runtime for general trigger event

    It implemented another bootstrap for other than web server purpose (to consume events of SQS, Kinesis, ..etc).

    • Add make rule for building general event env.
    • Add new bootstrap and php files to process general event.
    • This runtime is naively ported ruby2.5 env.
    • Change the handler specification rules as "FILENAME.METHOD" or "FILENAME.CLASS.METHOD" same as in other language.

    I concern this may not be appropriate for PR, as it has largely fragmented the code. If you are interested in this and can accept it even partially, I will rework this PR.

    opened by sabmeua 0
  • Bad Content-Type with ELB

    Bad Content-Type with ELB

    If using this layer with an ELB, http header Content-Type is set to application/octet-stream instead of text/html; charset=UTF-8.

    Bug or feature ? How can I change it ?

    opened by profy12 2
Owner
Stackery
A secure platform to design, develop, and deliver modern applications
Stackery
λ Run PHP Coroutines & Fibers as-a-Service on the AWS Lambda.

λ Swoole Runtime for AWS Lambda Run PHP Coroutines & Fibers as-a-Service on the AWS Lambda. Getting started Create your Lambda function index.php <?ph

Leo Cavalcante 32 Dec 29, 2022
Bridge to use Symfony Messenger on AWS Lambda with Bref

Bridge to use Symfony Messenger on AWS Lambda with Bref. This bridge allows messages to be dispatched to SQS, SNS or EventBridge, while workers handle

bref 58 Nov 15, 2022
Lambda calculus interpreter in PHP.

lambda-php Lambda calculus interpreter in PHP. Lambda calculus Lambda calculus is a very minimal programming language that was invented in 1936 by Alo

Igor 22 Feb 28, 2022
Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda.

Our Wedding Website Because every Wedding RSVP website needs to follow DDD, CQRS, Hexagonal Architecture, Event Sourcing, and be deployed on Lambda. ?

Edd Mann 3 Aug 21, 2022
Run PHP scripts on the fly at runtime on a PocketMine-MP server (useful for debugging)

Scripter Run PHP scripts on the fly at runtime on a PocketMine-MP server. This is useful for runtime debugging, when you don't want to restart the ser

Dylan's PocketMine-MP Plugins 15 Jul 28, 2022
PeachPie - the PHP compiler and runtime for .NET and .NET Core

PeachPie Compiler The open-source PHP compiler to .NET If you run into any inconsistencies, bugs or incompatibilities, kindly let us know and we'll do

PeachPie Compiler Platform 2.1k Dec 22, 2022
Runtime Code Generator like Lombok for PocketMine-MP

PlumbokPM Runtime Code Generator like Lombok for PocketMine-MP. Code generation starts when additional autoloader detects class uses PlumbokPM annotat

OctoPush 4 Apr 18, 2022
Lumen on Docker - Skeleton project with Nginx, MySQL & PHP 8 | Aws ECS, Google Kubernates, Azure Container Engine

Docker infrastructure for Lumen Description Microservice Lumen is a starting skeleton based on Docker and Lumen Framework. This project helps to devel

Fabrizio Cafolla 218 Sep 25, 2022
Private Composer registry for private PHP packages on AWS Serverless

Tug Tug is a Composer private registry for private PHP packages installable with Composer (1 and 2). The main idea of this project is to have an inter

Fxp 33 Oct 5, 2022
This demo app shows you how to run a simple PHP application on AWS Elastic Beanstalk.

Elastic Beanstalk + PHP Demo App - "Share Your Thoughts" This demo app shows you how to run a simple PHP application on AWS Elastic Beanstalk. Run the

AWS Samples 143 Nov 26, 2022
CDK patterns for serverless container with AWS Fargate

cdk-fargate-patterns CDK patterns for serverless container with AWS Fargate DualAlbFargateService Inspired by Vijay Menon from the AWS blog post intro

Pahud Hsieh 48 Sep 1, 2021
WHMCS Automation Module For AWS EC2 Instances.

使用方法 把AWSEC2目录直接扔到 WHMCS/modules/servers 下即可 自定义字段 cloudinit (文本框 textarea 在订单页面显示) pem (文本框 textarea 仅管理员可见) data (文本框 textarea 仅管理员可见) 特性 动态IP (关机再开

CoiaPrant 9 Jan 28, 2022
AWS DynamoDB session handler for Magento (experimental!)

Magento Session Handler for AWS DynamoDB Author: Fabrizio Branca TODO: disable automatic gc create cron that does gc how does it keep track of lifetim

AOE 5 Apr 6, 2017
A Laravel artisan based package to create the AWS (SES + SNS) infrastructure to receive email event notifications with Http/Https endpoint.

Laravel SES Tracking Setup the AWS infrastructure to handle email events using SES/SNS and http/s endpoints with a single Laravel artisan command. Thi

null 11 Apr 26, 2022
This component, based on the Symfony serializer and async-aws, is a human-readable and quick abstraction to easily store serialized objects in DynamoDB 🚀.

DynamoDB Storable This component, based on the Symfony serializer and async-aws, is a human-readable and quick abstraction to easily store serialized

Matthieu W. 2 Jun 19, 2022
Simple, single-file and dependency-free AWS S3 client.

Simple, single-file and dependency-free AWS S3 client. Why? In some scenarios we want the simplest and lightest S3 client possible. For example in Bre

Matthieu Napoli 28 Nov 15, 2022
Lightweight abstraction layer for payment gateways

Slickpay is lightweight abstraction layer for payment gateways. Documentation Documentation for Slickpay can be found on official website. Licence The

Slickpay 31 Oct 26, 2021
Google Tag Manager for Magento 2 with Advance Data Layer

Google Tag Manager is a user-friendly, yet powerful and cost-effective solution that is a must-have integration for every Magento store. It simplifies the process of adding and managing third-party JavaScript tags. With dozens of custom events and hundreds of data points our extensions the #1 GTM solution for Magento.

MagePal :: Magento Extensions 241 Dec 29, 2022
Spot v2.x DataMapper built on top of Doctrine's Database Abstraction Layer

Spot DataMapper ORM v2.0 Spot v2.x is built on the Doctrine DBAL, and targets PHP 5.4+. The aim of Spot is to be a lightweight DataMapper alternative

Spot ORM 602 Dec 27, 2022