├── .github
└── pull_request_template.md
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── bootstrap
├── build-php-remi.sh
├── build.sh
├── create-buckets.sh
├── php.ini
├── publish.sh
├── regions.sh
├── unpublish.sh
└── upload.sh
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | Please make sure pull requests are opened against the development branch. Pull requests opened against master will be closed automatically. Please delete this line once you have confirmed the correct branch.
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | php71.zip
2 | php73.zip
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------
2 | The PHP License, version 3.01
3 | Copyright (c) 1999 - 2018 The PHP Group. All rights reserved.
4 | --------------------------------------------------------------------
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, is permitted provided that the following conditions
8 | are met:
9 |
10 | 1. Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | 2. Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in
15 | the documentation and/or other materials provided with the
16 | distribution.
17 |
18 | 3. The name "PHP" must not be used to endorse or promote products
19 | derived from this software without prior written permission. For
20 | written permission, please contact group@php.net.
21 |
22 | 4. Products derived from this software may not be called "PHP", nor
23 | may "PHP" appear in their name, without prior written permission
24 | from group@php.net. You may indicate that your software works in
25 | conjunction with PHP by saying "Foo for PHP" instead of calling
26 | it "PHP Foo" or "phpfoo"
27 |
28 | 5. The PHP Group may publish revised and/or new versions of the
29 | license from time to time. Each version will be given a
30 | distinguishing version number.
31 | Once covered code has been published under a particular version
32 | of the license, you may always continue to use it under the terms
33 | of that version. You may also choose to use such covered code
34 | under the terms of any subsequent version of the license
35 | published by the PHP Group. No one other than the PHP Group has
36 | the right to modify the terms applicable to covered code created
37 | under this License.
38 |
39 | 6. Redistributions of any form whatsoever must retain the following
40 | acknowledgment:
41 | "This product includes PHP software, freely available from
42 | ".
43 |
44 | THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
45 | ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
46 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
48 | DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
49 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
51 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55 | OF THE POSSIBILITY OF SUCH DAMAGE.
56 |
57 | --------------------------------------------------------------------
58 |
59 | This software consists of voluntary contributions made by many
60 | individuals on behalf of the PHP Group.
61 |
62 | The PHP Group can be contacted via Email at group@php.net.
63 |
64 | For more information on the PHP Group and the PHP project,
65 | please see .
66 |
67 | PHP includes the Zend Engine, freely available at
68 | .
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
2 |
3 | all: php71.zip php73.zip
4 |
5 | php71.zip:
6 | docker run --rm -e http_proxy=${http_proxy} -v $(ROOT_DIR):/opt/layer lambci/lambda:build-provided /opt/layer/build.sh
7 |
8 | php73.zip:
9 | docker run --rm -e http_proxy=${http_proxy} -v $(ROOT_DIR):/opt/layer lambci/lambda:build-provided /opt/layer/build-php-remi.sh 3
10 |
11 | upload71: php71.zip
12 | ./upload.sh 7.1
13 |
14 | upload73: php73.zip
15 | ./upload.sh 7.3
16 |
17 | publish71: php71.zip
18 | ./publish.sh 7.1
19 |
20 | publish73: php73.zip
21 | ./publish.sh 7.3
22 |
23 | clean:
24 | rm -f php71.zip php73.zip
25 |
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP Layer For AWS Lambda
2 |
3 | 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](http://php.net/manual/en/features.commandline.webserver.php) in response to [AWS API Gateway](https://aws.amazon.com/api-gateway/) or [AWS Application Load Balancer](https://aws.amazon.com/elasticloadbalancing/features/#Details_for_Elastic_Load_Balancing_Products) requests.
4 |
5 | And, if you're looking for a great way to build serverless apps of all kinds, be sure to check out [Stackery](https://stackery.io)!
6 |
7 | 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.
8 |
9 | ## Current Layer Version ARN
10 | 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:
11 |
12 | **arn:aws:lambda:\:887080169480:layer:php73:3**
13 |
14 | **arn:aws:lambda:\:887080169480:layer:php71:10**
15 |
16 | See [Releases](https://github.com/stackery/php-lambda-layer/releases) for release notes.
17 |
18 | ### Usage
19 | #### General Usage
20 | The layer runs the PHP 7.* [PHP webserver](http://php.net/manual/en/features.commandline.webserver.php) in /var/task, the root directory of function code packages:
21 |
22 | ```sh
23 | $ php -S localhost:8000 ''
24 | ```
25 |
26 | 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.
27 |
28 | #### Configuration Files
29 | There are three locations where PHP configuration may be located:
30 |
31 | * Files in layer code packages located under /etc/php-${PHP_VERSION}.d/
32 | * Files in function code package located under /php-${PHP_VERSION}.d/
33 | * php.ini located at the root of the function code package
34 |
35 | Replace ${PHP_VERSION} with '7.3', or '7.1' according to your preferred runtime.
36 |
37 | ##### Extensions
38 | The following extensions are built into the layer and available in /opt/lib/php/${PHP_VERSION}/modules:
39 |
40 | PHP 7.3 Layer:
41 | ```
42 | bz2.so
43 | calendar.so
44 | ctype.so
45 | curl.so
46 | dom.so
47 | exif.so
48 | fileinfo.so
49 | ftp.so
50 | gettext.so
51 | iconv.so
52 | json.so
53 | mbstring.so
54 | mysqli.so
55 | mysqlnd.so
56 | pdo_mysql.so
57 | pdo_pgsql.so
58 | pdo.so
59 | pdo_sqlite.so
60 | pgsql.so
61 | phar.so
62 | posix.so
63 | shmop.so
64 | simplexml.so
65 | sockets.so
66 | sqlite3.so
67 | sysvmsg.so
68 | sysvsem.so
69 | sysvshm.so
70 | tokenizer.so
71 | wddx.so
72 | xmlreader.so
73 | xml.so
74 | xmlwriter.so
75 | xsl.so
76 | ```
77 |
78 | PHP 7.1 Layer:
79 | ```
80 | bz2.so
81 | calendar.so
82 | ctype.so
83 | curl.so
84 | dom.so
85 | exif.so
86 | fileinfo.so
87 | ftp.so
88 | gettext.so
89 | iconv.so
90 | json.so
91 | phar.so
92 | posix.so
93 | shmop.so
94 | simplexml.so
95 | sockets.so
96 | sysvmsg.so
97 | sysvsem.so
98 | sysvshm.so
99 | tokenizer.so
100 | wddx.so
101 | xml.so
102 | xmlreader.so
103 | xmlwriter.so
104 | xsl.so
105 | zip.so
106 | ```
107 |
108 | These extensions are not loaded by default. You must add the extension to a php.ini file to use it:
109 |
110 | ```ini
111 | extension=json.so
112 | ```
113 |
114 | 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.
115 |
116 | #### SAM Example
117 | Let's create an AWS SAM PHP application. We suggest using [Stackery](https://stackery.io) to make this super simple. It automates all the scaffolding shown below. But you may also choose to roll your own application from scratch.
118 |
119 | First, install [AWS SAM CLI](https://github.com/awslabs/aws-sam-cli). Make sure to create a SAM deployment bucket as shown in [Packaging your application](https://github.com/awslabs/aws-sam-cli/blob/develop/docs/deploying_serverless_applications.rst#packaging-your-application)
120 |
121 | Next, create a basic SAM application:
122 |
123 | ```sh
124 | $ mkdir my-php-app
125 | $ cd my-php-app
126 | ```
127 |
128 | Create a template.yaml file with the following SAM infrastructure:
129 |
130 | ```yaml
131 | AWSTemplateFormatVersion: 2010-09-09
132 | Description: My PHP Application
133 | Transform: AWS::Serverless-2016-10-31
134 | Resources:
135 | phpserver:
136 | Type: AWS::Serverless::Function
137 | Properties:
138 | FunctionName: !Sub ${AWS::StackName}-phpserver
139 | Description: PHP Webserver
140 | CodeUri: src/php
141 | Runtime: provided
142 | Handler: index.php
143 | MemorySize: 3008
144 | Timeout: 30
145 | Tracing: Active
146 | Layers:
147 | - !Sub arn:aws:lambda:${AWS::Region}:887080169480:layer:php73:3
148 | Events:
149 | api:
150 | Type: Api
151 | Properties:
152 | Path: /{proxy+}
153 | Method: ANY
154 | ```
155 |
156 | Lastly, let's write our script. Put this in `index.php`:
157 |
158 | ```php
159 | Hello World! You've reached
160 |
161 | ```
162 |
163 | You should now have a directory structure like:
164 |
165 | ```
166 | .
167 | ├── template.yaml
168 | └── src
169 | └── php
170 | └── index.php
171 | ```
172 |
173 | We're ready to deploy! Run the following commands:
174 |
175 | ```sh
176 | $ sam package \
177 | --template-file template.yaml \
178 | --output-template-file serverless-output.yaml \
179 | --s3-bucket
180 |
181 | $ sam deploy \
182 | --template-file serverless-output.yaml \
183 | --stack-name my-first-serverless-php-service \
184 | --capabilities CAPABILITY_IAM
185 | ```
186 |
187 | ### Development
188 | Build the layers by:
189 |
190 | 1. Installing a Docker environment
191 | 1. Running `make`
192 |
193 | This will launch Docker containers that will build php73.zip and php71.zip.
194 |
195 | If you are behind a proxy server, just set the environment variable `http_proxy` before
196 | invoking `make`, eg.:
197 |
198 | ```sh
199 | $ export http_proxy=http://myproxy.acme.com:8080
200 | $ make php73.zip
201 | ```
202 |
203 | #### Debugging Layer Builds
204 |
205 | Run:
206 |
207 | ```sh
208 | $ docker run --rm -it -v `pwd`:/opt/layer lambci/lambda:build-nodejs8.10 /bin/bash
209 | ```
210 |
211 | If you are on Windows, run this instead:
212 |
213 | ```sh
214 | > docker run --rm -it -v %cd%:/opt/layer lambci/lambda:build-nodejs8.10 /bin/bash
215 | ```
216 |
217 | then manually execute the commands in the build.sh file.
218 |
219 | ### Disclaimer
220 |
221 | > THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
222 | > ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
223 | > THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
224 | > PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
225 | > DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
226 | > INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
227 | > (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
228 | > SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
229 | > HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
230 | > STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
231 | > ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
232 | > OF THE POSSIBILITY OF SUCH DAMAGE.
233 |
--------------------------------------------------------------------------------
/bootstrap:
--------------------------------------------------------------------------------
1 | #!/opt/bin/php -c/opt/php.ini
2 | 'Continue',101=>'Switching Protocols',102=>'Processing',200=>'OK',201=>'Created',202=>'Accepted',203=>'Non-Authoritative Information',204=>'No Content',205=>'Reset Content',206=>'Partial Content',207=>'Multi-Status',208=>'Already Reported',226=>'IM Used',300=>'Multiple Choices',301=>'Moved Permanently',302=>'Found',303=>'See Other',304=>'Not Modified',305=>'Use Proxy',306=>'Switch Proxy',307=>'Temporary Redirect',308=>'Permanent Redirect',400=>'Bad Request',401=>'Unauthorized',402=>'Payment Required',403=>'Forbidden',404=>'Not Found',405=>'Method Not Allowed',406=>'Not Acceptable',407=>'Proxy Authentication Required',408=>'Request Timeout',409=>'Conflict',410=>'Gone',411=>'Length Required',412=>'Precondition Failed',413=>'Request Entity Too Large',414=>'Request-URI Too Long',415=>'Unsupported Media Type',416=>'Requested Range Not Satisfiable',417=>'Expectation Failed',418=>'I\'m a teapot',419=>'Authentication Timeout',420=>'Enhance Your Calm',420=>'Method Failure',422=>'Unprocessable Entity',423=>'Locked',424=>'Failed Dependency',424=>'Method Failure',425=>'Unordered Collection',426=>'Upgrade Required',428=>'Precondition Required',429=>'Too Many Requests',431=>'Request Header Fields Too Large',444=>'No Response',449=>'Retry With',450=>'Blocked by Windows Parental Controls',451=>'Redirect',451=>'Unavailable For Legal Reasons',494=>'Request Header Too Large',495=>'Cert Error',496=>'No Cert',497=>'HTTP to HTTPS',499=>'Client Closed Request',500=>'Internal Server Error',501=>'Not Implemented',502=>'Bad Gateway',503=>'Service Unavailable',504=>'Gateway Timeout',505=>'HTTP Version Not Supported',506=>'Variant Also Negotiates',507=>'Insufficient Storage',508=>'Loop Detected',509=>'Bandwidth Limit Exceeded',510=>'Not Extended',511=>'Network Authentication Required',598=>'Network read timeout error',599=>'Network connect timeout error'];
10 |
11 | function start_webserver() {
12 | $SERVER_STARTUP_TIMEOUT = 1000000; // 1 second
13 |
14 | $pid = pcntl_fork();
15 | switch($pid) {
16 | case -1:
17 | die("Failed to fork webserver process\n");
18 |
19 | case 0:
20 | // exec the command
21 | $HANDLER = getenv('_HANDLER');
22 | $phpMinorVersion = PHP_MINOR_VERSION;
23 | $handler_components = explode('/', $HANDLER);
24 | $handler_filename = array_pop($handler_components);
25 | $handler_path = implode('/', array_merge(['/var/task'], $handler_components));
26 | chdir($handler_path);
27 | exec("PHP_INI_SCAN_DIR=/opt/etc/php-7.${phpMinorVersion}.d/:/var/task/php-7.${phpMinorVersion}.d/ php -S localhost:8000 -c /var/task/php.ini -d extension_dir=/opt/lib/php/7.${phpMinorVersion}/modules '$handler_filename'");
28 | exit;
29 |
30 | default:
31 | // Wait for child server to start
32 | $start = microtime(true);
33 |
34 | do {
35 | if (microtime(true) - $start > $SERVER_STARTUP_TIMEOUT) {
36 | die("Webserver failed to start within one second\n");
37 | }
38 |
39 | usleep(1000);
40 | $fp = @fsockopen('localhost', 8000, $errno, $errstr, 1);
41 | } while ($fp == false);
42 |
43 | fclose($fp);
44 | }
45 | }
46 |
47 | function fail($AWS_LAMBDA_RUNTIME_API, $invocation_id, $message) {
48 | $ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/$invocation_id/response");
49 |
50 | $response = array();
51 |
52 | $response['statusCode'] = 500;
53 | $response['body'] = $message;
54 |
55 | $response_json = json_encode($response);
56 |
57 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
58 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
59 | curl_setopt($ch, CURLOPT_POSTFIELDS, $response_json);
60 | curl_setopt($ch, CURLOPT_HTTPHEADER, array(
61 | 'Content-Type: application/json',
62 | 'Content-Length: ' . strlen($response_json)
63 | ));
64 |
65 | curl_exec($ch);
66 | curl_close($ch);
67 | }
68 |
69 | start_webserver();
70 |
71 | while (true) {
72 | $ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/next");
73 |
74 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
75 | curl_setopt($ch, CURLOPT_FAILONERROR, TRUE);
76 |
77 | $invocation_id = '';
78 |
79 | curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$invocation_id) {
80 | if (!preg_match('/:\s*/', $header)) {
81 | return strlen($header);
82 | }
83 |
84 | [$name, $value] = preg_split('/:\s*/', $header, 2);
85 |
86 | if (strtolower($name) == 'lambda-runtime-aws-request-id') {
87 | $invocation_id = trim($value);
88 | }
89 |
90 | return strlen($header);
91 | });
92 |
93 | $body = '';
94 |
95 | curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$body) {
96 | $body .= $chunk;
97 |
98 | return strlen($chunk);
99 | });
100 |
101 | curl_exec($ch);
102 |
103 | if (curl_error($ch)) {
104 | die('Failed to fetch next Lambda invocation: ' . curl_error($ch) . "\n");
105 | }
106 |
107 | if ($invocation_id == '') {
108 | die("Failed to determine Lambda invocation ID\n");
109 | }
110 |
111 | curl_close($ch);
112 |
113 | if (!$body) {
114 | die("Empty Lambda invocation response\n");
115 | }
116 |
117 | $event = json_decode($body, TRUE);
118 |
119 | if (!array_key_exists('requestContext', $event)) {
120 | fail($AWS_LAMBDA_RUNTIME_API, $invocation_id, 'Event is not an API Gateway request');
121 | continue;
122 | }
123 |
124 | $uri = $event['path'];
125 |
126 | if (array_key_exists('multiValueQueryStringParameters', $event) && $event['multiValueQueryStringParameters']) {
127 | $first = TRUE;
128 | foreach ($event['multiValueQueryStringParameters'] as $name => $values) {
129 | foreach ($values as $value) {
130 | if ($first) {
131 | $uri .= "?";
132 | $first = FALSE;
133 | } else {
134 | $uri .= "&";
135 | }
136 |
137 | $uri .= $name;
138 |
139 | if ($value != '') {
140 | $uri .= '=' . $value;
141 | }
142 | }
143 | }
144 | }
145 |
146 | $ch = curl_init("http://localhost:8000$uri");
147 |
148 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, FALSE);
149 |
150 | if (array_key_exists('multiValueHeaders', $event)) {
151 | $headers = array();
152 |
153 | foreach ($event['multiValueHeaders'] as $name => $values) {
154 | foreach ($values as $value) {
155 | array_push($headers, "${name}: ${value}");
156 | }
157 | }
158 |
159 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
160 | }
161 |
162 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $event['httpMethod']);
163 |
164 | if (array_key_exists('body', $event)) {
165 | $body = $event['body'];
166 | if (array_key_exists('isBase64Encoded', $event) && $event['isBase64Encoded']) {
167 | $body = base64_decode($body);
168 | }
169 | } else {
170 | $body = '';
171 | }
172 |
173 | if (strlen($body) > 0) {
174 | curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
175 | }
176 |
177 | $response = array();
178 | $response['multiValueHeaders'] = array();
179 | $response['body'] = '';
180 |
181 | curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$response) {
182 | if (preg_match('/HTTP\/1.1 (\d+) .*/', $header, $matches)) {
183 | $response['statusCode'] = intval($matches[1]);
184 | return strlen($header);
185 | }
186 |
187 | if (!preg_match('/:\s*/', $header)) {
188 | return strlen($header);
189 | }
190 |
191 | [$name, $value] = preg_split('/:\s*/', $header, 2);
192 |
193 | $name = trim($name);
194 | $value = trim($value);
195 |
196 | if ($name == '') {
197 | return strlen($header);
198 | }
199 |
200 | if (!array_key_exists($name, $response['multiValueHeaders'])) {
201 | $response['multiValueHeaders'][$name] = array();
202 | }
203 |
204 | array_push($response['multiValueHeaders'][$name], $value);
205 |
206 | return strlen($header);
207 | });
208 |
209 | curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$response) {
210 | $response['body'] .= $chunk;
211 |
212 | return strlen($chunk);
213 | });
214 |
215 | curl_exec($ch);
216 | curl_close($ch);
217 |
218 | $ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/$invocation_id/response");
219 |
220 | $isALB = array_key_exists("elb", $event['requestContext']);
221 | if ($isALB) { // Add Headers For ALB
222 | $status = $response["statusCode"];
223 | if (array_key_exists($status, $http_codes)) {
224 | $response["statusDescription"] = "$status ". $http_codes[$status];
225 | } else {
226 | $response["statusDescription"] = "$status Unknown";
227 | }
228 | $response["isBase64Encoded"] = false;
229 | }
230 | $response_json = json_encode($response);
231 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
232 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
233 | curl_setopt($ch, CURLOPT_POSTFIELDS, $response_json);
234 | if (!$isALB){
235 | curl_setopt($ch, CURLOPT_HTTPHEADER, array(
236 | 'Content-Type: application/json',
237 | 'Content-Length: ' . strlen($response_json)
238 | ));
239 | }
240 | curl_exec($ch);
241 | curl_close($ch);
242 | }
243 |
244 | ?>
245 |
--------------------------------------------------------------------------------
/build-php-remi.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | PHP_MINOR_VERSION=$1
4 |
5 | echo "Building layer for PHP 7.$PHP_MINOR_VERSION - using Remi repository"
6 |
7 | yum install -y wget
8 | yum install -y yum-utils
9 | wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
10 | wget https://rpms.remirepo.net/enterprise/remi-release-6.rpm
11 | rpm -Uvh epel-release-latest-6.noarch.rpm
12 | rpm -Uvh remi-release-6.rpm
13 |
14 | yum-config-manager --enable remi-php7${PHP_MINOR_VERSION}
15 |
16 | yum install -y httpd
17 | yum install -y postgresql-devel
18 | yum install -y libargon2-devel
19 |
20 | yum install -y --disablerepo="*" --enablerepo="remi,remi-php7${PHP_MINOR_VERSION}" php php-mbstring php-pdo php-mysql php-pgsql php-xml php-process
21 |
22 |
23 | mkdir /tmp/layer
24 | cd /tmp/layer
25 | cp /opt/layer/bootstrap bootstrap
26 | sed "s/PHP_MINOR_VERSION/${PHP_MINOR_VERSION}/g" /opt/layer/php.ini >php.ini
27 |
28 | mkdir bin
29 | cp /usr/bin/php bin/
30 |
31 | mkdir lib
32 | for lib in libncurses.so.5 libtinfo.so.5 libpcre.so.0; do
33 | cp "/lib64/${lib}" lib/
34 | done
35 |
36 | cp /usr/lib64/libedit.so.0 lib/
37 | cp /usr/lib64/libargon2.so.0 lib/
38 | cp /usr/lib64/libpq.so.5 lib/
39 | cp /usr/lib64/libonig.so.5 lib/
40 |
41 | mkdir -p lib/php/7.${PHP_MINOR_VERSION}
42 | cp -a /usr/lib64/php/modules lib/php/7.${PHP_MINOR_VERSION}/
43 |
44 | zip -r /opt/layer/php7${PHP_MINOR_VERSION}.zip .
45 |
46 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | yum install -y php71-mbstring.x86_64 zip php71-pgsql php71-mysqli
4 |
5 | mkdir /tmp/layer
6 | cd /tmp/layer
7 | cp /opt/layer/bootstrap .
8 | sed "s/PHP_MINOR_VERSION/1/g" /opt/layer/php.ini >php.ini
9 |
10 | mkdir bin
11 | cp /usr/bin/php bin/
12 |
13 | mkdir lib
14 | for lib in libncurses.so.5 libtinfo.so.5 libpcre.so.0; do
15 | cp "/lib64/${lib}" lib/
16 | done
17 |
18 | cp /usr/lib64/libedit.so.0 lib/
19 | cp /usr/lib64/libpq.so.5 lib/
20 |
21 | cp -a /usr/lib64/php lib/
22 |
23 | zip -r /opt/layer/php71.zip .
--------------------------------------------------------------------------------
/create-buckets.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | source regions.sh
4 |
5 | for region in "${PHP71_REGIONS[@]}"; do
6 | bucket_name="stackery-layers-${region}"
7 |
8 | echo "Creating bucket ${bucket_name}..."
9 |
10 | aws s3 mb s3://$bucket_name --region $region
11 | done
--------------------------------------------------------------------------------
/php.ini:
--------------------------------------------------------------------------------
1 | extension_dir=/opt/lib/php/7.PHP_MINOR_VERSION/modules
2 | display_errors=On
3 |
4 | extension=curl.so
5 | extension=json.so
6 |
--------------------------------------------------------------------------------
/publish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | source regions.sh
4 |
5 | PHP_VERSION="${1}"
6 |
7 | LAYER="php${PHP_VERSION//.}"
8 | MD5SUM=$(md5 -q "${LAYER}.zip")
9 | S3KEY="${LAYER}/${MD5SUM}"
10 |
11 | for region in "${PHP_REGIONS[@]}"; do
12 | bucket_name="stackery-layers-${region}"
13 |
14 | echo "Publishing Lambda Layer ${LAYER} in region ${region}..."
15 | # Must use --cli-input-json so AWS CLI doesn't attempt to fetch license URL
16 | version=$(aws --region $region lambda publish-layer-version --cli-input-json "{\"LayerName\": \"${LAYER}\",\"Description\": \"PHP ${PHP_VERSION} Web Server Lambda Runtime\",\"Content\": {\"S3Bucket\": \"${bucket_name}\",\"S3Key\": \"${S3KEY}\"},\"CompatibleRuntimes\": [\"provided\"],\"LicenseInfo\": \"http://www.php.net/license/3_01.txt\"}" --output text --query Version)
17 | echo "Published Lambda Layer ${LAYER} in region ${region} version ${version}"
18 |
19 | echo "Setting public permissions on Lambda Layer ${LAYER} version ${version} in region ${region}..."
20 | aws --region $region lambda add-layer-version-permission --layer-name "${LAYER}" --version-number $version --statement-id=public --action lambda:GetLayerVersion --principal '*' > /dev/null
21 | echo "Public permissions set on Lambda Layer ${LAYER} version ${version} in region ${region}"
22 | done
23 |
--------------------------------------------------------------------------------
/regions.sh:
--------------------------------------------------------------------------------
1 | PHP_REGIONS=(
2 | ap-northeast-1
3 | ap-northeast-2
4 | ap-south-1
5 | ap-southeast-1
6 | ap-southeast-2
7 | ca-central-1
8 | eu-central-1
9 | eu-west-1
10 | eu-west-2
11 | eu-west-3
12 | sa-east-1
13 | us-east-1
14 | us-east-2
15 | us-west-1
16 | us-west-2
17 | )
18 |
--------------------------------------------------------------------------------
/unpublish.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | PHP_VERSION="${1}"
4 | LAYER_VERSION="${2}"
5 |
6 | source regions.sh
7 |
8 | LAYER="php${PHP_VERSION//.}"
9 | MD5SUM=$(md5 -q "${LAYER}.zip")
10 | S3KEY="${LAYER}/${MD5SUM}"
11 |
12 | for region in "${PHP_REGIONS[@]}"; do
13 | bucket_name="stackery-layers-${region}"
14 |
15 | echo "Deleting Lambda Layer ${LAYER} version ${VERSION} in region ${region}..."
16 | aws --region $region lambda delete-layer-version --layer-name ${LAYER} --version-number $VERSION > /dev/null
17 | echo "Deleted Lambda Layer ${LAYER} version ${VERSION} in region ${region}"
18 | done
19 |
--------------------------------------------------------------------------------
/upload.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 |
3 | source regions.sh
4 |
5 | PHP_VERSION="${1}"
6 |
7 | LAYER="php${PHP_VERSION//.}"
8 | MD5SUM=$(md5 -q "${LAYER}.zip")
9 | S3KEY="${LAYER}/${MD5SUM}"
10 |
11 | for region in "${PHP_REGIONS[@]}"; do
12 | bucket_name="stackery-layers-${region}"
13 |
14 | echo "Uploading ${LAYER}.zip to s3://${bucket_name}/${S3KEY}"
15 |
16 | aws --region $region s3 cp ${LAYER}.zip "s3://${bucket_name}/${S3KEY}"
17 | done
18 |
--------------------------------------------------------------------------------