2019年4月16日 星期二

關於使用PHP語法設定line的圖文選單(rich menu)筆記

之前研究line的圖文選單遇到幾個難題,所以特別留了一些筆記
文件可以參考 https://developers.line.biz/en/docs/messaging-api/using-rich-menus/

1.上傳圖文選單
根據文件上面的Upload the rich menu image章節使用curl的語法大概是這樣

curl -v -X POST https://api.line.me/v2/bot/richmenu/{richMenuId}/content \
-H "Authorization: Bearer {channel access token}" \
-H "Content-Type: image/jpeg" \
-T image.jpg

「-H」可以知道是header,在PHP可以透過CURLOPT_HTTPHEADER代入。
偏偏那個「-T」在curl_setopt的函式中完全沒有對應的參數可以使用。
在網站上很多透過post上傳檔案的方法都是使用CURLOPT_POSTFIELDS參數來模擬表單的方式來上傳並,例如設訂一個field為file,然後把檔案實體位置代進去,但是在line api上傳選單圖片的方式用此方法是行不通的,還會回報Unsupported media type(不支援媒體格式)。
雖然有人在 https://github.com/line/demo-rich-menu-bot/issues/5 有詢問這個問題,但完全沒人回答。
如果進一步去看文件的話,可以發現request body所放的資料應該是圖片內容,而CURLOPT_POSTFIELDS也可以做為設定request body使用,不一定要放入表單資訊。另外圖片大小可以放在標頭的Content-Length之中,這樣一來就會變成。

$image = "圖文選單圖片的真實路徑";
$richMenuId = "你的圖文選單ID";
$accessToken = "你的圖文選單Channel access token";
$headers = array(
    "Authorization: Bearer ". $accessToken,
    "Content-Type: image/jpeg",
    "Content-Length: ". filesize($image);
)
curl_setopt($ch,CURLOPT_URL, "https://api.line.me/v2/bot/richmenu/$richMenuId/content");
curl_setopt($ch,CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS, file_get_contents($image));
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);



檔案內容可以透過file_get_contents來取得。

2.設定預設的圖文選單

根據文件上面的Set the default rich menu章節使用curl的語法大概是這樣
curl -v -X POST https://api.line.me/v2/bot/user/all/richmenu/{richMenuId} \
-H "Authorization: Bearer {channel access token}"

做法不難,只要在網址放上richMenuId並在header上加上Authorization即可,但是問題出在使用上面的語法可能一直回傳bad request錯誤,又找不到錯誤是錯在哪裡。
(參考https://medium.com/@augustus0818/line-bot-rich-menu-aa5fa67ac6ae 章節3.3)

其實在 https://github.com/line/line-platform-feedback/issues/73 的文章中,也有人提到這個問題,關鍵在於要補上 「-d ''」就可以順利運作了,不會有bad request的問題。
這意味著,當你傳送POST來設定圖文選單時,必須要有request body,但因為不需要使用request body傳額外的資料,所以就直接放空字串就好了。

而在PHP語法中,除了設定CURLOPT_URL、CURLOPT_POST及CURLOPT_HTTPHEADER外,別忘了還要加入
curl_setopt($ch,CURLOPT_POSTFIELDS, "");