2019年1月16日 星期三

Google App Engine (GAE) 與 Laravel 5.7

2018/11 開始了新的專案,這個專案的目標是

  1. 取得Google Cloud Billing 資料然後整理呈現報表
  2. 使用者類別有:管理者/經銷商/一般客戶
  3. 不同類別使用者顯示的 Billing 金額不同,差異為服務費與折扣

主要的架構流程

  1. 取得每日的 Billing 資料並儲存到 Google BigQuery (Cloud SQL 無法應付每個月千萬筆的資料成長)
  2. 使用 Google service account & Oauth certification 透過 Google Cloud Platform 取得資料
  3. 透過 UI 呈現不同的資料分析(Chart / DataTable),提供不同的報表下載(CSV / PDF)

技術規格選用

  1. Laravel 5.7 (每個新案子都得要用最新的 stable的版本)
  2. PHP 7
  3. 第三方的 Library 一堆(這個都交給composer去管理吧)


所有的服務都建構在 Google Cloud Platform 上,包含 Version control。
在 GCE與GAE的選擇上做了些研究,最後選擇了GAE。理由很簡單,就是為了 Flexible。

整個案子很多環節遇到了很多問題,但是一開始的問題就是 Laravel 的安裝,GAE不像是 GCE 可以自由地瀏覽空間中的檔案並且及時修改。Deploy上去後就無法看到或是管理任何的檔案,而且最讓人困擾的就是每次的 Deploy 都要花上5-10分鐘,所以只要一次的疏忽就得要重新來一次,非常的浪費時間。

所以文章主要將問題簡單的拆分兩個,這兩個解決了,其他都可以參考個別的技術文件去學習。

  1. Laravel 的安裝與設定
  2. PDF 中文字型的安裝 (dompdf)

Laravel 的安裝與設定


laravel 5.7 + composer 1.8.0 + phpstorm 2018.1.16

下面就透過步驟來展示

使用 phpstorm 建立 laravel 專案

開啟 phpstorm > New project > Composer project ,Package 選擇 laravel/laravel 然後點選 create
你也可以只使用 composer 就可以完成





在根目錄下新增 app.yaml 檔案

這個檔案用於 GAE 的環境設定,也是唯一可以設定 GAE的方法,不需要懷疑,因為沒有其他方法了。


修改 app.yaml

直接把所有 .env 的設定都移到這個檔案來,下面我直接把說明備註在後面

runtime: php #php版本設定,在撰寫這篇文章的時候 php72 無法設定 env_variables
env: flex #GAE flexible選用

runtime_config:    document_root: public #網站根目錄設定, laravel 是public
    composer_flags:  --no-dev # composer 設定不安裝開發用套件

env_variables: # 下面都是 laravel 的環境設定,也就是說將需要在 .env 的設定都搬來這裡  APP_KEY:  'base64:hWWKPKQ6u48Cn8lw4WM00UHdCEQJerEQk5ognsy4u' # 必須使用 artisan 產生後複製過來  APP_LOG: errorlog 
  STORAGE_DIR: /tmp #GAE上除了 tmp 目錄外都只會有 readonly 權限
  APP_NAME: "[BETA]GCPBS| Summer "  APP_ENV:  production
  APP_DEBUG:  true
  CACHE_DRIVER: database
  SESSION_DRIVER:  database
  GCP_PROJECT_ID:  'summer-digital.com'  GCP_PROJECT_BUCKET_ID:  'summer-digital.appspot.com'
  GCP_BILLING_DATASET_NAME:  'summer-digital.com.billing-history'
  GCP_CLIENT_SECRET:  '/resources/gcp/summer-client-secret.json'
  GCP_SERVICE_ACCOUNT_CREDENTIAL:  '/resources/gcp/summer-service-account.json'  DB_CONNECTION:  mysql
  DB_HOST:  localhost
  DB_PORT:  3306
  DB_DATABASE:  summer
  DB_USERNAME:  summer
  DB_PASSWORD:  summer
  DB_SOCKET:  "/cloudsql/summer:asia-northeast1: summer-production"

修改 composer

deploy 後我們必須對 laravel 作 cache 的清理,否則會出現路徑上的問題,但是無法操作GAE所以只能透過 composer scripts 來代勞,在 composer.json 中新增下面的 scripts。GAE在 deploy後會執行 composer install,所以下面的 script 可以幫我們清理 laravel 的cache。

"scripts": {
  "post-autoload-dump": [
    "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
    "@php artisan package:discover",
    "@php artisan config:cache",
    "@php artisan view:clear"]
}



部署到 GAE

執行指令前必須安裝 Gcloud SDK,而且需要設定 GCP。部署只需在 Terminal 執行下面指令


YUCHANs-MBP:~ yuchanlin$ gcloud app deploy

deploy log 會以文字訊息的方式顯示。

部署完成後執行


YUCHANs-MBP:~ yuchanlin$ gcloud app browse

就可以測試 laravel 是否安裝成功


PDF 中文字型的安裝 (dompdf)

PDF我透過 composer 安裝使用 dompdf 0.8.3 的版本,但是安裝後本身並無中文字型,所以必須要透過下面步驟安裝字型才能正常的顯示中文。

下載上方的資源體字型檔案,必須是 TTF 格式,然後到下面的位置

  1. storage/fonts/NotoSansTC-Medium.ttf
  2. storage/fonts/NotoSansTC-Bold.ttf

下載字型安裝工具

下載 load_font.php 然後放到 laravel 目錄下


安裝字型

開啟 Terminal 然後到 load_font.php 目錄下執行下面指令


php load_font.php storage/fonts/NotoSansTC-Medium.ttf storage/fonts/NotoSansTC-Bold.ttf 


執行完成後,會將字型安裝到 dompdf/lib/fonts 中,在 html 裡頭就可以透過 css 設定中文字型:
body {
    font-family: 'notosanstc';
    font-size: 16px;
    color: #555e6b;
}

設定 composer 


因為部署不會把 vendor 上傳上去,有兩個原因
  1. GAE限制 deploy 的檔案限制是 100,00
  2. 把 vendor 上傳上去需要花很多時間,很浪費時間
所以需要透過 composer scripts 在 install 後幫忙安裝字型檔案
"scripts": {
  "post-autoload-dump": [
    "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
    "@php artisan package:discover",
    "@php artisan config:cache",
    "@php artisan view:clear",
    "@php load_font.php 'notosanstc' storage/fonts/NotoSansTC-Medium.ttf storage/fonts/NotoSansTC-Bold.ttf"  ]
}

下面的範本包含圖檔的處理與產生PDF的設定:



$arrContextOptions = array(    "ssl" => array(        "verify_peer" => false,        "verify_peer_name" => false,    ),);
$type = pathinfo($logoUrl, PATHINFO_EXTENSION);$avatarData = file_get_contents($logoUrl, false, stream_context_create($arrContextOptions));$avatarBase64Data = base64_encode($avatarData);$imageData = 'data:image/' . $type . ';base64,' . $avatarBase64Data;
$html = view('export/html',    compact('table', 'currency', 'total', 'logoUrl', 'imageData', 'billingName', 'firstDay', 'lastDay', 'time', 'businessSupport', 'discount', 'paymentDueDay'))    ->render();
$options = new Options();$options->setIsHtml5ParserEnabled(true);$options->setIsPhpEnabled(true);$options->setIsRemoteEnabled(true);$options->setIsJavascriptEnabled(true);
$dompdf = new Dompdf($options);$dompdf->setPaper('A4', 'portrait');
$dompdf->loadHtml($html, 'utf8');$dompdf->render();$dompdf->stream($downloadFileNmae . '.pdf', ['compress' => 1, 'Attachment' => 1]);

上面展示了 laravel  部署到 GAE的方式,也說明了 dompdf 中文字型的安裝方式,其餘開發上的問題都可以直接閱讀 laravel / composer / dompdf 官網文件來解決了。


希望大家可以透過我的分享省去些摸索的時間。


參考資料

  1. Google App Engine Document
  2. Google Cloud SDK
  3. Laravel 5.7 Document
  4. Composer Document
  5. Dompdf