From 2725da6b1ba01891efbe62a8320c05370f918b75 Mon Sep 17 00:00:00 2001 From: Damien Goujard Date: Thu, 2 Feb 2017 20:28:28 +0100 Subject: [PATCH] Add initial support for PHP7 (#97) * Add initial support for PHP7 * Update PHP env with now an PSR3 logger (Monolog). Now you can also create a handler function with PSR7 Http message and PSR3 logger in parameter. * Add examples for PHP7 environement * For development you can create a function in this path /app/userfuncdev.php it will be loaded * Switch to alpine base image * handler now receive an array with request, response and logger object --- .gitignore | 3 +- environments/php7/Dockerfile | 73 +++++++++ environments/php7/README.md | 56 +++++++ environments/php7/composer.json | 11 ++ environments/php7/composer.lock | 244 +++++++++++++++++++++++++++++++ environments/php7/index.php | 4 + environments/php7/src/Server.php | 64 ++++++++ environments/python3/README.md | 2 +- examples/php7/hello.php | 3 + examples/php7/hellopsr.php | 12 ++ examples/php7/stock.php | 47 ++++++ 11 files changed, 517 insertions(+), 2 deletions(-) create mode 100644 environments/php7/Dockerfile create mode 100644 environments/php7/README.md create mode 100644 environments/php7/composer.json create mode 100644 environments/php7/composer.lock create mode 100644 environments/php7/index.php create mode 100644 environments/php7/src/Server.php create mode 100644 examples/php7/hello.php create mode 100644 examples/php7/hellopsr.php create mode 100644 examples/php7/stock.php diff --git a/.gitignore b/.gitignore index fc70c76c..d60d073d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *~ # Pycharm IDE -.idea \ No newline at end of file +.idea +environments/php7/vendor/ diff --git a/environments/php7/Dockerfile b/environments/php7/Dockerfile new file mode 100644 index 00000000..37a25790 --- /dev/null +++ b/environments/php7/Dockerfile @@ -0,0 +1,73 @@ +FROM php:7.1-alpine + +ENV PATH="/root/.composer/vendor/bin:${PATH}" \ + COMPOSER_ALLOW_SUPERUSER=1 + +RUN echo '#!/bin/sh' > /usr/local/bin/apk-install \ + && echo 'apk add --update "$@" && rm -rf /var/cache/apk/*' >> /usr/local/bin/apk-install \ + && chmod +x /usr/local/bin/apk-install + +RUN echo 'http://dl-4.alpinelinux.org/alpine/edge/testing' >> /etc/apk/repositories \ + && apk update \ + && apk-install \ + git \ + curl \ + curl-dev \ + libcurl \ + zlib-dev \ + freetype-dev \ + jpeg-dev \ + libjpeg-turbo-dev \ + postgresql-dev \ + libmcrypt-dev \ + libpng-dev \ + icu-dev \ + gettext-dev \ + vim \ + libxml2-dev \ + freetype-dev \ + unzip \ + libc6-compat \ + openssl \ + gcc \ + autoconf + +RUN docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ + +# Install useful extensions +RUN docker-php-ext-install \ + opcache \ + bcmath \ + ctype \ + curl \ + dom \ + iconv \ + fileinfo \ + gd \ + gettext \ + intl \ + json \ + mcrypt \ + mysqli \ + pgsql \ + pcntl \ + pdo \ + ftp \ + pdo_mysql \ + pdo_pgsql \ + phar \ + simplexml \ + xmlrpc \ + zip + +RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer + +COPY . /app +WORKDIR /app + +RUN composer install + +EXPOSE 8888 + +ENTRYPOINT ["php"] +CMD ["-S","0.0.0.0:8888","index.php"] \ No newline at end of file diff --git a/environments/php7/README.md b/environments/php7/README.md new file mode 100644 index 00000000..513d76fc --- /dev/null +++ b/environments/php7/README.md @@ -0,0 +1,56 @@ +# Fission: PHP Environment + +This is the PHP environment for Fission. + +It's a Docker image containing a PHP 7.1 runtime. This image use php:7.1-cli base image with the built-in PHP server + +This environment didn't force you to use class or create a main function. + +A few common extensions are included : +- curl +- gd +- json +- mcrypt +- PDO (pdo_mysql, pdo_pgsql, pdo_sqlite) +- OPcache +- ftp +- iconv +- phar +- mysqli +- pgsql +- SimpleXML +- xmlrpc +- zip + +## Customizing this image + +To add other extensions or packages(composer.json) you need to edit the Dockerfile and rebuild this image (instructions below). + +## Rebuilding and pushing the image + +You'll need access to a Docker registry to push the image: you can +sign up for Docker hub at hub.docker.com, or use registries from +gcr.io, quay.io, etc. Let's assume you're using a docker hub account +called USER. Build and push the image to the the registry: + +``` + docker build -t USER/php7-env . && docker push USER/php7-env +``` + +## Using the image in fission + +You can add this customized image to fission with "fission env +create": + +``` + fission env create --name php7 --image USER/php7-env +``` + +Or, if you already have an environment, you can update its image: + +``` + fission env update --name php7 --image USER/php7-env +``` + +After this, fission functions that have the env parmeter set to the +same environment name as this command will use this environment. diff --git a/environments/php7/composer.json b/environments/php7/composer.json new file mode 100644 index 00000000..66056e79 --- /dev/null +++ b/environments/php7/composer.json @@ -0,0 +1,11 @@ +{ + "autoload": { + "psr-4": { + "PHPEnv\\": "src/" + } + }, + "require": { + "zendframework/zend-diactoros": "^1.3", + "monolog/monolog": "^1.22" + } +} diff --git a/environments/php7/composer.lock b/environments/php7/composer.lock new file mode 100644 index 00000000..c0f3cfe8 --- /dev/null +++ b/environments/php7/composer.lock @@ -0,0 +1,244 @@ +{ + "_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#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "26efb7d1cc58e9ecdc8765fac5eca4e1", + "content-hash": "c0c5cd003c9c3ca4cf3346b232e86258", + "packages": [ + { + "name": "monolog/monolog", + "version": "1.22.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "bad29cb8d18ab0315e6c477751418a82c850d558" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bad29cb8d18ab0315e6c477751418a82c850d558", + "reference": "bad29cb8d18ab0315e6c477751418a82c850d558", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "psr/log": "~1.0" + }, + "provide": { + "psr/log-implementation": "1.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", + "php-console/php-console": "^3.1.3", + "phpunit/phpunit": "~4.5", + "phpunit/phpunit-mock-objects": "2.3.0", + "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "~5.3" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-mongo": "Allow sending log messages to a MongoDB server", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "php-console/php-console": "Allow sending log messages to Google Chrome", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "time": "2016-11-26 00:15:39" + }, + { + "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-06 14:39:51" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10 12:19:37" + }, + { + "name": "zendframework/zend-diactoros", + "version": "1.3.10", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-diactoros.git", + "reference": "83e8d98b9915de76c659ce27d683c02a0f99fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/83e8d98b9915de76c659ce27d683c02a0f99fa90", + "reference": "83e8d98b9915de76c659ce27d683c02a0f99fa90", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "~1.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6 || ^5.5", + "zendframework/zend-coding-standard": "~1.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev", + "dev-develop": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://github.com/zendframework/zend-diactoros", + "keywords": [ + "http", + "psr", + "psr-7" + ], + "time": "2017-01-23 04:53:24" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/environments/php7/index.php b/environments/php7/index.php new file mode 100644 index 00000000..3013812b --- /dev/null +++ b/environments/php7/index.php @@ -0,0 +1,4 @@ +run(); \ No newline at end of file diff --git a/environments/php7/src/Server.php b/environments/php7/src/Server.php new file mode 100644 index 00000000..618690c0 --- /dev/null +++ b/environments/php7/src/Server.php @@ -0,0 +1,64 @@ +pushHandler(new StreamHandler('php://stdout', Logger::DEBUG)); + + $this->server = ZendServer::createServer( + function (ServerRequest $request, Response $response) use ($logger, $codepath) { + $path = parse_url($request->getUri(), PHP_URL_PATH); + + if($path == "/specialize" && $request->getMethod() == "POST"){ + //Nothing to do + return new Response\EmptyResponse(201); + }else{ + if(!file_exists($codepath)){ + $response = $response->withStatus(500); + $response->getBody()->write("Generic container: no requests supported"); + return $response; + } + + ob_start(); + include($codepath); + //If the function as an handler class it will be called with request, response and logger + if(function_exists("handler")){ + ob_end_clean(); + return handler(array("request"=>$request, "response"=>$response,"logger"=>$logger)); + } + //php code didn't have handler function, i will return the content + $bodyRowContent = ob_get_contents(); + ob_end_clean(); + return $response->getBody()->write($bodyRowContent); + } + }, + $_SERVER, + $_GET, + $_POST, + $_COOKIE, + $_FILES + ); + } + + public function run(){ + $this->server->listen(); + } +} +?> \ No newline at end of file diff --git a/environments/python3/README.md b/environments/python3/README.md index cd9de2f0..69e87394 100644 --- a/environments/python3/README.md +++ b/environments/python3/README.md @@ -41,5 +41,5 @@ Or, if you already have an environment, you can update its image: fission env update --name python --image USER/python-env ``` -After this, fission functions that have the env parmeter set to the +After this, fission functions that have the env parameter set to the same environment name as this command will use this environment. diff --git a/examples/php7/hello.php b/examples/php7/hello.php new file mode 100644 index 00000000..340116ab --- /dev/null +++ b/examples/php7/hello.php @@ -0,0 +1,3 @@ +warning("Hello logger"); \ No newline at end of file diff --git a/examples/php7/hellopsr.php b/examples/php7/hellopsr.php new file mode 100644 index 00000000..31c9bdb4 --- /dev/null +++ b/examples/php7/hellopsr.php @@ -0,0 +1,12 @@ +getBody()->write("Hello from handler PHP"); + $logger->warning("Hello logger"); +} \ No newline at end of file diff --git a/examples/php7/stock.php b/examples/php7/stock.php new file mode 100644 index 00000000..ede840f5 --- /dev/null +++ b/examples/php7/stock.php @@ -0,0 +1,47 @@ +withStatus(500); + $response->getBody()->write($message); + return $response; +} + +function handler($context){ + /** @var ResponseInterface $response */ + $response = $context["response"]; + /** @var ServerRequestInterface $request */ + $request = $context["request"]; + /** @var LoggerInterface $logger */ + $logger = $context["logger"]; + + $logger->debug("Request : ",$request->getParsedBody()); + if($request->getMethod() != "POST") + return sendError($response,"You must use POST method"); + + $body = $request->getParsedBody(); + if(!isset($body["currency"])) + return sendError($response,"'currency' is not present in the POST request"); + + $allowedCurrency = ["ltc","btc"]; + if(!in_array($body["currency"],$allowedCurrency)) + return sendError($response,"'currency' is non allowed. Use one of them : ".implode(",",$allowedCurrency)); + + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_URL => 'https://api.cryptonator.com/api/ticker/'.$body["currency"].'-usd' + )); + $result = curl_exec($curl); + curl_close($curl); + + $result = json_decode($result,true); + if($result){ + $logger->debug("Response API",$result); + $response->getBody()->write(json_encode(array("text"=>sprintf("%s-USB = %02f",$body["currency"],$result["ticker"]["price"])))); + }else + return sendError($response,"Cryptonator API not available"); + +}