【ITニュース解説】Handle Telegram Callback Queries in PHP Without Truncating Inline Keyboard Payloads
2026年10月24日に「Dev.to」が公開したITニュース「Handle Telegram Callback Queries in PHP Without Truncating Inline Keyboard Payloads」について初心者にもわかりやすく解説しています。
ITニュース概要
Telegramボットのインラインキーボード作成では、ボタンデータが64バイトを超えるとエラーに。ボタン押下後、すぐに「処理中」と応答しないと読み込み中が続く。本記事は、PHPでデータ形式を短縮し、ボタン押下時に素早く応答しメッセージを更新する堅牢なボット開発手法を解説する。
ITニュース解説
Telegramのボット開発において、ユーザーがメッセージに表示されたボタンを押して操作を進める「インラインキーボード」は、注文管理やサポートチケットのルーティングなど、多段階の複雑なワークフローを構築するために非常に重要な機能である。しかし、このインラインキーボードを適切に実装しないと、予期せぬ問題に直面することが少なくない。システムエンジニアを目指す初心者がこれらの落とし穴を避け、堅牢なボットを開発するためのポイントを解説する。
最も頻繁に発生する問題の一つは、「callback_data」というパラメータに設定できるデータのサイズ制限である。これは、ユーザーがインラインキーボードのボタンをクリックしたときにボットに送られる情報で、どのボタンが押されたか、そしてそれに関連するアクションやデータを示すために使われる。Telegram Bot APIでは、このcallback_dataのサイズが64バイトに制限されている。もし開発者がこの制限を超えて、例えばJSON形式のオブジェクトや長いID、詳細なアクション文字列などをそのままボタンに格納しようとすると、Telegramはキーボードの生成自体をサイレントに拒否したり、APIエラーを返したりする。結果として、ユーザーにはボタンが表示されなかったり、ボットが正しく動作しなかったりする原因となる。特に、IDの長さが可変の場合、予期せぬタイミングでシステムが停止する可能性もある。
もう一つの重要な問題は、ユーザーがボタンをクリックした後の動作に関するものである。ユーザーがボタンを押すと、Telegramはボットのサーバーに「callback_query」という更新情報(Webhook)を送る。この情報を受け取ったボットのサーバーは、ビジネスロジック(例えばデータベースの更新や外部APIの呼び出し)を実行する前に、Telegramに対して「answerCallbackQuery」というAPIメソッドを呼び出して、「問い合わせを受け取った」という応答を即座に返す必要がある。もしこの応答が遅れると、ユーザーのTelegramクライアントには、押されたボタンの上に無限に回転するローディングスピナーが表示され続け、約10秒後にネットワークタイムアウトのエラーが表示される。サーバー側で処理が正常に完了したとしても、ユーザー体験は著しく損なわれることになる。
これらの問題を解決し、堅牢なTelegramボットを構築するためには、いくつかの対策が必要である。一つは、Telegram APIと安全に通信できるクライアントを構築すること。二つ目は、callback_dataの64バイト制限を遵守するためのコンパクトなデータ形式を設計すること。そして三つ目は、Webhookで受け取ったコールバッククエリを適切に処理するハンドラを実装することである。
まず、安全なTelegram APIクライアントの構築について説明する。PHPでTelegram APIと通信する際に、file_get_contentsのような基本的な関数に頼るべきではない。これらの関数は、APIからのエラー応答(例えば「リクエストが多すぎる」を示すHTTP 429エラーや、「不正なリクエスト」を示すHTTP 400エラー)を適切に処理できないため、詳細なエラー情報を取得することが難しい。代わりに、PHPのcURL拡張機能を利用して、専用のAPIクライアント関数を作成することを推奨する。この関数では、通信のタイムアウト設定、HTTPレスポンスコードの検証、応答JSONの構造検証、そしてTelegram APIが返すokという真偽値フラグのチェックなどを行う。これにより、ネットワークエラーやAPI側の問題が発生した場合でも、明確な例外をスローして開発者が対処できるようにする。例えば、指定されたボットトークンとメソッド、ペイロード(データ)を受け取り、それらをHTTP POSTリクエストとしてTelegram APIに送信し、正常な応答が200 OKであること、JSONが正しくパースできること、そして応答に含まれるokフラグが真であることを確認する処理を実装する。これにより、API通信の信頼性が大幅に向上する。
次に、callback_dataを64バイト未満に保つためのコンパクトなペイロード形式の設計方法である。冗長なキーと値のペアを使うのではなく、アクションを短いコードにマッピングする方式を採用する。例えば、「承認」を意味するapprove_orderのような長い文字列ではなく、appのように短縮する。さらに、具体的なコンテキスト情報(例えば注文ID、管理者IDなど)を直接callback_dataに含める代わりに、ランダムな一意のキーを生成し(例:14文字の16進数文字列)、そのキーをデータベースやRedisなどの永続ストレージに保存された詳細な情報と関連付ける。そして、callback_dataにはこの短いアクションコードと生成したキーだけを含める(例:app:f83a21b03e21a4)。この方法により、callback_dataの長さは常に一定(約18〜20バイト)に保たれ、関連するビジネスロジックの複雑さやデータの量に依存しない。例えば、リード情報を処理するメッセージを送信する際には、リードIDを直接含む形式(例:app:ld_98234)でも、その合計バイト数が64バイト制限内に収まるように設計する。また、HTML形式でメッセージを送信する場合は、ユーザーが入力したデータやデータベースから取得したデータがHTMLの特殊文字(<や>など)を含まないよう、htmlspecialchars()関数などで適切にエスケープ処理を行うことも重要である。これにより、Telegramがメッセージを正しく解釈し、APIエラーを防ぐことができる。
最後に、Webhookでのイベント処理とメッセージ更新の方法である。ユーザーがインラインボタンをタップすると、ボットのWebhookエンドポイントにcallback_queryオブジェクトを含む更新ペイロードがPOSTリクエストとして送信される。このリクエストを受信したら、次の3つのステップを順番に実行する必要がある。まず、受信したWebhookリクエストが正当なものかを確認するため、Telegramが送信する秘密トークンヘッダー(X-Telegram-Bot-Webhook-Secret-Token)と、サーバーが事前に設定した秘密トークンが一致するかを検証する。これにより、不正なリクエストを拒否できる。次に、先述の通り、callback_queryに含まれるidを使用してanswerCallbackQueryを即座に呼び出す。この際、ユーザーに表示する短い通知メッセージ(トーストポップアップ)を指定することもできるが、スピナーを消すことが最優先である。この呼び出しによって、ユーザーの画面に表示されていたロードスピナーがすぐに消え、ユーザーはボットが応答していることを確認できる。最後に、ビジネスロジック(例えば、リードの承認、拒否、保留といった処理をデータベースに記録する)を実行し、その結果に基づいて、editMessageTextメソッドを呼び出して元のメッセージの内容を更新する。この更新では、ボタンの表示を削除したり、テキストを「承認済み」などの状態を示すものに変更したりする。キーボードを削除するには、reply_markupパラメータに空のインラインキーボードの配列を設定すればよい。これにより、ユーザーはすでに操作が完了したことを視覚的に確認でき、誤って再度ボタンを押すことを防ぐことができる。
本番環境で運用する際には、いくつかのエッジケースにも注意が必要である。例えば、editMessageTextを呼び出す際に、更新しようとするテキストやキーボードの内容が、現在のメッセージと完全に同じ場合、Telegramは「Bad Request: message is not modified」というHTTP 400エラーを返すことがある。このようなエラーは、特別な問題ではないため、特定の文字列を含むエラーを捕捉し、抑制するような例外ハンドリングを実装することが望ましい。また、より複雑な状態管理が必要な場合は、前述のように、ステップ番号、フィルターフラグ、レコード識別子などの実行時引数をRedisのような外部ストレージに保存し、ボタンのペイロードにはそのストレージを参照するための短いキーだけを含める方法が有効である。さらに、Webhookは稀に同じ更新情報を複数回送信してくることがあるため、データベースの更新や支払いの記録など、一度しか実行されてはならない重要なビジネスロジックを処理する際は、受け取ったupdate_idをデータベースに記録し、すでに処理済みの更新であれば再度実行しない「冪等性(Idempotency)」を確保する仕組みを導入することが信頼性の高いシステムには不可欠である。
これらの実践的な知識とテクニックを習得することで、システムエンジニアを目指す初心者は、Telegram Bot APIの潜在的な制約を克服し、ユーザーにとって快適で信頼性の高いインタラクティブなボットアプリケーションを開発できるようになる。