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
This commit is contained in:
Damien Goujard
2017-02-02 11:28:28 -08:00
committed by Soam Vasani
parent c353e7f230
commit 2725da6b1b
11 changed files with 517 additions and 2 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
*~
# Pycharm IDE
.idea
.idea
environments/php7/vendor/
+73
View File
@@ -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"]
+56
View File
@@ -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.
+11
View File
@@ -0,0 +1,11 @@
{
"autoload": {
"psr-4": {
"PHPEnv\\": "src/"
}
},
"require": {
"zendframework/zend-diactoros": "^1.3",
"monolog/monolog": "^1.22"
}
}
+244
View File
@@ -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": []
}
+4
View File
@@ -0,0 +1,4 @@
<?php
require __DIR__ . '/vendor/autoload.php';
$server = new PHPEnv\Server();
$server->run();
+64
View File
@@ -0,0 +1,64 @@
<?php
namespace PHPEnv;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Response;
use Zend\Diactoros\Server as ZendServer;
class Server {
private $server;
public function __construct(){
$codepath = '/userfunc/user';
//if i have a local function i use it
$devcodepath = '/app/userfuncdev.php';
if(file_exists($devcodepath))
$codepath = $devcodepath;
$logger = new Logger("Function");
$logger->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();
}
}
?>
+1 -1
View File
@@ -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.
+3
View File
@@ -0,0 +1,3 @@
<?php
echo "Hello from PHP";
$logger->warning("Hello logger");
+12
View File
@@ -0,0 +1,12 @@
<?php
function handler($context){
/** @var \Psr\Http\Message\ResponseInterface $response */
$response = $context["response"];
/** @var \Psr\Http\Message\ServerRequestInterface $request */
$request = $context["request"];
/** @var \Psr\Log\LoggerInterface $logger */
$logger = $context["logger"];
$response->getBody()->write("Hello from handler PHP");
$logger->warning("Hello logger");
}
+47
View File
@@ -0,0 +1,47 @@
<?php
use \Psr\Http\Message\ResponseInterface;
use \Psr\Http\Message\ServerRequestInterface;
use \Psr\Log\LoggerInterface;
function sendError($response,$message){
$response = $response->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");
}