作者: Jerry Lin

  • WordPress SSL 錯誤修復

    最近使用 wordpress 外掛,透過 curl 可能會發生錯誤,如果遇到這類型的錯誤:

    SSL certificate problem: certificate has expired
    SSL certificate problem: certificate has expired

    是因為許多網站都在使用全球證書,該證書已於 2021 年 9 月 30 日到期。參考:

    解決方法是使用新的 crt 檔案替代 wordpress 目錄:wp-includes/certificates 底下的 ca-bundle.crt 檔案。
    crt 檔案下載網址:https://github.com/WordPress/WordPress/blob/master/wp-includes/certificates/ca-bundle.crt

    而這個問題預估在 wordpress 5.9 版會修復。

    參考:

    SSL certificate problem: certificate has expired – Smart Slider Documentation
    In this article Check the error Error only displays during update Solution on localhost servers (with WampServer example) A lot of websites are using a global c

  • WordPress 之中藍新金流開啟後, Elementor 外掛有時會打不開的問題處理

    WordPress 之中藍新金流開啟後, Elementor 外掛有時會打不開的問題處理

    WordPress 有很多外掛,在藍新金流啟用時,同時有使用 Elementor 這個 page builder 外掛,在某些編輯視窗中,可能會造成 AJAX “/wp-json/elementor/v1/globals” 路徑中抓不到 wc_get_chosen_shipping_method_ids() 這個 function 的錯誤訊息。

    這邊查了一下資料,不只是藍新金流外掛會這樣,應該 woocommerce 外掛和 page builder 都有可能造成類似的錯誤。紀錄一下避免老了忘記。

    最近又遇到一樣的問題,查看 log 發現是 wc_get_chosen_shipping_method_ids() 裡面的問題:

    2024/01/02 19:30:32 [error] 1870242#1870242: *46728 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Uncaught Error: Call to a member function get() on null in /xxx/xxx/wp-content/plugins/woocommerce/includes/wc-cart-functions.php:394
    Stack trace:
    #0 /xxx/xxx/wp-content/plugins/newebpay/class-newebpay.php(1673): wc_get_chosen_shipping_method_ids()
    
    ...

    查看 woocommerce 的程式碼(參考),並且參考有類似問題的 stackoverflow

    function wc_get_chosen_shipping_method_ids() {
    	$method_ids     = array();
    	$chosen_methods = WC()->session->get( 'chosen_shipping_methods', array() );
    	foreach ( $chosen_methods as $chosen_method ) {
    		$chosen_method = explode( ':', $chosen_method );
    		$method_ids[]  = current( $chosen_method );
    	}
    	return $method_ids;
    }

    判斷應該是 WC()->session 取不到 get 參數,實際上就是這樣沒錯, woocommerce 當下這個沒有判斷 session 為空的狀況。
    可以參考原文,於 class-newebpay.php:1676 附近, wc_get_chosen_shipping_method_ids() 呼叫之前判斷 WC()->session 是否為空。這邊於底下原文中添加新的 code 。

    附上錯誤訊息:

    Fatal error: Uncaught Error: Call to undefined function wc_get_chosen_shipping_method_ids() in /xxx/wp-content/plugins/newebpay/class-newebpay.php:1676 Stack trace: #0 /xxx/wp-includes/class-wp-hook.php(303): newebpay_alter_payment_gateways(Array) ...

    附上發現錯誤的版本資訊,wordpress 核心版本為 5.8.1 , Elementor 版本為 3.4.3:

    /**
     * newebpay Payment Gateway
     * Plugin URI: http://www.newebpay.com/
     * Description: 藍新金流收款/物流 模組
     * Version: 1.0.3
     * Author URI: http://www.newebpay.com/
     * Author: 藍新金流 newebpay
     * Plugin Name:   藍新金流
     * @class       newebpay
     * @extends     WC_Payment_Gateway
     * @version
     * @author  Pya2go Libby
     * @author  Pya2go Chael
     * @author  Spgateway Geoff
     * @author  Spgateway_Pay2go Q //20170217 1.0.1
     * @author  Spgateway_Pay2go jack //20170622 1.0.2
     * @author  Spgateway_Pay2go Stally //20180420 1.0.3 20181018 1.0.4 20181222 newebpay 1.0.0 20190417 1.0.1 20190711 1.0.2 20200326 1.0.3
     */

    目前的解決方法是在 class-newebpay.php:1676 的 newebpay_alter_payment_gateways() 內添加判斷,檢查是否有方法,沒方法就直接跳回不動作。
    另外也在 plugin meta 上修改版本號和描述,避免被直接更新。不過這個外掛也沒上版控,所以屆時可能需要也是手動更新嘍。

    附上修改後資訊:

    <?php
    /**
     * newebpay Payment Gateway
     * Plugin URI: http://www.newebpay.com/
     * Description: 藍新金流收款/物流 模組 修復了 elementor 開啟會有 wc_get_chosen_shipping_method_ids 錯誤的問題 
     * Version: 99.99.99
     * Author URI: http://www.newebpay.com/
     * Author: 藍新金流 newebpay 修改過 By Jerry
     * Plugin Name:   藍新金流
     * @class       newebpay
     * @extends     WC_Payment_Gateway
     * @version
     * @author  Pya2go Libby
     * @author  Pya2go Chael
     * @author  Spgateway Geoff
     * @author  Spgateway_Pay2go Q //20170217 1.0.1
     * @author  Spgateway_Pay2go jack //20170622 1.0.2
     * @author  Spgateway_Pay2go Stally //20180420 1.0.3 20181018 1.0.4 20181222 newebpay 1.0.0 20190417 1.0.1 20190711 1.0.2 20200326 1.0.3
     */
    add_action('plugins_loaded', 'newebpay_gateway_init', 0);
    
    function newebpay_gateway_init() {
        if (!class_exists('WC_Payment_Gateway')) {
            return;
        }
    
        class WC_newebpay extends WC_Payment_Gateway {
    
     ...
    
        // 選擇藍新金流超商取貨後 payment只輸出藍新金流
        function newebpay_alter_payment_gateways($list) {
            if(isset($_GET['pay_for_order']) && isset($_GET['key'])) {
                $order_id = wc_get_order_id_by_order_key($_GET['key']);
                $order = wc_get_order($order_id);
                if($order->has_shipping_method('newebpay_cvscom')) {
                    $list = array('WC_newebpay');
                }
            } elseif(!is_admin()) { //後台無wc_get_chosen_shipping_method_ids function
                if ( !function_exists( 'wc_get_chosen_shipping_method_ids' ) ) { 
                    return $list;
                } 
    
                // 2024-01-02 更新判斷
                $session = WC()->session;
                if($session){
                    $chosen_shipping = wc_get_chosen_shipping_method_ids();
                    //判斷購物車內商品是否全為虛擬商品 全為虛擬商品時會無法選擇物流方式 導致session的chosen_shipping會維持上次所選
                    $virtual_count = 0;
                    $cart_items = WC()->cart->get_cart();
                    foreach ($cart_items as $key => $cart_item) {
                        $virtual_count += ($cart_item['data']->is_virtual()) ? 1 : 0;
                    }
                    if (@in_array('newebpay_cvscom', $chosen_shipping) && $virtual_count < count($cart_items)) {
                        $list = array('WC_newebpay');
                    }
                } // end 判斷
            }
    
            return $list;
        }
        add_filter('woocommerce_payment_gateways', 'newebpay_alter_payment_gateways', 100);
    
    ...
  • Linux SSH 斷線後保持 session 的工具 – Screen

    紀錄一下之前用很久的一個 linux 套件,主要用途是作爲讓 Server 在再斷線後,依然可以跑池長時間非背景運作。

    安裝方法,權限問題請自行加上 sudo:

    # ubuntu \ debian
    apt-get install screen
    
    # centos
    yum install screen

    一些基本的操作:

    # 建立一個新的 screen 
    screen -U -S SCREEN_NAME
    
    # 進入已開啟的 screen
    screen -drU SCREEN_NAME
    
    # 列出所有 screen
    screen -ls

    至於進入 screen 內的操作,請參考:

    大概可以記住:所有指令都是 ctrl + a 開始。

    • c 是關閉一個建立一個新視窗。另外要離開當前視窗,就和一般 ssh 一樣輸入 exit 就行了,會殺掉當前視窗的 session。
    • d 是離開當前的 screen (keep session)
    • A 大寫的 a 可以重新命名當前的視窗,這很好用

    以前同事有分享一個 screenrc 設定檔案,不錯用。請自行取代 /etc/screenrc 檔案:

    startup_message off
    defencoding utf8
    encoding utf8 utf8
    #caption always "%{= wk} %{= KY} [%n]%t @ %H %{-} %= %{= KR} %l %{-} | %{= KG} %Y-%m-%d %{-} "
    #hardstatus alwayslastline " %-Lw%{= Bw}%n%f %t%{-}%+Lw %=| %0c:%s "
    #bindkey ^[z prev
    #bindkey ^[x next
    termcapinfo xterm*|rxvt* 'ti@:te@'
    termcapinfo xterm ti@:te@
    vbell off
    # C + left : prev
    # C + right : next
    bindkey "^[[1;5C" next
    bindkey "^[O5C" next
    bindkey "^[[C" next
    bindkey "^[[1;5D" prev
    bindkey "^[O5D" prev
    bindkey "^[[D" prev
    
    
    # C-a b : encoding big5
    # C-a u : encoding utf8
    bind b encoding big5 utf8
    bind u encoding utf8 utf8
    
    
    # C-b $num : move current window to number $num
    bind -c move 0 number 0
    bind -c move 1 number 1
    bind -c move 2 number 2
    bind -c move 3 number 3
    bind -c move 4 number 4
    bind -c move 5 number 5
    bind -c move 6 number 6
    bind -c move 7 number 7
    bind -c move 8 number 8
    bind -c move 9 number 9
    bindkey "^b" command -c move
    
    
    # F12 : fast kill
    #bindkey "^[[24~" kill
    
    
    #termcapinfo xterm 'hs:ts=\E]0;:fs=\007:ds=\E]0;bash\007'
    #caption always "%{= bk} %{= wk} %-Lw%{by}%n+%f %t%{wk}%{wk}%+Lw %=%{kw}%{= R}%{-}"
    
    
    shelltitle '$ |csh'
    
    
    defhstatus "\005t"
    #hardstatus on
    #caption always "%{= wk} %{= KY} [%n]%t @ %H %{-} %= %{= KR} %l %{-} | %{= KG} %Y-%m-%d %{-} "
    #hardstatus alwayslastline " %-Lw%{= Bw}%n%f %t%{-}%+Lw %=| %0c:%s "
    
    
    #buttom status bar
    caption always "%{= .G} %-w%<%{=ub .y}[%n %t]%{= .G}%+w "
    hardstatus alwaysignore
    #hardstatus alwayslastline "%{= .K} [%l]%<%=%{= .W}@%H %=%{= .y} %Y/%m/%d%{= .m} %C %A"
    
    
    #shelltitle '$|csh'
    #caption always "%{bw}%M/%d %c %{wb} %-w%{c}%n %t%{w}%+w%{k}"
    
    
    shell -$SHELL
  • 排程檢查服務是否正常

    好久以前遇到一些伺服器鬼故事,所以參考網路上的資料,弄了一個排程檢查系統服務的機制,配合上 crontab 可以使用。

    原則上,這個做法和把程式 try / catch 包起來一樣,掩耳盜鈴的行徑。在沒有安全疑慮的狀況下,建議配合 log 確認系統紀錄,這樣可以保持穩定又可以找到系統問題,不失為一個權宜之計。

    使用的環境是 CentOS7 / Linode VPS ,從指令上來看應該 debian 系列的也可以用才對。

    操作上只要把 service 的變數替換為對應的服務名稱即可,以下是 mysql 檢查重啟的 code.

    #!/bin/bash
    
    PATH=/usr/sbin:/usr/bin:/sbin:/bin
    
    service=mysql
    if [[ ! "$(/usr/sbin/service $service status)" =~ "running" ]]
    then
        echo "`date "+%Y-%m-%d %H:%M:%S"` | [logadm -on@`date "+%Y%m%d%H%M%S"`] "
        echo "$service is stop!!"
        /usr/sbin/service $service start
    else
        echo "`date "+%Y-%m-%d %H:%M:%S"` | [logadm -on@`date "+%Y%m%d%H%M%S"`] "
        echo "$service is running"
    fi

    同場加映,今天寫這篇時,網路上再找了一下,找到一些比較進階的檢查 code:

  • Docker 初體驗

    最近在嘗試用 docker 建構各種環境,目標有 N 個:

    1. 實現 docker 的優勢,讓開發環境和正式環境一致,去除可能的環境差異
    2. 讓環境設定模塊化,搭配已經整理好的設定檔案,減少重複架設的工作內容
    3. 環境設定可以更為彈性和獨立,降低耦合,增加不同語言協作的可行性。

    我想打造一個可以無腦部署又有彈性而且開發成本低的系統部署方法就是。

    這邊弄了一個 LEMP 的結構,未來應該會在不斷新增各種可選的設定檔案上去這樣。

    GitHub – lazyjerry/docker-compose-lemp-stack: Docker Compose LNMP 結構安裝
    Docker Compose LNMP 結構安裝. Contribute to lazyjerry/docker-compose-lemp-stack development by creating an account on GitHub.

    有興趣可以幫我點星星和留言。

    先說設定檔案我都是網路上直接抓模板還有抄各種 hosting panel 的設定檔,到時還要再優化是真的。

    目前玩到這裡的有些結論,記錄起來避免忘記:

    1. 這肯定套件王愛用,hub 上很多已經有配置好的,每個都是獨立的一包不會互相依賴。
    2. 不會互相依賴也是有壞處,一些基礎的套件要分開裝,所以使用 docker 還是有門檻在。
    3. 設定檔案先寫好,docker 的優勢就會出來,到時一包一個配置好裝起來就可以用。
    4. 但是因為設定檔案必須先寫好的原因,所以如果在本機開發環境上,常常會遇到一次要開不同的案子,這邊本機用 docker 就會囧囧的。
    5. 所有的 config 建議 mont 到宿主機的磁碟上,這邊如果不是使用官方的 docker image 就會囧囧,很多 docker 會包成一包,這樣違反 docker 無狀態的精神,建議套件王避開這種 image。
    6. 不要把 docker 當作 VM 來跑作業系統,這樣彈性就跑掉了。然而我也不懂是為什麼會有文章寫不建議 docker 跑 mysql ? 這個問題待釐清就是。

    這裡有一份對岸知乎的比較文章,簡體字閱讀功能沒障礙的話推薦可以看一下:

    请问各位业界人士,Docker的优缺点有哪些? – 知乎
    如题,有一篇相关论文提到了docker。我随便看了看感觉这东西缺点很多,尽管安装后使用可以省掉很多安装第…


    同場加映 附上 Docker 安裝步驟

    安裝套件

    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

    docker.repo 中也同時包含 edge 版本的 Docker 套件庫,不過預設是被停用的,想安裝 edge 版本的話,就要先啟用 edge 版本的套件庫(如果只是要安裝 stable 版本的人,就可以省略這一步):

    sudo yum-config-manager --enable docker-ce-edge

    更新 yum 的套件索引:

    sudo yum makecache fast

    安裝 Docker CE 版:

    sudo yum install docker-ce

    第一次安裝 Docker 的時候,會需要匯入 GPG 的金鑰,Docker CE 版的金鑰指紋是 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35 確認無誤就選擇 y 匯入。

    安裝好之後,啟動系統的 Docker 服務:

    sudo systemctl start docker

    執行 hello world 程式測試:

    sudo docker run hello-world

    安裝 docker-compose

    curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    chmod +x /usr/local/bin/docker-compose

    建立連結

    ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

    測試版本,應該要顯示版本號碼

    docker-compose --version
    
    # docker-compose version 1.29.2, build 1110ad01

    啟動 docker

    systemctl start docker;systemctl enable docker;




    參考資料:

    專家觀點:Docker架構優缺點大剖析
    深入研究Docker原始碼、著有《Docker源碼分析》而大受好評的中國Docker …
    Share Compose configurations between files and projects
    How to use Docker Compose's extends keyword to share configuration between files and projects

    GitHub – stevenliebregt/docker-compose-lemp-stack: Docker Compose Linux Nginx MariaDB PHP7.2 Stack
    Docker Compose Linux Nginx MariaDB PHP7.2 Stack. Contribute to stevenliebregt/docker-compose-lemp-stack development by creating an account on GitHub.

    可以裝起來抓裡面的設定檔案樣板,滿實用我覺得

    GitHub – aaPanel/BaoTa: 宝塔Linux面板 – 简单好用的服务器运维面板
    宝塔Linux面板 – 简单好用的服务器运维面板. Contribute to aaPanel/BaoTa development by creating an account on GitHub.

    2021-07-29 update

    推薦一個不錯的筆記:

  • 一些關於 iMessage 的注意事項

    iMessage 是 Apple 提供有別於 SMS ,但是又放在同一個 APP 中的通訊管道,使用 Apple ID 作為帳號(廢話),內建在 Mac 和 iOS 系統中,非常方便。但近年來 Apple 積極的防治 iMessage 被當做廣告群發的通道,也導致很多人被阻擋、甚至被停止了 iMessage 的使用權限。這裡分享一些關於 iMessage 的注意事項:

    導致 iMessage 帳號被封鎖的原因

    如果 iMessage 帳號被封鎖了應該怎麼辦?

    If you can't sign in to your iMessage account or FaceTime on your Mac
    If you can't sign in to your iMessage account or FaceTime, one of these solutions might help.

  • iOS 權限提示(Protected Resources)

    在 iOS 的二進制檔案上傳之後,有時會有關於 Missing Purpose String in Info.plist  的錯誤,參考這個鏈結會發現需要在 info.plist 中添加說明的字串,這裡列表一份,以後可以直接使用。

    <key>NSSpeechRecognitionUsageDescription</key>
    <string>App需要您的同意,才能訪問語音識別</string>
    <key>NSAppleMusicUsageDescription</key>
    <string>App需要您的同意,才能訪問媒體資料庫</string>
    <key>NSBluetoothPeripheralUsageDescription</key>
    <string>App需要您的同意,才能訪問藍牙</string>
    <key>NSCalendarsUsageDescription</key>
    <string>App需要您的同意,才能訪問日曆</string>
    <key>NSCameraUsageDescription</key>
    <string>App需要您的同意,才能訪問相冊</string>
    <key>NSContactsUsageDescription</key>
    <string>App需要您的同意,才能訪問通信錄</string>
    <key>NSHealthShareUsageDescription</key>
    <string>App需要您的同意,才能訪問健康分享</string>
    <key>NSHealthUpdateUsageDescription</key>
    <string>App需要您的同意,才能訪問健康更新</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>App需要您的同意,才能始終訪問位置</string>
    <key>NSLocationUsageDescription</key>
    <string>App需要您的同意,才能訪問位置</string>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>App需要您的同意,才能在使用期間訪問位置</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>App需要您的同意,才能訪問麥克風</string>
    <key>NSMotionUsageDescription</key>
    <string>App需要您的同意,才能訪問運動與健身</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>App需要您的同意,才能訪問相機</string>
    <key>NSRemindersUsageDescription</key>
    <string>App需要您的同意,才能訪問提醒事項</string>
  • Flutter 開發環境設定(影片)

    筆記一下,避免以後換新電腦都忘記這種三百年才會設定一次的開發環境。

  • iOS APP 上架注意事項

    筆記一下,有點久沒寫 app 了。最近在用 flutter 套版實作 iOS 和 Android 工具 app , Android 上架沒意外介面大改版,不過還算難不倒我,遇到的問題比較多是 flutter 簽名的問題,寫好 shell 用 command line 執行還算簡單,但是 iOS 上架就麻煩了,真心懷疑 iOS 和 Facebook 的人工審核是包給同一家公司做的……。

    這編列點一下,也把自己的經驗整理起來,希望可以記起來不要給踩兩次雷了:

    1. 關鍵字欄位可以為空,如果不為空,要注意描述、標題、子標題內不可以和關鍵字重複
    2. 權限要求要記得附上說明,會顯示在要求權限時的 alert 副標題,可以參考這個鏈結
    3. 如果應用程式內容被判斷為 “未經過濾的互聯網訪問”,要注意年齡要改成 17+
    4. 支援網址可以放自己的個人網站、記得要做隱私權網址,推薦可以弄一個靜態網站起來,各種語系各種內容這樣。
    5. 用 flutter 開模擬器截圖的話,會有 debug banner,包含 debug 示意的截圖是不被允許的,參考這個鏈結可以解決。
    6. 上傳檔案、送審都會有 email 通知,如果遇到鬼打牆的狀況,像是上傳了一直沒產生二進制檔案選擇,記得收信看一下有沒有提示錯誤。

    革命尚未成功,還會持續更新,請同志繼續努力。

    真的太久沒弄上架,目前還在和審核人員戰鬥中,希望能夠順利上架啊。稍微抱怨一下,不管是 fb 還是 iOS 的 app 審核也都滿討厭的,送審一次問題就丟一個回來,然後光是上架頁面表單填寫的問題就來來回回兩三次了,為什麼不要ㄧ次送審把有遇到的問題丟回來勒,難怪有專門幫人代操上架的工作,這也算是造就一個產業鍊吧。

  • Flutter 建立 iOS 專案遇到 Missing Purpose String in Info.plist 問題

    使用 Flutter 建立 iOS release 專案時,如果上傳失敗會得到一封檢測錯誤的信件,其中有一個錯誤是 Missing Purpose String in Info.plist ,裡面會有

    Your app’s code references one or more APIs that access sensitive user data. The app’s Info.plist file should contain a NSContactsUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. Starting Spring 2019, all apps submitted to the App Store that access user data are required to include a purpose string. If you’re using external libraries or SDKs, they may reference APIs ….

    你會在你註冊的信箱中收到錯誤的信件

    關鍵字是 NSContactsUsageDescription ,表示缺乏要求權限的文字訊息。而在 info.plist 添加要求資訊以後還是會有錯,才發現是因為使用 permission_handler 這個 dart 套件,他需要一些額外設定。

    先放一下 Flutter 的 iOS 上架流程:

    发布的IOS版APP – Flutter中文网
    本文介绍了如何构建Flutter的IOS发布版,并将其发布到App Store或TestFlight。

    參考這兩個鏈結:

    iOS macro not working with new Flutter 1.20.0 Podfile · Issue #358 · …
    ? Bug Report After upgrading to Flutter 1.20.0 beta a new Podfile needs to be generated (flutter/flutter#45197). Afterwards I added the configuration to the Podfile but it is not taking effect. I r…

    主要就是要把不需要的權限給關掉才行,如果有用這個套件的話要特別注意。
    注意 Profile 更新過後,要把 Profile.lock 刪除再重新 pod install 一次。

    Update 權限參考: