雲函數 SCF 中 PHP 的一些入門坑

本文來自 Serverless 社區用戶「逸笙」投稿javascript

因爲雲函數 SCF 自己是用 bootstrap.php 來調用咱們的入口函數,默認爲 index.main\_handler,意思是調用 index.php 文件中的 main\_handler(),因此不少地方寫法要有改變。php 通常提供網頁服務,因此我主要講API 網關配合的雲函數 SCF。php

main_handler($event, $context)函數會傳入2個參數,首先這2個參數是object,須要用->來訪問子項,如 $event->{'headers'} ,不是很方便,我通常轉換成數組:html

$event = json_decode(json_encode($event), true);

這樣就比較方便了,如 $event['headers']['host'] 。java

你們能夠打印這兩個參數看一眼裏面有些什麼。git

咱們能夠從中獲取到不少有用的東西,好比:github

$_GET = $event['queryString'];
$_POST = $event['body'];
$_COOKIE = $event['headers']['cookie'];

在雲函數 SCF 中運行的 php 程序,由於瀏覽器是提交給 API 網關,不是提交給 SCF 的,這些超全局變量徹底沒有獲取到東西,因此要這樣來獲取。express

但咱們發現,$event['body']$event['headers']['cookie'] 自己是一個長字符串,裏面有好幾個值,而且裏面 url 編碼了,這樣不方便使用,因此作些小操做:json

$postbody = explode("&",$event['body']);
foreach ($postbody as $postvalues) {
    $pos = strpos($postvalues,"=");
    $_POST[urldecode(substr($postvalues,0,$pos))]=urldecode(substr($postvalues,$pos+1));
}
$cookiebody = explode("; ",$event['headers']['cookie']);
foreach ($cookiebody as $cookievalues) {
    $pos = strpos($cookievalues,"=");
    $_COOKIE[urldecode(substr($cookievalues,0,$pos))]=urldecode(substr($cookievalues,$pos+1));
}

這樣就方便使用了。bootstrap

在雲函數 SCF 中,全局變量目前有個坑,就是上次訪問獲取的全局變量在此次並不會清空,因此本次訪問的時候,上次提交的值可能還在全局變量中,這個狀況無論是 php 固有的超全局仍是本身定義的,都有這個狀況,因此使用前注意 unset。api

用戶提交過來的數據,除了 GET、POST、COOKIE,還有一種比較重要的就是路徑了,好比這樣一個 url: https://hostname/path/file.jpg?foo=bar,在 API 網關中,/path/file.jpg 會被放到 $event['path'] 中,但注意,若是經過 API 網關默認 url 訪問,裏面會含有 /functionname ,注意去除(如下代碼將路徑裏起始的 '/' 也去除了):

$function_name = $context['function_name'];
$host_name = $event['headers']['host'];
$serviceId = $event['requestContext']['serviceId'];
if ( $serviceId === substr($host_name,0,strlen($serviceId)) ) {
    // using long url of API gateway
    // 使用API網關長連接時
    $path = substr($event['path'], strlen('/' . $function_name . '/'));
} else {
    // using custom domain
    // 使用自定義域名時
    $path = substr($event['path'], strlen($event['requestContext']['path']=='/'?'/':$event['requestContext']['path'].'/'));
}

取得用戶提交的信息後,就能夠本身處理了,過程不詳談,只是注意:

SCF 是隻讀的,只有 /tmp/ 目錄可讀寫,這個 tmp 目錄併發實例間互不相通,實例結束後銷燬。

處理完後,就要輸出給瀏覽器了,注意,由於跟瀏覽器對話的是 API 網關,

在代碼中直接 echo 的話,只會顯示在運行日誌中,瀏覽器徹底看不到,

因此

咱們須要在 main\_handler 中把須要顯示的東西 return 給 API 網關。

這時,若是要返回一個網頁,那 API 網關要勾選「集成響應」,SCF 這邊要返回一個特定結構的數組,這樣瀏覽器纔會正常顯示,否則瀏覽器就會只看到一堆字符串。

return [
    'isBase64Encoded' => false,
    'statusCode' => 200,
    'headers' => [ 'Content-Type' => 'text/html' ],
    'body' => $html
];

其中 body 就是咱們要返回的網頁內容,是個字符串;

headers 是給瀏覽器辨認的,Location 或 Set-Cookie 要放在這裏面;

statusCode 是狀態碼,能夠在 Location 時爲 302,也能夠在某些時候 404;

isBase64Encoded 是 API 網關用的,告訴它,body 裏面是否 base64 加密。

這樣返回,瀏覽器就會顯示一個 HTML 網頁了。

但有些時候,咱們想給一個文件給用戶下載,這時候,就要用到 isBase64Encoded 了:

$image_data = fread(fopen('logo.png', 'r'), filesize('logo.png'));
return [
    'isBase64Encoded' => true,
    'statusCode' => 200,
    'headers' => [ 'Content-Type' => 'image/png' ],
    'body' => base64_encode($image_data)
];

這樣瀏覽器會直接獲得一個 png 文件,有些瀏覽器彈出下載,有些本身就打開了。

上面代碼已經提交到雲函數 SCF 模板庫:https://github.com/tencentyun/scf-demo-repo/tree/master/Php7.2-QRcodewithLogo ,不吝賜教!

One More Thing

3 秒你能作什麼?喝一口水,看一封郵件,仍是 —— 部署一個完整的 Serverless 應用?

複製連接至 PC 瀏覽器訪問:https://serverless.cloud.tencent.com/deploy/express

3 秒極速部署,當即體驗史上最快的 Serverless HTTP 實戰開發!

傳送門:

歡迎訪問:Serverless 中文網,您能夠在 最佳實踐 裏體驗更多關於 Serverless 應用的開發!


推薦閱讀:《Serverless 架構:從原理、設計到項目實戰》

相關文章
相關標籤/搜索