Reputation: 492
I have two files: index.js and php-cgi
When I press the test button in aws lambda console I see an empty string instead of the php version.
Here is my Index.js code:
exports.handler = function(event, context) {
var php = spawn('./php-cgi', ['-v']);
var output = '';
php.stdout.on('data', function(data) {
output += data.toString('utf-8');
});
php.on('close', function() {
context.succeed(output);
});
};
How I can execute php-cgi. Thank you
Upvotes: 1
Views: 1617
Reputation: 307
You need to launch an EC2 instance with AMI Amazon Linux 1 and follow next commands:
mkdir php-lambda
cd php-lambda
Download https://github.com/akrabat/lambda-php/blob/2019-01-02-article/doc/compile_php.sh and execute with the desired version of php sh compile_php.sh 7.3.6
It creates a folder called php-7-bin. Inside the folder /bin/php there is the php binary that we need.
Download bootstrap and runtime.php from: https://github.com/akrabat/lambda-php/tree/2019-01-02-article/layer/php
Create a new folder and add php binary, bootstrap and runtime.php to it.
Create a zip with this content.
zip -r9 php-layer.zip *
Create a layer with this zip.
For using php in a lambda. You need to create a lambda function and select Custom runtime and add the php layer created above.
Create a file for example handler.php and add next code inside it:
<?php
function hello($eventData) : array
{
echo "Prueba";
return ["msg" => "hola"];
}
Now your PHP Lambda is working.
I have added some changes to runtime.php so I just receive now json data.
<?php
/**
*
* Modified from: https://github.com/pagnihotry/PHP-Lambda-Runtime/blob/master/runtime/runtime.php
* Copyright (c) 2018 Parikshit Agnihotry
*
* RKA Changes:
* - JSON encode result of handler function
* - Catch any Throwables and write to error log
*/
/**
* PHP class to interact with AWS Runtime API
*/
class LambdaRuntime
{
const POST = "POST";
const GET = "GET";
private $url;
private $functionCodePath;
private $requestId;
private $response;
private $rawEventData;
private $eventPayload;
private $handler;
/**
* Constructor to initialize the class
*/
function __construct()
{
$this->url = "http://".getenv("AWS_LAMBDA_RUNTIME_API");
$this->functionCodePath = getenv("LAMBDA_TASK_ROOT");
$this->handler = getenv("_HANDLER");
}
/**
* Get the current request Id being serviced by the runtime
*/
public function getRequestId() {
return $this->requestId;
}
/**
* Get the handler setting defined in AWS Lambda configuration
*/
public function getHandler() {
return $this->handler;
}
/**
* Get the current event payload
*/
public function getEventPayload() {
return json_decode($this->eventPayload);
}
/**
* Get the buffered response
*/
public function getResponse() {
return $this->response;
}
/**
* Reset the response buffer
*/
public function resetResponse() {
$this->response = "";
}
/**
* Add string to the response buffer. This is printed out on success.
*/
public function addToResponse($str) {
$this->response = $this->response.$str;
}
public function flushResponse() {
$result = $this->curl(
"/2018-06-01/runtime/invocation/".$this->getRequestId()."/response",
LambdaRuntime::POST,
$this->getResponse()
);
$this->resetResponse();
}
/**
* Get the Next event data
*/
public function getNextEventData() {
$this->rawEventData = $this->curl("/2018-06-01/runtime/invocation/next", LambdaRuntime::GET);
if(!isset($this->rawEventData["headers"]["lambda-runtime-aws-request-id"][0])) {
//Handle error
$this->reportError(
"MissingEventData",
"Event data is absent. EventData:".var_export($this->rawEventData, true)
);
//setting up response so the while loop does not try to invoke the handler with unexpected data
return array("error"=>true);
}
$this->requestId = $this->rawEventData["headers"]["lambda-runtime-aws-request-id"][0];
$this->eventPayload = $this->rawEventData["body"];
return $this->rawEventData;
}
/**
* Report error to Lambda runtime
*/
public function reportError($errorType, $errorMessage) {
$errorArray = array("errorType"=>$errorType, "errorMessage"=>$errorMessage);
$errorPayload = json_encode($errorArray);
$result = $this->curl(
"/2018-06-01/runtime/invocation/".$this->getRequestId()."/error",
LambdaRuntime::POST,
$errorPayload
);
}
/**
* Report initialization error with runtime
*/
public function reportInitError($errorType, $errorMessage) {
$errorArray = array("errorType"=>$errorType, "errorMessage"=>$errorMessage);
$errorPayload = json_encode($errorArray);
$result = $this->curl(
"/2018-06-01/runtime/init/error",
LambdaRuntime::POST,
$errorPayload
);
}
/**
* Internal function to make curl requests to the runtime API
*/
private function curl($urlPath, $method, $payload="") {
$fullURL = $this->url . $urlPath;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fullURL);
curl_setopt($ch, CURLOPT_NOBODY, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$headers = [];
// Parse curl headers
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
function($curl, $header) use (&$headers)
{
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) // ignore invalid headers
return $len;
$name = strtolower(trim($header[0]));
if (!array_key_exists($name, $headers))
$headers[$name] = [trim($header[1])];
else
$headers[$name][] = trim($header[1]);
return $len;
}
);
//handle post request
if($method == LambdaRuntime::POST) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
// Set HTTP Header for POST request
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Length: ' . strlen($payload)
)
);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return array("headers"=>$headers, "body"=>$response, "httpCode" => $httpCode);
}
}
$lambdaRuntime = new LambdaRuntime();
$handler = $lambdaRuntime->getHandler();
//Extract file name and function
list($handlerFile , $handlerFunction) = explode(".", $handler);
//Include the handler file
require_once($handlerFile.".php");
//Poll for the next event to be processed
while (true) {
//Get next event
$data = $lambdaRuntime->getNextEventData();
//Check if there was an error that runtime detected with the next event data
if(isset($data["error"]) && $data["error"]) {
continue;
}
//Process the events
$eventPayload = $lambdaRuntime->getEventPayload();
try {
//Handler is of format Filename.function
//Execute handler
$functionReturn = $handlerFunction($eventPayload);
$json = json_encode($functionReturn, true);
$lambdaRuntime->addToResponse($json);
} catch (\Throwable $e) {
error_log((string)$e);
}
//Report result
$lambdaRuntime->flushResponse();
}
Upvotes: 2