2022年7月20日 星期三

PHP 開發筆記 - 使用 Google Analytic (GA4) Measurement Protocol

使用 GA Measurement Protocol 大概也有超過五年了 XD 最近一直收到通報,說舊版 GA Measurement Protocol 即將在 2023.07.01 不在接收資料處理,簡稱看不到報表。

建立一個 GA4 專案後,發現要在使用 Measurement Protocol 的難度有稍微增加。包括測試也有點卡卡 XD 最近就記錄一下筆記:
首先,想要模擬個 page_view 時,才發現官方文件沒有多提,後來大概是組出這樣:

{
    "client_id":"00000000",
    "non_personalized_ads":true,
    "events":[
        {
            "name":"page_view",
            "params":{
                "page_title":"hello",
                "page_location":"blog.changyy.org"
            }
        }
    ]
}

而 PHP Code:

function _GA4_($api_secret, $measurement_id, $deviceId, $deviceIP, $events = array()) {
    $query_string = array(
        'measurement_id' => $measurement_id,
        'api_secret' => $api_secret,
    );  
    if (!empty($deviceIP)) {
        // https://support.google.com/analytics/answer/9143382
        // https://github.com/dataunlocker/save-analytics-from-content-blockers/issues/25
        $query_string['uip'] = $deviceIP;
        $query_string['_uip'] = $deviceIP;
    }   
    $url = 'https://www.google-analytics.com/mp/collect?'.http_build_query($query_string);
    //$url = 'https://www.google-analytics.com/debug/mp/collect?'.http_build_query($query_string);

    //  post without libcurl
    // https://ga-dev-tools.web.app/ga4/event-builder/
    $payload = array(
        'client_id' => $deviceId,
        'non_personalized_ads' => true,
        //'timestamp_micros' => "".floor(microtime(true) * 1000)."000",
        'events' => $events,
    );

    //if (isset($_SERVER) && isset($_SERVER['COUNTRY_CODE']) && !empty($_SERVER['COUNTRY_CODE']) ) {
    //        if (!isset($payload['user_properties']))
    //                $payload['user_properties'] = array();
    //        $payload['user_properties']['country_code'] = array(
    //                'value' => $_SERVER['COUNTRY_CODE'],
    //        );
    //}

    $POST_DATA = json_encode($payload);
    $options = array(
        'http' => array(
            'header' => implode("\r\n", array(
                "Content-Type: application/json",
                //"Content-Length: ".strlen($POST_DATA),
            )), 
            'method' => 'POST',
            'content' => $POST_DATA,
        )   
    );  
    $context  = @stream_context_create($options);
    $result = @file_get_contents($url, false, $context);
    //echo "result:[$result]\n$POST_DATA\n".print_r($options)."\n";exit;
}

如此,就可以用以下完成事件回報了:

_GA4_($api_secret, $measurement_id, $deviceId, $deviceIP, array(
    array(
        'name' => 'page_view',
        'params' => array(
            'page_title' => 'Hello',
            'page_location' => 'https://blog.changyy.org/',
        ),
    )
);

而使用 https://www.google-analytics.com/debug/mp/collect 驗證時,有錯誤可以在 http response body 看到資料,例如:

{
  "validationMessages": [ {
    "description": "Unable to parse Measurement Protocol JSON payload. : invalid value Cannot bind a list to map for field 'user_properties'. for type Map",
    "validationCode": "VALUE_INVALID"
  } ]
}

2022年7月7日 星期四

Node.js 開發筆記 - 模擬 Web Browser 環境,執行前端 JS code / library

最近協助同事處理一個棘手的事,把一段需要算力的 JS Code 從本地端改成雲端運行,首要碰到的就是 node.js 預設環境並沒有很適合,如果有 JS library 十分依賴 Web Browser 環境時,那段 js code 透過 eval 運行時,會出現初始化錯誤。

原本土炮零碎地拼湊出 window, document, location, hostname 等把環境弄的堪用,後來還是先找一下,找到 browser-env 這套件,非常不錯!套上去後,所有土炮破壞架構美感的東西都可以去掉了。

如此,如果要將算力很高的任務拋去雲端計算時,且不幸依賴很多常見的 Web browser 套件邏輯時,就可以如此封裝成一隻 api ,供人把算力高的任務拋去高速運算的機器處理即可。

註:此例用 eval 是個危險的用法,只適合運行信任的程式碼,亂給使用者填寫會有高資安風險的。


範例:
  • 故意在 node.js 植入前端 jQuery library - https://code.jquery.com/jquery-3.6.0.slim.min.js (實務上真的有需求時,是要找 node.js 套件)
  • 在 node.js 透過 eval 啟用整段程式碼時,缺少 web browser 環境時,會噴錯誤訊息:TypeError: Cannot read properties of undefined (reading 'createElement')

2022年6月24日 星期五

Go開發筆記 - 使用 net/http 處理 URL Redirect 和 Cookie 之 Service Unit Test 需求

最近用 Golang 撰寫 Service Unit Test 時,練了一下 net/http 要如何處理 HTTP Response Header Location 的處理。主要是在使用 net/http 的 http.Client 時,可以加設定 CheckRedirect 的機制來阻擋 URL Redirect 的行為,藉以檢驗 URL Redirect 是否正確。

//httpClient := http.DefaultClient
httpClient := &http.Client{}

httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}

if jar, err := cookiejar.New(nil); err == nil {
httpClient.Jar = jar
}

如此,做 Service Unit Test 時,在發送 HTTP GET request or HTTP HEAD request 時,可以停下來,看看要跳轉到哪裡,以此判斷跳轉機制是否正常。

接著,碰到了另一個問題: 在 follow URL Redirect 後,似乎跳轉過程中產生的 Cookie 都沒有被記錄下來?例如最後的 response.Cookies() 輸出,的確只列出最後的 Response Cookies 資料。這時想要驗證中間的 Cookie 資訊,則需要瀏覽 httpClient.Jar 資料:

for _, c := range(httpClient.Jar.Cookies(res.Request.URL)) {
fmt.Println(c)
}

如此就可以搞定 URL Redirect 驗證,以及全部過程的產生的 Cookie 檢查!當然,若要更細膩地去追蹤每次 URL Redirect 時,產生的 Response Cookies 資料,可以透過 httpClient.CheckRedirect 那處理:

httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
for _, c := range (req.Response.Cookies()) {
fmt.Println(c)
}
}

參考資料:
  • https://pkg.go.dev/net/http#Client
  • https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/net/http/client.go
  • https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/net/http/client.go;l=493
  • https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/net/http/client.go;l=811
  • https://pkg.go.dev/net/http/cookiejar#Jar.Cookies
  • https://cs.opensource.google/go/go/+/refs/tags/go1.18.3:src/net/http/cookiejar/jar.go

2022年6月21日 星期二

VIM 設定檔(vimrc)切換方式 @ macOS 12.4

由於 coding style 的規劃,需要調整 vim editor 的行為:

set tabstop=4
set shiftwidth=4
set expandtab

因此,設計一個 vim_env.sh 來做切換啟用:

% vim --version
...
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/share/vim"

% cat project_vimrc 
try
    source $VIM/vimrc 
catch
    echo "\$VIM/vimrc not found"
endtry

set tabstop=4
set shiftwidth=4
set expandtab

% cat vim_env.sh
#!/bin/bash

SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )";
alias vim='vim -u $SCRIPT_DIR/project_vimrc'
echo "Update vim environment (using 'type vim' to show raw command) "

% type vim
vim is an alias for vim -u $SCRIPT_DIR/project_vimrc

接著,就靠 alias 來啟用專案 vimrc

2022年6月19日 星期日

隔離險理賠 - 富邦疫苗隔離險理賠郵寄申請 時程約30天才開始審核


四月就被隔離了,恰好 110 年打疫苗前,保了個疫苗險,原本只是單純保個疫苗不良事件,殊不知翻出來看有隔離補償。找了個時間打電話問問看申辦流程,客服要求留完資料後,會有專人聯繫,可惜過了兩個月也沒接到過電話,現在疫情放緩,來把資料郵寄過去試試。

首先,先到 富邦產險 - 防疫險專區 網站,查一下理賠申請方式,內容都是建議,直接攜帶好相關證件直接到現場辦理。先來試試看郵件這招。

致電富邦產險客服(免付費電話,手機可打 0800-009-888 ),確認一下郵寄收件的切確地址跟收件人,於是得知台北地區就直接掛號寄到總公司即可。

地址:台北市中山區遼寧街179號7樓
電話:(02)66367890
富邦壽險 個人理賠部 收

至於文件方面,就下載一份理賠申請單填寫一下,再將身分證影本, 銀行帳戶影本和隔離簡訊列上,有順便把當初衛福部的隔離單印一下(六月下旬,點擊原本的簡訊,已經看不到帶有個人資訊的網頁內容),再看看是不是這樣就搞定。

後續大概寄出 20天後,突然想到查了一下,果真有一些進度,不錯,至少可以信件溝通了:



約30天後,收到簡訊通知,顯示開始審核:


最後,送件滿 3個月後,收到匯款通知。

參考資料: