1

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

1 Answer 1

2

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();
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.