diff --git a/.gitignore b/.gitignore index 15cc1ca..1defdc9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -php71.zip +php7*.zip + +/vendor/ diff --git a/Makefile b/Makefile index e6453b0..c4d2505 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,15 @@ ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -php71.zip: - docker run --rm -v $(ROOT_DIR):/opt/layer lambci/lambda:build-nodejs8.10 /opt/layer/build.sh +php73.zip: + docker run -v $(ROOT_DIR):/var/layer lambci/lambda:build-nodejs8.10 /var/layer/build.sh -upload: php71.zip +upload: php73.zip ./upload.sh -publish: php71.zip +publish: php73.zip ./publish.sh clean: - rm php71.zip + rm php73.zip + +.PHONY: clean upload publish diff --git a/bootstrap b/bootstrap index 2710746..1cc5757 100755 --- a/bootstrap +++ b/bootstrap @@ -1,238 +1,209 @@ #!/opt/bin/php -c/opt/php.ini -'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']; - -function start_webserver() { - $pid = pcntl_fork(); - switch($pid) { - case -1: - die('Failed to fork webserver process'); - - case 0: - // exec the command - $HANDLER = getenv('_HANDLER'); - $handler_components = explode('/', $HANDLER); - $handler_filename = array_pop($handler_components); - $handler_path = implode('/', array_merge(['/var/task'], $handler_components)); - chdir($handler_path); - exec("PHP_INI_SCAN_DIR=/opt/etc/php-7.1.d/:/var/task/php-7.1.d/ php -S localhost:8000 -c /var/task/php.ini -d extension_dir=/opt/lib/php/7.1/modules '$handler_filename'"); - exit; - - // return the child pid to parent - default: - // Wait for child server to start - sleep(1); - return $pid; - } +$AWS_LAMBDA_RUNTIME_API = \getenv('AWS_LAMBDA_RUNTIME_API'); +$timezone = \getenv('TZ'); +if (':UTC' === $timezone) { + \putenv('TZ=Etc/UTC'); } -function fail($AWS_LAMBDA_RUNTIME_API, $invocation_id, $message) { - $ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/$invocation_id/response"); - - $response = array(); - - $response['statusCode'] = 500; - $response['body'] = $message; - - $response_json = json_encode($response); - - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_POSTFIELDS, $response_json); - curl_setopt($ch, CURLOPT_HTTPHEADER, array( - 'Content-Type: application/json', - 'Content-Length: ' . strlen($response_json) - )); +function start_server(): Process +{ + $process = Process::fromShellCommandline('/opt/sbin/php-fpm -c/opt/php.ini -F -R', null, null, null, null); + $process->start(function (string $type, string $data): void { + echo $data; + }); - curl_exec($ch); - curl_close($ch); + return $process; } -start_webserver(); - -while (true) { - $ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/next"); - - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); - curl_setopt($ch, CURLOPT_FAILONERROR, TRUE); - - $invocation_id = ''; - - curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$invocation_id) { - if (!preg_match('/:\s*/', $header)) { - return strlen($header); +class CGIRequest extends FastCGI\Requests\AbstractRequest +{ + /** + * @var string + */ + private $method; + + /** + * @var string + */ + private $invocationId; + + /** + * @var bool + */ + private $isAlb; + + public function __construct(string $method, string $invocationId, bool $isAlb, string $scriptFilename, string $content) + { + parent::__construct($scriptFilename, $content); + + $this->method = $method; + $this->invocationId = $invocationId; + $this->isAlb = $isAlb; } - [$name, $value] = preg_split('/:\s*/', $header, 2); - - if (strtolower($name) == 'lambda-runtime-aws-request-id') { - $invocation_id = trim($value); + public function getRequestMethod(): string + { + return $this->method; } - return strlen($header); - }); - - $body = ''; - - curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$body) { - $body .= $chunk; - - return strlen($chunk); - }); - - curl_exec($ch); + public function getResponseCallbacks(): array + { + return [ + function (FastCGI\Interfaces\ProvidesResponseData $response): void { + send_response( + $this->invocationId, + $this->isAlb, + $response->getHeader('Status') ?: '200 OK', + $response->getBody(), + $response->getHeaders() + ); + }, + ]; + } - if (curl_error($ch)) { - die('Failed to fetch next Lambda invocation: ' . curl_error($ch) . "\n"); - } + public function getFailureCallbacks(): array + { + return [ + function (\Throwable $e): void { + echo 'ERROR: ' . $e->getMessage(); + send_response($this->invocationId, $this->isAlb, '500 Internal Server Error'); + }, + ]; + } +} - if ($invocation_id == '') { - die('Failed to determine Lambda invocation ID'); - } +$process = start_server(); +$process->waitUntil(function (string $type, string $output): bool { + return -1 !== \strpos($output, 'ready to handle connections'); +}); - curl_close($ch); +if (! $process->isRunning()) { + echo 'PHP-FPM is NOT running'; + die(1); +} - if (!$body) { - die("Empty Lambda invocation response\n"); - } +$connection = new FastCGI\SocketConnections\NetworkSocket('127.0.0.1', 9000, 5000, 5000); +$client = new FastCGI\Client($connection); - $event = json_decode($body, TRUE); +$apiClient = new GuzzleHttp\Client([ + 'handler' => new GuzzleHttp\HandlerStack(new GuzzleHttp\Handler\CurlHandler()), + 'timeout' => 0.05, +]); +$nextRequest = new GuzzleHttp\Psr7\Request(Request::METHOD_GET, "http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/next"); - if (!array_key_exists('requestContext', $event)) { - fail($AWS_LAMBDA_RUNTIME_API, $invocation_id, 'Event is not an API Gateway request'); - continue; - } +$handler = \getenv('_HANDLER'); +$filename = \getenv('LAMBDA_TASK_ROOT').DIRECTORY_SEPARATOR.\substr($handler, 0, \strrpos($handler, '.')).'.php'; - $uri = $event['path']; +function send_response(string $invocationId, bool $isALB, string $status = '200 OK', string $body = '', array $headers = []): void +{ + global $AWS_LAMBDA_RUNTIME_API, $apiClient; - if (array_key_exists('multiValueQueryStringParameters', $event) && $event['multiValueQueryStringParameters']) { - $first = TRUE; - foreach ($event['multiValueQueryStringParameters'] as $name => $values) { - foreach ($values as $value) { - if ($first) { - $uri .= "?"; - $first = FALSE; - } else { - $uri .= "&"; - } + $responseBody = [ + 'body' => $body, + 'statusCode' => (int) \preg_replace('/^(\d+).+$/', '$1', $status), + 'headers' => $headers, + 'isBase64Encoded' => false, + ]; - $uri .= $name; - - if ($value != '') { - $uri .= '=' . $value; - } - } + if ($isALB) { + $responseBody['statusDescription'] = $status; } - } - - $ch = curl_init("http://localhost:8000$uri"); - - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); - - if (array_key_exists('multiValueHeaders', $event)) { - $headers = array(); - foreach ($event['multiValueHeaders'] as $name => $values) { - foreach ($values as $value) { - array_push($headers, "${name}: ${value}"); - } - } + $responseBody = \json_encode($responseBody); + $responseRequest = new GuzzleHttp\Psr7\Request( + Request::METHOD_POST, + "http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/$invocationId/response", + [ + 'Content-Type' => 'application/json', + 'Content-Length' => \strlen($responseBody), + ], + $responseBody, + ); + + $apiClient->sendAsync($responseRequest, [ + GuzzleHttp\RequestOptions::HTTP_ERRORS => false, + ]); +} - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - } +register_tick_function(function (): void { + global $client, $process; - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $event['httpMethod']); + $client->handleReadyResponses(100); + $process->getExitCode(); +}); - if (array_key_exists('body', $event)) { - $body = $event['body']; - if (array_key_exists('isBase64Encoded', $event) && $event['isBase64Encoded']) { - $body = base64_decode($body); +while (true) { + $nextInvocation = $apiClient->sendAsync($nextRequest); + try { + /** @var \Psr\Http\Message\ResponseInterface $response */ + $response = $nextInvocation->wait(); + } catch (GuzzleHttp\Exception\RequestException $exception) { + continue; } - } else { - $body = ''; - } - - if (strlen($body) > 0) { - if($event['httpMethod'] === 'POST'){ - curl_setopt($ch, CURLOPT_POSTFIELDS, $body); - } - curl_setopt($ch, CURLOPT_INFILESIZE, strlen($body)); - curl_setopt($ch, CURLOPT_READFUNCTION, function ($ch, $fd, $length) use ($body) { - return $body; - }); - } - - $response = array(); - $response['multiValueHeaders'] = array(); - $response['body'] = ''; - curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($ch, $header) use (&$response) { - if (preg_match('/HTTP\/1.1 (\d+) .*/', $header, $matches)) { - $response['statusCode'] = intval($matches[1]); - return strlen($header); + /** @var string $invocationId */ + $invocationId = $response->getHeader('lambda-runtime-aws-request-id')[0] ?? null; + if (null === $invocationId) { + continue; } - if (!preg_match('/:\s*/', $header)) { - return strlen($header); + $event = \json_decode((string)$response->getBody(), TRUE); + if (! isset($event['httpMethod'])) { + send_response( + $invocationId, + false, + '500 Internal Server Error', + 'Unknown event', + [ + 'Content-Type' => 'application/json', + 'Content-Length' => \strlen($body), + ] + ); + + \usleep(10); + continue; } - [$name, $value] = preg_split('/:\s*/', $header, 2); - - $name = trim($name); - $value = trim($value); - - if ($name == '') { - return strlen($header); + $body = $event['body'] ?? ''; + if ($event['isBase64Encoded'] ?? false) { + $body = \base64_decode($body); } - if (!array_key_exists($name, $response['multiValueHeaders'])) { - $response['multiValueHeaders'][$name] = array(); + $queryParams = $event['queryStringParameters'] ?? []; + foreach ($event['multiValueQueryStringParameters'] ?? [] as $name => $values) { + $queryParams[$name] = \is_array($values) && \count($values) === 1 ? $values[0] : $values; } - array_push($response['multiValueHeaders'][$name], $value); - - return strlen($header); - }); - - curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $chunk) use (&$response) { - $response['body'] .= $chunk; - - return strlen($chunk); - }); + $query = \http_build_query($queryParams); + $cgiRequest = new CGIRequest($event['httpMethod'], $invocationId, \array_key_exists('elb', $event['requestContext'] ?? []), $filename, $body); + $cgiRequest->setServerPort((int) ($event['headers']['X-Forwarded-Port'] ?? 80)); + $cgiRequest->setCustomVar('QUERY_STRING', $query); + $cgiRequest->setCustomVar('HTTPS', 'on'); + $cgiRequest->setCustomVar('REMOTE_ADDR', $event['requestContext']['identity']['sourceIp'] ?? '127.0.0.1'); + + $cgiRequest->setRequestUri('https://localhost' . $event['path'] . '?' . $query); + foreach ($event['multiValueHeaders'] ?? $event['headers'] ?? [] as $name => $values) { + if (\is_array($values)) { + $values = $values[0]; + } - curl_exec($ch); - curl_close($ch); + if ('content-type' === \mb_strtolower($name)) { + $cgiRequest->setContentType($values); + } elseif ('content-length' !== \mb_strtolower($name)) { + $cgiRequest->setCustomVar('HTTP_' . \str_replace('-', '_', \mb_strtoupper($name)), $values); + } + } - $ch = curl_init("http://$AWS_LAMBDA_RUNTIME_API/2018-06-01/runtime/invocation/$invocation_id/response"); + $cgiRequest->setCustomVar('_X_AMZN_TRACE_ID', $response->getHeader('Lambda-Runtime-Trace-Id')[0]); - $isALB = array_key_exists("elb", $event['requestContext']); - if ($isALB) { // Add Headers For ALB - $status = $response["statusCode"]; - if (array_key_exists($status, $http_codes)) { - $response["statusDescription"] = "$status ". $http_codes[$status]; - } else { - $response["statusDescription"] = "$status Unknown"; - } - $response["isBase64Encoded"] = false; - } - $response_json = json_encode($response); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_POSTFIELDS, $response_json); - if (!$isALB){ - curl_setopt($ch, CURLOPT_HTTPHEADER, array( - 'Content-Type: application/json', - 'Content-Length: ' . strlen($response_json) - )); - } - curl_exec($ch); - curl_close($ch); + $requestId = $client->sendAsyncRequest($cgiRequest); } - -?> diff --git a/build.sh b/build.sh index c646c79..4701aea 100755 --- a/build.sh +++ b/build.sh @@ -1,22 +1,262 @@ #!/bin/bash -yum install -y php71-cli zip +set -eux -mkdir /tmp/layer -cd /tmp/layer -cp /opt/layer/bootstrap . -cp /opt/layer/php.ini . +LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib +PHPIZE_DEPS=" + autoconf + file + gcc-c++ + gcc + glibc-devel + make + pkgconfig + re2c +" -mkdir bin -cp /usr/bin/php bin/ +yum install -y https://dev.mysql.com/get/mysql80-community-release-el7-2.noarch.rpm > mysql80.rpm +yum install -y http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/j/jsoncpp-0.10.5-2.el7.x86_64.rpm +yum install -y http://mirror.ghettoforge.org/distributions/gf/el/7/plus/x86_64/cmake-3.3.2-1.gf.el7.x86_64.rpm -mkdir lib +yum makecache +yum install -y \ + $PHPIZE_DEPS \ + ca-certificates \ + curl \ + dirmngr \ + gnupg \ + tar \ + wget \ + xz \ + zip + +PHP_INI_DIR=/opt/etc/php +PHP_EXTRA_CONFIGURE_ARGS="--enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data --disable-cgi" +PHP_CFLAGS="-fstack-protector-strong -fpic -fpie -O2" +PHP_CPPFLAGS="$PHP_CFLAGS" +PHP_LDFLAGS="-Wl,-O1 -Wl,--hash-style=both -pie" + +GPG_KEYS="CBAF69F173A0FEA4B537F470D66C9593118BCCB6 F38252826ACD957EF380D39F2F7956BC5DA04B5D" + +PHP_VERSION="7.3.1" +PHP_URL="https://secure.php.net/get/php-7.3.1.tar.xz/from/this/mirror" +PHP_ASC_URL="https://secure.php.net/get/php-7.3.1.tar.xz.asc/from/this/mirror" +PHP_SHA256="cfe93e40be0350cd53c4a579f52fe5d8faf9c6db047f650a4566a2276bf33362" + +mkdir -p /usr/src/php +cd /usr/src + +wget -O php.tar.xz "$PHP_URL" +echo "$PHP_SHA256 *php.tar.xz" | sha256sum -c - + +wget -O php.tar.xz.asc "$PHP_ASC_URL" +export GNUPGHOME="$(mktemp -d)" +for key in $GPG_KEYS; do + ( gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key" \ + || gpg --batch --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys "$key" \ + || gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" \ + || gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys "$key" \ + || gpg --batch --keyserver pgp.mit.edu --recv-keys "$key" \ + || gpg --batch --keyserver keyserver.pgp.com --recv-keys "$key" ) +done + +gpg --batch --verify php.tar.xz.asc php.tar.xz +rm -rf "$GNUPGHOME" + +yum install -y \ + libcurl-devel \ + libedit-devel \ + sqlite \ + openssl-devel \ + libxml2-devel \ + libpng-devel \ + libjpeg-devel \ + libgmp-devel \ + libicu-devel \ + mysql-community-libs \ + postgresql-devel \ + zlib-devel \ + cmake + +wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.17.tar.gz -O libsodium.tar.gz +mkdir -p /src/libsodium && tar -xf libsodium.tar.gz -C /src/libsodium --strip-components=1 +rm libsodium.tar.gz +cd /src/libsodium + +./configure --prefix=/usr +make -j4 && make check +make install + +cd /usr/src + +curl -sSL https://github.com/P-H-C/phc-winner-argon2/archive/20171227.tar.gz > libargon2.tar.gz +mkdir -p /src/libargon2 && tar -xf libargon2.tar.gz -C /src/libargon2 --strip-components=1 +rm libargon2.tar.gz +cd /src/libargon2 + +make -j4 && make test +make install + +cd /usr/src + +curl -sSL https://libzip.org/download/libzip-1.5.1.tar.gz > libzip.tar.gz +mkdir -p /src/libzip && tar -xf libzip.tar.gz -C /src/libzip --strip-components=1 +rm libzip.tar.gz +cd /src/libzip + +mkdir build +cd build +cmake .. -DCMAKE_INSTALL_PREFIX=/usr +make -j4 +make install + +cd /usr/src + +export \ + CFLAGS="$PHP_CFLAGS" \ + CPPFLAGS="$PHP_CPPFLAGS" \ + LDFLAGS="$PHP_LDFLAGS" + +tar -Jxf /usr/src/php.tar.xz -C /usr/src/php --strip-components=1 +cd /usr/src/php + +mkdir -p /opt + +./configure \ + --prefix=/opt \ + --with-config-file-path="$PHP_INI_DIR" \ + --with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \ + --enable-option-checking=fatal \ + --with-mhash \ + --enable-ftp \ + --enable-mbstring \ + --enable-mysqlnd \ + --with-password-argon2 \ + --with-sodium=static \ + --with-curl \ + --with-libedit \ + --with-openssl \ + --with-zlib \ + --with-gd \ + --with-gmp \ + --enable-exif \ + --enable-bcmath \ + --enable-sockets \ + --with-mysqli=mysqlnd \ + --with-pdo-mysql=mysqlnd \ + --with-pgsql \ + --with-pdo-pgsql \ + --enable-opcache \ + --enable-libxml \ + --enable-soap \ + --enable-zip \ + --with-xsl \ + ${PHP_EXTRA_CONFIGURE_ARGS:-} + +make -j "$(nproc)" +make install + +find /opt/bin /opt/sbin -type f -executable -exec strip --strip-all '{}' + || true +make clean + +cd /src + +wget https://github.com/mongodb/mongo-php-driver/releases/download/1.5.3/mongodb-1.5.3.tgz -O mongodb.tgz +mkdir -p /src/mongodb && tar -xf mongodb.tgz -C /src/mongodb --strip-components=1 +rm mongodb.tgz +cd /src/mongodb + +/opt/bin/phpize +./configure --with-php-config=/opt/bin/php-config +make -j4 +make install + +cd /src + +wget https://github.com/igbinary/igbinary/releases/download/2.0.8/igbinary-2.0.8.tgz -O igbinary.tgz +mkdir -p /src/igbinary && tar -xf igbinary.tgz -C /src/igbinary --strip-components=1 +rm igbinary.tgz +cd /src/igbinary + +/opt/bin/phpize +./configure CFLAGS="-O2 -g" --enable-igbinary --with-php-config=/opt/bin/php-config +make -j4 +make install + +cd /src + +wget https://github.com/phpredis/phpredis/archive/4.2.0.tar.gz -O phpredis.tar.gz +mkdir -p /src/phpredis && tar -xf phpredis.tar.gz -C /src/phpredis --strip-components=1 +rm phpredis.tar.gz +cd /src/phpredis + +/opt/bin/phpize +./configure CFLAGS="-O2 -g" --enable-redis-igbinary --with-php-config=/opt/bin/php-config +make -j4 +make install + +cd /src + +wget https://pecl.php.net/get/imagick -O imagick.tgz +mkdir -p /src/imagick && tar -xf imagick.tgz -C /src/imagick --strip-components=1 +rm imagick.tgz +cd /src/imagick + +/opt/bin/phpize +./configure --with-php-config=/opt/bin/php-config +make -j4 +make install + +cd / +rm -rf /usr/src +rm -rf /src +yum clean all + +/opt/bin/php --version +/opt/bin/php -m + +cd /opt + +mkdir -p /opt/etc/php/conf.d +echo "extension=mongodb.so" > /opt/etc/php/conf.d/mongodb.ini +echo "extension=igbinary.so" > /opt/etc/php/conf.d/igbinary.ini +echo "extension=redis.so" > /opt/etc/php/conf.d/redis.ini +echo "extension=imagick.so" > /opt/etc/php/conf.d/imagick.ini + +/opt/bin/php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" +/opt/bin/php -r "if (hash_file('sha384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" +/opt/bin/php composer-setup.php --install-dir=/usr/bin --filename=composer +/opt/bin/php -r "unlink('composer-setup.php');" + +cp /var/layer/composer.* . +cp /var/layer/bootstrap . +cp /var/layer/php.ini . + +sed -i "s/;request_terminate_timeout = 0/request_terminate_timeout = 5/g" /opt/etc/php-fpm.d/www.conf.default +#sed -i "s/;listen.allowed_clients = 127.0.0.1/listen.allowed_clients = 127.0.0.1/g" /opt/etc/php-fpm.d/www.conf.default +sed -i "s/^user = www-data/;user = www-data/g" /opt/etc/php-fpm.d/www.conf.default +sed -i "s/^group = www-data/;group = www-data/g" /opt/etc/php-fpm.d/www.conf.default +sed -i "s/;error_log = log\\/php-fpm.log/error_log = \\/dev\\/stderr/g" /opt/etc/php-fpm.conf.default + +echo "php_admin_value[error_log] = /dev/stderr" >> /opt/etc/php-fpm.d/www.conf.default +echo "php_admin_flag[log_errors] = on" >> /opt/etc/php-fpm.d/www.conf.default +echo "clear_env = no" >> /opt/etc/php-fpm.d/www.conf.default + +/opt/bin/php /usr/bin/composer install + +mkdir -p lib for lib in libncurses.so.5 libtinfo.so.5 libpcre.so.0; do cp "/lib64/${lib}" lib/ done -cp /usr/lib64/libedit.so.0 lib/ +for lib in libargon2.so.1 libsodium.so.23; do + cp "/usr/lib/${lib}" lib/ +done -cp -a /usr/lib64/php lib/ +for lib in libedit.so.0 libzip.so.5 libpq.so.5; do + cp "/usr/lib64/${lib}" lib/ +done -zip -r /opt/layer/php71.zip . \ No newline at end of file +cp /opt/etc/php-fpm.conf.default /opt/etc/php-fpm.conf +cp /opt/etc/php-fpm.d/www.conf.default /opt/etc/php-fpm.d/www.conf +zip -r /var/layer/php73.zip . diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..e1d2368 --- /dev/null +++ b/composer.json @@ -0,0 +1,12 @@ +{ + "minimum-stability": "stable", + "require": { + "php": "^7.3", + "ext-curl": "*", + "ext-json": "*", + "hollodotme/fast-cgi-client": "^2.4", + "guzzlehttp/guzzle": "^6.3", + "symfony/http-foundation": "^4.2", + "symfony/process": "^4.2" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..cc46a26 --- /dev/null +++ b/composer.lock @@ -0,0 +1,512 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "fc82e98be65a3e4d5373cce0f4b0dce5", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.3-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2018-04-22T15:46:56+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "9f83dded91781a01c63574e387eaa769be769115" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", + "reference": "9f83dded91781a01c63574e387eaa769be769115", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2018-12-04T20:46:45+00:00" + }, + { + "name": "hollodotme/fast-cgi-client", + "version": "v2.4.3", + "source": { + "type": "git", + "url": "https://github.com/hollodotme/fast-cgi-client.git", + "reference": "aa5ded562b5708b4ead96364b041c5c9a06586da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hollodotme/fast-cgi-client/zipball/aa5ded562b5708b4ead96364b041c5c9a06586da", + "reference": "aa5ded562b5708b4ead96364b041c5c9a06586da", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "tm/tooly-composer-script": "^1.0" + }, + "bin": [ + "bin/fcgiget" + ], + "type": "library", + "extra": { + "tools": { + "phpunit": { + "url": "https://phar.phpunit.de/phpunit-7.phar", + "only-dev": true + }, + "coveralls": { + "url": "https://github.com/php-coveralls/php-coveralls/releases/download/v2.1.0/php-coveralls.phar", + "only-dev": true + } + } + }, + "autoload": { + "psr-4": { + "hollodotme\\FastCGI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Holger Woltersdorf", + "email": "hw@hollo.me" + } + ], + "description": "A PHP fast CGI client to send requests (a)synchronously to PHP-FPM.", + "keywords": [ + "Socket", + "fastcgi", + "php-fpm" + ], + "time": "2018-09-17T07:14:06+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.0", + "satooshi/php-coveralls": ">=1.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2016-02-11T07:05:27+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v4.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "a633d422a09242064ba24e44a6e1494c5126de86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a633d422a09242064ba24e44a6e1494c5126de86", + "reference": "a633d422a09242064ba24e44a6e1494c5126de86", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.1" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/expression-language": "~3.4|~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpFoundation Component", + "homepage": "https://symfony.com", + "time": "2019-01-05T16:37:49+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.10.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2018-09-21T13:07:52+00:00" + }, + { + "name": "symfony/process", + "version": "v4.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "ea043ab5d8ed13b467a9087d81cb876aee7f689a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/ea043ab5d8ed13b467a9087d81cb876aee7f689a", + "reference": "ea043ab5d8ed13b467a9087d81cb876aee7f689a", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2019-01-03T14:48:52+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/create-buckets.sh b/create-buckets.sh index 0a2b44b..c9113c3 100755 --- a/create-buckets.sh +++ b/create-buckets.sh @@ -2,10 +2,10 @@ source regions.sh -for region in "${PHP71_REGIONS[@]}"; do - bucket_name="stackery-layers-${region}" +for region in "${PHP_REGIONS[@]}"; do + bucket_name="com-fazland-php-lambda-${region}" echo "Creating bucket ${bucket_name}..." - aws s3 mb s3://$bucket_name --region $region -done \ No newline at end of file + aws s3 mb s3://$bucket_name --region $region --profile=alessandro.chitolina +done diff --git a/php.ini b/php.ini index ce1c3ec..2293610 100644 --- a/php.ini +++ b/php.ini @@ -1,4 +1,2 @@ -extension_dir=/opt/lib/php/7.1/modules -extension=curl.so -extension=json.so -display_errors=On \ No newline at end of file +display_errors=On +variables_order=EGPCS diff --git a/publish.sh b/publish.sh index 1f91f7d..325da66 100755 --- a/publish.sh +++ b/publish.sh @@ -2,18 +2,18 @@ source regions.sh -MD5SUM=$(md5 -q php71.zip) -S3KEY="php71/${MD5SUM}" +MD5SUM=$(md5 -q php73.zip) +S3KEY="php73/${MD5SUM}" -for region in "${PHP71_REGIONS[@]}"; do - bucket_name="stackery-layers-${region}" +for region in "${PHP_REGIONS[@]}"; do + bucket_name="com-fazland-php-lambda-${region}" - echo "Publishing Lambda Layer php71 in region ${region}..." + echo "Publishing Lambda Layer php73 in region ${region}..." # Must use --cli-input-json so AWS CLI doesn't attempt to fetch license URL - version=$(aws --region $region lambda publish-layer-version --cli-input-json "{\"LayerName\": \"php71\",\"Description\": \"PHP 7.1 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) - echo "Published Lambda Layer php71 in region ${region} version ${version}" + version=$(aws --profile=alessandro.chitolina --region $region lambda publish-layer-version --cli-input-json "{\"LayerName\": \"php73\",\"Description\": \"PHP 7.3 Lambda Runtime\",\"Content\": {\"S3Bucket\": \"${bucket_name}\",\"S3Key\": \"${S3KEY}\"},\"CompatibleRuntimes\": [\"provided\"],\"LicenseInfo\": \"http://www.php.net/license/3_01.txt\"}" --output text --query Version) + echo "Published Lambda Layer php73 in region ${region} version ${version}" - echo "Setting public permissions on Lambda Layer php71 version ${version} in region ${region}..." - aws --region $region lambda add-layer-version-permission --layer-name php71 --version-number $version --statement-id=public --action lambda:GetLayerVersion --principal '*' > /dev/null - echo "Public permissions set on Lambda Layer php71 version ${version} in region ${region}" + echo "Setting public permissions on Lambda Layer php73 version ${version} in region ${region}..." + aws --profile=alessandro.chitolina --region $region lambda add-layer-version-permission --layer-name php73 --version-number $version --statement-id=public --action lambda:GetLayerVersion --principal '*' > /dev/null + echo "Public permissions set on Lambda Layer php73 version ${version} in region ${region}" done diff --git a/regions.sh b/regions.sh index dc2002f..f44b493 100644 --- a/regions.sh +++ b/regions.sh @@ -1,17 +1,3 @@ -PHP71_REGIONS=( - ap-northeast-1 - ap-northeast-2 - ap-south-1 - ap-southeast-1 - ap-southeast-2 - ca-central-1 - eu-central-1 +PHP_REGIONS=( eu-west-1 - eu-west-2 - eu-west-3 - sa-east-1 - us-east-1 - us-east-2 - us-west-1 - us-west-2 ) diff --git a/unpublish.sh b/unpublish.sh index eb2ff9d..3e722f3 100755 --- a/unpublish.sh +++ b/unpublish.sh @@ -4,13 +4,13 @@ VERSION=$1 source regions.sh -MD5SUM=$(md5 -q php71.zip) -S3KEY="php71/${MD5SUM}" +MD5SUM=$(md5 -q php73.zip) +S3KEY="php73/${MD5SUM}" -for region in "${PHP71_REGIONS[@]}"; do - bucket_name="stackery-layers-${region}" +for region in "${PHP_REGIONS[@]}"; do + bucket_name="com-fazland-php-lambda-${region}" - echo "Deleting Lambda Layer php71 version ${VERSION} in region ${region}..." - aws --region $region lambda delete-layer-version --layer-name php71 --version-number $VERSION > /dev/null - echo "Deleted Lambda Layer php71 version ${VERSION} in region ${region}" + echo "Deleting Lambda Layer php version ${VERSION} in region ${region}..." + aws --profile=alessandro.chitolina --region $region lambda delete-layer-version --layer-name php73 --version-number $VERSION > /dev/null + echo "Deleted Lambda Layer php version ${VERSION} in region ${region}" done diff --git a/upload.sh b/upload.sh index 89c5afb..9f6e86b 100755 --- a/upload.sh +++ b/upload.sh @@ -2,13 +2,13 @@ source regions.sh -MD5SUM=$(md5 -q php71.zip) -S3KEY="php71/${MD5SUM}" +MD5SUM=$(md5 -q php73.zip) +S3KEY="php73/${MD5SUM}" -for region in "${PHP71_REGIONS[@]}"; do - bucket_name="stackery-layers-${region}" +for region in "${PHP_REGIONS[@]}"; do + bucket_name="com-fazland-php-lambda-${region}" - echo "Uploading php71.zip to s3://${bucket_name}/${S3KEY}" + echo "Uploading php73.zip to s3://${bucket_name}/${S3KEY}" - aws --region $region s3 cp php71.zip "s3://${bucket_name}/${S3KEY}" + aws --region $region s3 cp php73.zip "s3://${bucket_name}/${S3KEY}" done