在AWS Lambda中执行php

时间:2019-12-02 06:48:02

标签: php amazon-web-services aws-lambda

我有两个文件:index.js和php-cgi

当我在AWS Lambda控制台中按下测试按钮时,我看到一个空字符串而不是php版本。

这是我的Index.js代码:

Response.Clear();
Response.ContentType = "text/plain";
Response.Write("{'some': 'json'}");
Response.End();

我如何执行php-cgi。 谢谢

1 个答案:

答案 0 :(得分:1)

您需要使用AMI Amazon Linux 1启动EC2实例并遵循以下命令:

mkdir php-lambda
cd php-lambda

下载https://github.com/akrabat/lambda-php/blob/2019-01-02-article/doc/compile_php.sh并使用所需的php sh compile_php.sh 7.3.6版本执行

它将创建一个名为php-7-bin的文件夹。在/ bin / php文件夹中,是我们需要的php二进制文件。

https://github.com/akrabat/lambda-php/tree/2019-01-02-article/layer/php

下载bootstrap和runtime.php

创建一个新文件夹,并将php二进制文件,bootstrap和runtime.php添加到其中。

使用此内容创建一个zip。

zip -r9 php-layer.zip *

使用此zip创建图层。

用于在lambda中使用php。您需要创建一个lambda函数,然后选择自定义运行时,并添加上面创建的php层。

为例如handler.php创建一个文件,并在其中添加下一个代码:

<?php
function hello($eventData) : array
{
    echo "Prueba";
    return ["msg" => "hola"];
}

现在您的PHP Lambda可以正常工作了。

我对runtime.php添加了一些更改,所以我现在只接收json数据。

<?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();
}