Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
php73.zip
php74.zip
phpunit.xml
vendor
layer.zip
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM public.ecr.aws/lambda/provided:latest

RUN dnf install -y php php-mysqlnd php-intl
62 changes: 12 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
# PHP Runtime Layer for AWS Lambda

This runtime layer aims to replicate the typical web server environment for executing PHP scripts within AWS Lambda, so that an Lambda function can be used as an alternative hosting environment for a PHP-based site.
This runtime layer aims to replicate the typical web server environment for executing PHP scripts within AWS Lambda, so that an Lambda function can be used as an alternative hosting environment for a PHP-based application.

This layer utilises the PHP CGI runtime to replicate the environment offered in other runtime setups such as PHP FPM.

## PHP 8

This repo has been updated to PHP 8.0 and with the intention of fully supporting the `arm64` Lambda environment.

Because of this this version now uses Amazon Linux Extras for a PHP 8.0 build. At the time of development, despite the stable release of 8.1, no repositories for x86 and arm64 builds of PHP 8.x were available. Should this change in the future it is hoped to update this project accordingly.

## Usage

### General Usage
Expand Down Expand Up @@ -46,70 +40,38 @@ You can optionally format the output by declaring the `ACCESS_FORMAT` variable.
The default value is `"%m %r%Q%q" %s %f %d`.

### Extensions
The following extensions are built into the layer and available in `/opt/lib/php/8.0/modules`:

```
bz2.so
calendar.so
ctype.so
curl.so
dom.so
exif.so
fileinfo.so
ftp.so
gettext.so
iconv.so
mbstring.so
mysqli.so
mysqlnd.so
pdo.so
pdo_mysql.so
pdo_sqlite.so
phar.so
simplexml.so
sockets.so
sqlite3.so
tokenizer.so
xml.so
xmlreader.so
xmlwriter.so
xsl.so
zip.so
```
When building, the default extensions for the most recent PHP version will be included in `/opt/lib/php/modules`.

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

```ini
extension=dom.so
```

It is recommended that custom extensions be provided by a separate Lambda Layer with the extension .so files placed in `/lib/php/8.0/modules/` so they can be loaded alongside the built-in extensions listed above.

### Amazon Linux 2
It is recommended that additional extensions be provided by a separate Lambda Layer with the extension .so files placed in the `/lib/php/modules` directory so they can be loaded alongside the built-in extensions listed above.

The PHP 8.0 layer is targeted to an environment running Amazon Linux 2, which at the time of development was the default environment for Lambda functions.
### Architecture

When the build script is run under an arm64 environment, it will produce a layer suitable for running within an arm64 Lambda. Similarly running under x86 will provide an x86 layer.
`arm64` is the target architecture for this Lambda layer.

## Development

### Building

To build the layer zip package you will need to launch an EC2 instance running Amazon Linux v2. Choose the architecture based on which you wish to use for your final Lambda functions.
The build process requires Docker to boot a container provided by Amazon which replicates the current Lambda environment.

Once your EC2 instance is booted and you have a copy of this repo available, run the `build.sh` script.
With a system that has Docker installed, run `./build.sh`. This script will build a new Docker image from the Amazon-supplied one, launch a container and then copy the required files for PHP to execute on Lambda from the container to the local file system, before creating a zip file.

This will build a layer zip file (`php80.zip`) for you in the current directory.
The resulting `layer.zip` file is your final Lambda layer.

### Testing

A basic PHPUnit functional test case is provided for the bootstrap. You can run this locally although this will target your local machines PHP environment.
In the `test` directory is as `run.sh` script which will launch the Amazon-supplied Lambda environment container on a local Docker install, supplying the most recent layer build on your local system to it.

```
composer test
```
This will result in an HTTP server on port 9000 which mimics the Lambda environment, ready to receive invocation requests.

This assumes you have PHP and composer setup in your local environment.
The second script in this directory, `request.sh`, provides an example of how to send a request to the HTTP server.

## Disclaimer

Expand Down
67 changes: 43 additions & 24 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,29 +1,48 @@
#!/usr/bin/env sh

REQUIRED_LIB_FILES="/usr/lib64/libedit.so.0
/usr/lib64/libonig.so.2"

echo "Building layer for PHP 8 - using Amazon Linux Extras"

amazon-linux-extras enable php8.0
yum install -y php-cli php-dom php-mbstring php-mysqlnd

mkdir /tmp/layer
cd /tmp/layer
cp /opt/layer/php.ini .
cp /opt/layer/bootstrap .
chmod a+x bootstrap

mkdir bin
cp /usr/bin/php bin/
cp /usr/bin/php-cgi bin/

mkdir lib
for LIB in $REQUIRED_LIB_FILES; do
cp $LIB lib/
# tidy up any previous attempts
rm layer.zip
rm -rf build

# this line force Docker to build for arm64 regardless of host architecture
docker buildx build --platform linux/arm64 -t aiir/php .

# create a container from the docker image, which should contain a PHP installation
docker run -d --name dummy --platform linux/arm64 --entrypoint sleep aiir/php infinity

# extract the required files from the container to the host file system
mkdir -p build/bin build/lib/php

docker cp dummy:/usr/bin/php build/bin/
docker cp dummy:/usr/bin/php-cgi build/bin/

EXTENSION_DIR=$(docker exec dummy php -r "echo ini_get('extension_dir');")

docker cp -a "dummy:$EXTENSION_DIR" build/lib/php/modules

# get all unique shared library dependencies for both binaries, resolve symlinks, and copy both symlink and real file
docker exec dummy sh -c "
ldd /usr/bin/php /usr/bin/php-cgi $EXTENSION_DIR/*.so \
| grep -oP '(?<=> )/[^ ]+' \
| sort -u \
| while read -r lib; do
echo \"\$lib\"
readlink -f \"\$lib\"
done \
| sort -u
" | while read -r path; do
docker cp "dummy:$path" build/lib/
done

mkdir -p lib/php/8.0
cp -a /usr/lib64/php/modules lib/php/8.0/
# destroy the container
docker rm -f dummy

# copy the bootstrap and config
cp src/bootstrap build/
cp src/php.ini build/

zip -r /opt/layer/php80.zip .
# create the layer zip file
cd build
zip -ry ../layer.zip .
cd ..
rm -rf build
29 changes: 0 additions & 29 deletions composer.json

This file was deleted.

Loading