Skip to content

Commit 35f7a86

Browse files
Added support for PHP 7.2 and 7.3
1 parent bdd2286 commit 35f7a86

File tree

10 files changed

+597
-15
lines changed

10 files changed

+597
-15
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
php71.zip
2+
php72.zip
3+
php73.zip

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@ ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
33
php71.zip:
44
docker run --rm -v $(ROOT_DIR):/opt/layer lambci/lambda:build-nodejs8.10 /opt/layer/build.sh
55

6+
php72.zip:
7+
docker run --rm -v $(ROOT_DIR):/opt/layer lambci/lambda:build-nodejs8.10 /opt/layer/build-php72.sh
8+
9+
php73.zip:
10+
docker run --rm -v $(ROOT_DIR):/opt/layer lambci/lambda:build-nodejs8.10 /opt/layer/build-php73.sh
11+
612
upload: php71.zip
713
./upload.sh
814

915
publish: php71.zip
1016
./publish.sh
1117

1218
clean:
13-
rm php71.zip
19+
rm -f php71.zip php72.zip php73.zip
20+

README.md

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
# PHP Layer For AWS Lambda
22

3-
Ever wanted to run PHP websites in AWS Lambda? It's your lucky day! This Lambda Runtime Layer runs the [PHP 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.
3+
Ever wanted to run PHP websites in AWS Lambda? It's your lucky day! This Lambda Runtime Layer runs the [PHP 7.1/7.2/7.3 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.
44

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)!
5+
This project is fork of the [Stackery](https://stackery.io) [php-lambda-layer](https://github.com/stackery/php-lambda-layer) that has been modified to:
66

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 ARN is:
7+
- support PHP 7.1, 7.2, and 7.3 (the original supports 7.1 only) - using the [Remi RPM Repository](https://rpms.remirepo.net/)
8+
- add support for mbstring, MySQL (pdo-mysql) and Postgres (pdo-pgsql)
119

12-
**arn:aws:lambda:\<region\>:887080169480:layer:php71:6**
10+
that are requirements for running frameworks such as [Lumen](https://lumen.laravel.com/) and [Laravel](https://laravel.com/) frameworks in serverless mode.
1311

14-
See [Releases](https://github.com/stackery/php-lambda-layer/releases) for release notes.
12+
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.
1513

1614
### Usage
1715
#### General Usage
18-
The layer runs the PHP 7.1 [PHP webserver](http://php.net/manual/en/features.commandline.webserver.php) in /var/task, the root directory of function code packages:
16+
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:
1917

2018
```sh
2119
$ php -S localhost:8000 '<handler>'
@@ -26,12 +24,14 @@ The Lambda Function Handler property specifies the location of the the script ex
2624
#### Configuration Files
2725
There are three locations where PHP configuration may be located:
2826

29-
* Files in layer code packages located under /etc/php-7.1.d/
30-
* Files in function code package located under /php-7.1.d/
27+
* Files in layer code packages located under /etc/php-<PHP_VERSION>.d/
28+
* Files in function code package located under /php-<PHP_VERSION>.d/
3129
* php.ini located at the root of the function code package
3230

31+
Replace <PHP_VERSION> with 7.1, 7.2, or 7.3 according to your preferred runtime.
32+
3333
##### Extensions
34-
The following extensions are built into the layer and available in /opt/lib/php/7.1/modules:
34+
The following extensions are built into the layer and available in /opt/lib/php/7.1/modules (PHP 7.1) or /opt/lib/php/modules (PHP 7.2/7.3):
3535

3636
```
3737
bz2.so
@@ -154,9 +154,23 @@ $ sam deploy \
154154
Build the layer by:
155155

156156
1. Installing a Docker environment
157-
1. Running `make`
157+
2. Running `make`
158+
159+
This will launch a Docker container that will build php71.zip, based on PHP 7.1 (default).
160+
161+
You can run `make php72.zip` and `make php73.zip` to create a layer that is based on PHP 7.2/7.3.
162+
163+
### Debugging
164+
165+
Run:
166+
167+
$ docker run --rm -it -v `pwd`:/opt/layer lambci/lambda:build-nodejs8.10 /bin/bash
168+
169+
If you are on Windows, run this instead:
158170

159-
This will launch a Docker container that will build php71.zip.
171+
> docker run --rm -it -v %cd%:/opt/layer lambci/lambda:build-nodejs8.10 /bin/bash
172+
173+
and execute manually the commands in the build.sh file.
160174

161175
### Disclaimer
162176

bootstrap-php72

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
#!/opt/bin/php -c/opt/php.ini
2+
<?php
3+
4+
error_reporting(E_ALL | E_STRICT);
5+
6+
$AWS_LAMBDA_RUNTIME_API = getenv('AWS_LAMBDA_RUNTIME_API');
7+
8+
/* https://gist.github.com/henriquemoody/6580488 */
9+
$http_codes = [100=>'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+
$pid = pcntl_fork();
13+
switch($pid) {
14+
case -1:
15+
die('Failed to fork webserver process');
16+
17+
case 0:
18+
// exec the command
19+
$HANDLER = getenv('_HANDLER');
20+
chdir('/var/task');
21+
exec("PHP_INI_SCAN_DIR=/opt/etc/php-7.2.d/:/var/task/php-7.2.d/ php -S localhost:8000 -c /var/task/php.ini -d extension_dir=/opt/lib/php/modules '$HANDLER'");
22+
exit;
23+
24+
// return the child pid to parent
25+
default:
26+
// Wait for child server to start
27+
sleep(1);
28+
return $pid;
29+
}
30+
}
31+
32+
function fail($AWS_LAMBDA_RUNTIME_API, $invocation_id, $message) {
33+
$ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/$invocation_id/response");
34+
35+
$response = array();
36+
37+
$response['statusCode'] = 500;
38+
$response['body'] = $message;
39+
40+
$response_json = json_encode($response);
41+
42+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
43+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
44+
curl_setopt($ch, CURLOPT_POSTFIELDS, $response_json);
45+
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
46+
'Content-Type: application/json',
47+
'Content-Length: ' . strlen($response_json)
48+
));
49+
50+
curl_exec($ch);
51+
curl_close($ch);
52+
}
53+
54+
start_webserver();
55+
56+
while (true) {
57+
$ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/next");
58+
59+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
60+
curl_setopt($ch, CURLOPT_FAILONERROR, TRUE);
61+
62+
$invocation_id = '';
63+
64+
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$invocation_id) {
65+
if (!preg_match('/:\s*/', $header)) {
66+
return strlen($header);
67+
}
68+
69+
[$name, $value] = preg_split('/:\s*/', $header, 2);
70+
71+
if (strtolower($name) == 'lambda-runtime-aws-request-id') {
72+
$invocation_id = trim($value);
73+
}
74+
75+
return strlen($header);
76+
});
77+
78+
$body = '';
79+
80+
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$body) {
81+
$body .= $chunk;
82+
83+
return strlen($chunk);
84+
});
85+
86+
curl_exec($ch);
87+
88+
if (curl_error($ch)) {
89+
die('Failed to fetch next Lambda invocation: ' . curl_error($ch) . "\n");
90+
}
91+
92+
if ($invocation_id == '') {
93+
die('Failed to determine Lambda invocation ID');
94+
}
95+
96+
curl_close($ch);
97+
98+
if (!$body) {
99+
die("Empty Lambda invocation response\n");
100+
}
101+
102+
$event = json_decode($body, TRUE);
103+
104+
if (!array_key_exists('requestContext', $event)) {
105+
fail($AWS_LAMBDA_RUNTIME_API, $invocation_id, 'Event is not an API Gateway request');
106+
continue;
107+
}
108+
109+
$uri = $event['path'];
110+
111+
if (array_key_exists('multiValueQueryStringParameters', $event) && $event['multiValueQueryStringParameters']) {
112+
$first = TRUE;
113+
foreach ($event['multiValueQueryStringParameters'] as $name => $values) {
114+
foreach ($values as $value) {
115+
if ($first) {
116+
$uri .= "?";
117+
$first = FALSE;
118+
} else {
119+
$uri .= "&";
120+
}
121+
122+
$uri .= $name;
123+
124+
if ($value != '') {
125+
$uri .= '=' . $value;
126+
}
127+
}
128+
}
129+
}
130+
131+
$ch = curl_init("http://localhost:8000$uri");
132+
133+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
134+
135+
if (array_key_exists('multiValueHeaders', $event)) {
136+
$headers = array();
137+
138+
foreach ($event['multiValueHeaders'] as $name => $values) {
139+
foreach ($values as $value) {
140+
array_push($headers, "${name}: ${value}");
141+
}
142+
}
143+
144+
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
145+
}
146+
147+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $event['httpMethod']);
148+
149+
if (array_key_exists('body', $event)) {
150+
$body = $event['body'];
151+
if (array_key_exists('isBase64Encoded', $event) && $event['isBase64Encoded']) {
152+
$body = base64_decode($body);
153+
}
154+
} else {
155+
$body = '';
156+
}
157+
158+
if (strlen($body) > 0) {
159+
if($event['httpMethod'] === 'POST'){
160+
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
161+
}
162+
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($body));
163+
curl_setopt($ch, CURLOPT_READFUNCTION, function ($ch, $fd, $length) use ($body) {
164+
return $body;
165+
});
166+
}
167+
168+
$response = array();
169+
$response['multiValueHeaders'] = array();
170+
$response['body'] = '';
171+
172+
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$response) {
173+
if (preg_match('/HTTP\/1.1 (\d+) .*/', $header, $matches)) {
174+
$response['statusCode'] = intval($matches[1]);
175+
return strlen($header);
176+
}
177+
178+
if (!preg_match('/:\s*/', $header)) {
179+
return strlen($header);
180+
}
181+
182+
[$name, $value] = preg_split('/:\s*/', $header, 2);
183+
184+
$name = trim($name);
185+
$value = trim($value);
186+
187+
if ($name == '') {
188+
return strlen($header);
189+
}
190+
191+
if (!array_key_exists($name, $response['multiValueHeaders'])) {
192+
$response['multiValueHeaders'][$name] = array();
193+
}
194+
195+
array_push($response['multiValueHeaders'][$name], $value);
196+
197+
return strlen($header);
198+
});
199+
200+
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$response) {
201+
$response['body'] .= $chunk;
202+
203+
return strlen($chunk);
204+
});
205+
206+
curl_exec($ch);
207+
curl_close($ch);
208+
209+
$ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/$invocation_id/response");
210+
211+
$isALB = array_key_exists("elb", $event['requestContext']);
212+
if ($isALB) { // Add Headers For ALB
213+
$status = $response["statusCode"];
214+
if (array_key_exists($status, $http_codes)) {
215+
$response["statusDescription"] = "$status ". $http_codes[$status];
216+
} else {
217+
$response["statusDescription"] = "$status Unknown";
218+
}
219+
$response["isBase64Encoded"] = false;
220+
}
221+
$response_json = json_encode($response);
222+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
223+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
224+
curl_setopt($ch, CURLOPT_POSTFIELDS, $response_json);
225+
if (!$isALB){
226+
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
227+
'Content-Type: application/json',
228+
'Content-Length: ' . strlen($response_json)
229+
));
230+
}
231+
curl_exec($ch);
232+
curl_close($ch);
233+
}
234+
235+
?>

0 commit comments

Comments
 (0)