全部产品
云市场

PHP 运行环境

更新时间:2020-03-30 11:26:12

函数计算支持 PHP 7.2.7(runtime = php7.2)运行环境。本文介绍了 PHP 运行环境的以下内容:

打印日志

PHP 函数通过 $GLOBALS['fcLogger'] 打印的内容会被收集到创建服务时指定的日志服务 Logstore 中。函数计算内置了 logger 模块,您可以通过 $GLOBALS['fcLogger'] 使用该内置 logger 模块。

日志级别

您可以通过 setLevel 方法改变日志级别,其中日志级别从高到低如下所示。

日志级别 Level 接口 描述
EMERGENCY 600 $logger->emergency 紧急日志
ALERT 550 $logger->alert 警示日志
CRITICAL 500 $logger->critical 严重警告
ERROR 400 $logger->error 出错信息
WARNING 300 $logger->warning 警告信息
NOTICE 250 $logger->notice 通知及常规日志
INFO(默认) 200 $logger->info 详细输出信息
DEBUG 100 $logger->debug 调试日志

函数日志的更多详情,请参见函数日志

logger 示例一

  1. <?php
  2. function handler($event, $context) {
  3. $logger = $GLOBALS['fcLogger'];
  4. $logger->info("hello world");
  5. return 'hello world';
  6. };

执行上面的代码输出的日志内容如下所示。

  1. message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [INFO] hello world

logger 示例二

  1. <?php
  2. use Monolog\Logger;
  3. function handler($evt, $ctx) {
  4. $logger = $GLOBALS['fcLogger'];
  5. $logger->setLevel(400);
  6. $logger->error("console error 1");
  7. $logger->info("console info 1");
  8. $logger->warning("console warn 1");
  9. $logger->debug("console debug 1");
  10. $logger->setLevel(Logger::WARNING);
  11. $logger->error("console error 2");
  12. $logger->info("console info 2");
  13. $logger->warn("console warn 2");
  14. $logger->debug("console debug 2");
  15. $logger->setLevel(200);
  16. }

执行上面的代码输出的日志内容如下所示。

  1. 2018-08-22T09:01:26Z c19b2706-9c4d-270b-52c8-5248ed5e2315 [ERROR]: console error 1
  2. 2018-08-22T09:01:26Z c19b2706-9c4d-270b-52c8-5248ed5e2315 [ERROR]: console error 2
  3. 2018-08-22T09:01:26Z c19b2706-9c4d-270b-52c8-5248ed5e2315 [WARNING]: console warn 2

错误处理

PHP 函数在执行过程中发生异常时,函数计算捕获异常并返回异常信息。以下示例代码返回了 oops 的异常信息。

  1. <?php
  2. function handler($event, $context) {
  3. throw new Exception("oops");
  4. }

根据以上示例代码,您调用函数时可能会收到以下响应信息。

  1. {
  2. "errorMessage":"oops",
  3. "errorType":"Exception",
  4. "stackTrace":{
  5. "file":"/code/index.php",
  6. "line":3,
  7. "traceString":"#0 /var/fc/runtime/php7/src/invoke.php(67): handler('{\n "product"...', Array)
  8. #1 "
  9. }
  10. }

发生异常时,函数调用的响应的 HTTP header 中会包含 X-Fc-Error-Type: UnhandledInvocationError。有关函数计算错误类型的更多信息,请参见错误类型

PHP 内置扩展

下文介绍了 PHP 运行环境的内置扩展(built-in extension)的相关内容,这些能满足您的大部分需求。

  1. "Core", "date", "libxml", "openssl", "pcre", "zlib", "curl","filter", "hash", "readline", "Reflection",
  2. "SPL", "session","xml", "standard", "mysqlnd", "bcmath", "bz2", "calendar","ctype", "dom", "mbstring",
  3. "fileinfo", "ftp", "gettext", "gmp", "iconv","imagick", "json", "exif", "mysqli", "pcntl", "PDO",
  4. "pdo_mysql","Phar", "posix", "protobuf", "redis", "shmop", "SimpleXML", "soap","sockets", "sysvmsg", "zip", "memcached",
  5. "sysvsem", "sysvshm", "tokenizer", "xmlreader","xmlrpc", "xmlwriter"

PHP 内置扩展应用示例

以下示例代码使用 imagick 对图片做了简单处理。

  1. <?php
  2. function imageProc($event, $context) {
  3. $image = new Imagick(__DIR__ . '/lena.jpg');
  4. $image->thumbnailImage(100, 0);
  5. $image->writeImages(__DIR__ . "/thumb.jpg", true);
  6. return strval($image->getImageWidth()) . "," . strval($image->getImageHeight());
  7. }

PHP 自定义扩展

您可以在函数入口文件同级目录下创建一个名为 extension 的目录,并且将扩展对应的 .ini.so 文件放在 extension 目录下来添加 PHP 自定义扩展。下文演示了一个 hello 的自定义扩展,假设该扩展里有一个 hello_world 函数。

  1. .
  2. |____extension
  3. | |____hello.ini
  4. | |____hello.so
  5. |____main.php
  • hello.ini

    1. extension=/code/extension/hello.so
  • main.php

    1. <?php
    2. function handler($event, $context) {
    3. var_dump(extension_loaded('hello'));
    4. hello_world();
    5. return "ok";
    6. }

PHP 内置库

函数计算的 PHP 运行环境中自带了一些常用库(Package)供您直接使用,目前包含的内置库如下所示。

Package 版本 内置库介绍
oss v2.3.0 对象存储 OSS SDK for PHP
tablestore v4.1.0 表格存储 TableStore SDK for PHP
mns v1.3.5.5 消息服务 MNS SDK for PHP
fc v1.1.0 函数计算 FC SDK for PHP

PHP 内置库使用示例

以下代码示例演示了如何使用 OSS 库中的方法上传一个 .txt 文件。

  1. <?php
  2. use OSS\OssClient;
  3. function handler($event, $context) {
  4. $accessKeyId = $context["credentials"]["accessKeyId"];
  5. $accessKeySecret = $context["credentials"]["accessKeySecret"];
  6. $securityToken = $context["credentials"]["securityToken"];
  7. $endpoint = "oss-cn-shenzhen.aliyuncs.com";
  8. $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint, false, $securityToken);
  9. $bucket = "my-bucket";
  10. $object = "php.txt";
  11. $content = "Hello fc!";
  12. try {
  13. $ossClient->putObject($bucket, $object, $content);
  14. } catch (OssException $e) {
  15. print($e->getMessage());
  16. }
  17. return 'success';
  18. }

PHP 自定义库

除内置库外,您可以在上传 PHP 函数代码时打包您需要的自定义库。建议您使用 Composer 添加自定义库。

下文进行详细介绍两种方式安装自定义库。

方式一:使用 Composer 添加自定义库示例

您要使用的库已经发布在 Packagist The PHP Package Repository 时,您可以使用 Composer 添加自定义库。下文演示添加 Humble HTTP request library package requests 的步骤。

1.新建目录用于存放代码和依赖模块。

  1. mkdir /tmp/code

2.新建代码文件,例如 /tmp/code/index.php ,在代码中使用 requests

  1. <?php
  2. require_once __DIR__ . "/vendor/autoload.php";
  3. function handler($event, $context){
  4. $headers = array('Accept' => 'application/json');
  5. $options = array('auth' => array('user', 'pass'));
  6. $request = Requests::get('https://www.baidu.com', $headers, $options);
  7. var_dump($request->status_code);
  8. // int(200)
  9. var_dump($request->headers['content-type']);
  10. // string(31) "application/json; charset=utf-8"
  11. var_dump($request->body);
  12. // string(26891) "[...]"
  13. }

3.在 /tmp/code 目录下安装自定义库。

  1. 编辑一份文件取名为 composer.json

    1. {
    2. "require": {
    3. "rmccue/requests": ">=1.0"
    4. }
    5. }
  2. 执行命令 composer install --no-dev 安装依赖。

  1. cd /tmp/code
  2. composer install --no-dev

方式二:直接下载自定义库

您要使用的库没有发布在 Packagist The PHP Package Repository 时,例如 Aliyun-openapi-php-sdk日志服务 PHP SDK,您可以直接下载对应库,然后在代码中直接引用。下文演示添加日志服务 PHP SDK 自定义库。

  1. 新建目录用于存放代码和依赖模块。

    1. mkdir /tmp/code
  2. 新建代码文件,例如 /tmp/code/index.php ,在代码中使用 requests

  1. <?php
  2. /* 使用 autoloader 类自动加载所有需要的 PHP 模块。注意使用合适的路径指向 autoloader 类所在文件 */
  3. require_once realpath(dirname(__FILE__) . '/aliyun-log-php-sdk/Log_Autoload.php');
  4. function handler($event, $context){
  5. $endpoint = 'cn-hangzhou.sls.aliyuncs.com'; // 选择与上面步骤创建 project 所属区域匹配的接入地址 Endpoint
  6. $accessKeyId = 'your_access_key_id'; // 使用您的阿里云访问密钥 AccessKeyId
  7. $accessKey = 'your_access_key'; // 使用您的阿里云访问密钥 AccessKeySecret
  8. $project = 'your_project'; // logProject 名称
  9. $logstore = 'your_logstore'; // LogStore 名称
  10. $client = new Aliyun_Log_Client($endpoint, $accessKeyId, $accessKey);
  11. # 列出当前 logProject 下的所有日志库名称
  12. $req1 = new Aliyun_Log_Models_ListLogstoresRequest($project);
  13. $res1 = $client->listLogstores($req1);
  14. var_dump($res1);
  15. }

3.在 /tmp/code 目录中下载依赖。

  1. cd /tmp/code
  2. git clone https://github.com/aliyun/aliyun-log-php-sdk.git

打包上传到函数计算

打包时,需要针对文件进行打包,而不是针对代码整体目录进行打包。打包完成后,入口函数文件需要位于包内的根目录。

  • 在 Windows 下打包时,可以进入函数代码目录,全选所有文件以后,单击鼠标右键,选择压缩为 zip 包,生成代码包。

  • 在 Linux 下打包时,通过调用 zip 命令时,将源文件指定为代码目录下的所有文件,实现生成部署代码包,例如 zip code.zip /tmp/code/*

打包后,您通过函数计算控制台代码执行页面,您可以选择 OSS 上传或者代码包上传方式上传代码包。

调用外部命令

当您的 PHP 函数需要调用非 PHP 语言构建的工具,例如 Shell、C++ 或 Go 编译出来的可执行文件,您可以将工具与函数代码一起打包上传,然后在函数中通过运行外部命令来使用工具。常见的调用外部命令的 PHP 方法有 execsystemshell-exec

说明:使用 C、C++ 和 Go 编译的可执行文件,需要与函数计算的运行环境兼容。函数计算的 PHP 运行环境采用了 Linux 4.4.24-2.al7.x86_64 内核版本和 Docker pull php:7.2 基础镜像。

下文代码示例演示了如何使用 exec 方法调用一个 Shell 脚本。

  1. <?php
  2. function handler($evt, $ctx){
  3. $script = $_ENV['FC_FUNC_CODE_PATH'] . '/script.sh';
  4. $a = exec("bash " . $script, $out, $status);
  5. print_r($a);
  6. var_dump($out);
  7. print_r($status);
  8. }