ربات API تلگرام چگونه کار می‌کند؟

اگه با تلگرام کار کرده باشید، قطعا سر و کارتون با ربات‌های تلگرامی جورواجور و مختلف افتاده و شاید حین استفاده از اون‌ها به این فکر فرو رفته باشید که این ربات‌ها چطوری کار می‌کنن؟

توی این مقاله قصد داریم به صورت فنی پاسخ این سوال رو بدیم و به صورت جزئی‌تری API تلگرام رو توضیح بدیم.


آدرس وب‌سرویس تلگرام

قبل از هرچیز برای داشتن یک ربات باید به BotFather رفته و یک ربات برای خودمون ایجاد کنیم.

پس از ایجاد ربات در BotFather، ما یک token در اختیار داریم که حکم شناسنامه‌ی ربات ما در تبادل اطلاعات با تلگرام رو داره. پس باید خیلی مراقب باشیم تا این توکن محفوظ بمونه و در اختیار کسی قرار نگیره.

تمام درخواست‌های ارسالی به تلگرام به آدرسی با فرمت زیر ارسال میشه:

https://api.telegram.org/bot<TOKEN>/Method

به جای <TOKEN> مشخص شده در بالا، همون توکنی که از بات‌فادر دریافت کردیم قرار می‌گیره.

در مورد Method نیز، همونطور که از اسمش پیداست مشخص کننده‌ی نوع درخواستی میشه که مد نظر ما هست. به عنوان مثال اگه قصد داریم پیامی ارسال کنیم، Method باید برابر با sendMessage باشه، و یا اگه نیاز به ارسال عکس با ربات داریم باید از متد sendPhoto استفاده کنیم.

یک مثال واقعی از آدرسی که برای ارسال پیام با ربات باید از اون استفاده کنیم:

https://api.telegram.org/bot794746520:AAEFsSLepmGE-un1h6uB3tuc-ltYlLdbsBA/sendMessage

ارسال درخواست (request) به تلگرام

باید توجه داشته باشیم، آدرسی که در بالا گفتیم صرفا فقط یک آدرس URL هست که باید درخواستمون رو بهش ارسال کنیم. پس قطعا پارامترهایی در کار هست که باید اون پارامترها به این آدرس ارسال بشن تا در نهایت پیام مد نظر از ربات به کاربر ارسال بشه. برای متد sendMessage (هنگامی که این مقاله تایپ شده) ۹ پارامتر مختلف وجود داره که همگی بخشی از تنظیمات پیام ارسالی رو مشخص می‌کنند. این پارامترها مشخص می‌کنند:

  • پبام مورد نظر به چه کسی ارسال بشه؟
  • متن پیام چی باشه؟
  • پیام ارسالی به چه پیامی ریپلای شده باشه؟
  • کیبورد همراه با پیام چی باشه؟
  • آیا با ارسال پیام، به کاربر نوتیفیکیشن ارسال بشه؟
  • آیا در صورت وجود آدرس‌های اینترنتی در پیام، پیش‌نمایش اون‌ها در زیر پیام نشون داده بشه؟
  • و …

هر کدوم از پارامتر‌ها یک اسم مختص به خود دارند. مثلا مورد اول در مثال بالا، پارامتر chat_id و مثال دوم پارامتر text هست.

همچنین باید توجه داشته باشیم تعدادی از این پارامترها اجباری هستند، یعنی باید حتما مقداردهی بشن (برای متد sendMessage پارامترهای chat_id و text اجباری هستند) و تعدادی از پارامترها هم اختیاری هستند، یعنی لزومی نداره حتما مقداردهی شده باشند (مثلا پارامتر reply_markup مربوط به ارسال کیبورد همراه با پیام هست، که اگه مقداردهی شده باشه همراه با پیام کیبورد هم ارسال میشه و در غیر این صورت پیام بدون کیبورد ارسال میشه)

تلگرام به صورت کامل در مورد هر متد توضیح داده و پارامترهای مربوط به هر متد به همراه توضیحات کافی در موردشون رو در اختیار ما قرار داده. عکس زیر بخشی از توضیحات مربوط به متد sendMessage هست.

توضیحات متد sendMessage در وب‌سایت تلگرام

همون‌طور که در تصویر مشخص هست، تلگرام ابتدا یک توضیح کوتاه در مورد متد مربوطه داده و سپس پارامترهای مربوط به متد رو به ما معرفی کرده و همچنین برای هر پارامتر مشخص کرده:

  • جنس پارامتر چی هست (Type)
  • پارامتر اختیاری هست یا اجباری (Required)
  • کاربرد پارامتر چی هست (Description)

لیست کامل متدهای API تلگرام رو میشه در این صفحه مشاهده کرد.

حالا تا همین‌جای کار بهتره کدی به زبان PHP که یک درخواست ارسال پیام به تلگرام ارسال می‌کنه رو بررسی کنیم:

<?php

$data = [
    'chat_id' => 577710232,
    'text' => 'Hello World!'
];

$ch = curl_init('https://api.telegram.org/bot794746520:AAEFsSLepmGE-un1h6uB3tuc-ltYlLdbsBA/sendMessage');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$result = curl_exec($ch);
$result_array = json_decode($result, true);

echo json_encode($result_array, 448);

در این کد ابتدا دو پارامتر ضروری متد سند مسیج مقداردهی شدند.

پارامتر chat_id حاوی آیدی عددی منحصر به فرد چتی هست که قصد ارسال پیام به اونجا رو داریم. شاید براتون سوال باشه که من این آیدی عددی رو از کجا پیدا کردم و اصلا از کجا بدونیم آیدی عددی شخصی که قصد ارسال پیام به اون رو داریم چی هست؟ که در ادامه‌ی مقاله در موردش صحبت میشه.

پارامتر text هم حاوی متنی هست که قصد داریم ارسال بشه.

به صورت خلاصه این کد باعث میشه ربات یک پیام با متن Hello World به چتی که آیدی عددی مشخص شده ارسال کنه.

البته باید توجه داشته باشیم، اگر ربات:

  • به یک شخص پیام می‌فرسته، حتما اون شخص قبلا ربات رو استارت کرده باشه و بلاکش نکرده باشه
  • به یک گروه پیام میفرسته، حتما در گروه اضافه شده باشه (و دسترسی ارسال پیام داشته باشه)
  • در یک کانال پیام ارسال می‌کنه، حتما در کانال ادمین شده باشه (و دسترسی ارسال پیام داشته باشه)

پاسخ تلگرام به درخواست ارسالی

اگه نتیجه‌ی کدی که برای ارسال پیام نشون دادیم رو چاپ کنیم، به این خروجی می‌رسیم:

{
    "ok": true,
    "result": {
        "message_id": 16257,
        "from": {
            "id": 794746520,
            "is_bot": true,
            "first_name": "Test Bot",
            "username": "Test_Bot"
        },
        "chat": {
            "id": 577710232,
            "first_name": "Hadi",
            "last_name": "Moghadam",
            "username": "Hadiology",
            "type": "private"
        },
        "date": 1606205599,
        "text": "Hello World"
    }
}

می‌بینیم که پاسخ تلگرام به درخواست ما، یک خروجی در قالب JSON هست. این موضوع همواره صادق هست و تلگرام همیشه یک رشته JSON در خروجی به ما تحویل میده.

پارامتر ok همواره در خروجی تلگرام هست و مقدار true نشون‌دهنده‌ی موفق بودن انجام درخواست ما و مقدار false هم نشون‌دهنده‌ی وجود خطا در درخواست ارسالی ما هست.

طیف پاسخ تلگرام در واکنش به درخواست ما بسیار گسترده هست و میشه ده‌ها مثال از پاسخ‌های مختلف تلگرام در رابطه با نوع درخواست ما نشون داد، اما یک اصل در بحث ارسال هر نوع پیام (متنی، عکس، ویدیو، ویس، و …) به کاربر صادق هست:

در صورتی که ارسال پیام موفقیت‌آمیز باشه، تلگرام در پارامتر result اطلاعات پیام ارسال شده رو نشون میده

در خروجی بالا پارامتر های زیر رو داریم:

  • پارامتر message_id: آیدی عددی پیام ارسال شده رو نشون میده
  • پارامتر from: اطلاعات فرستنده‌ی پیام (که در اینجا ربات ما هست) رو نشون میده
  • پارامتر chat: اطلاعات چتی که پیام داخلش ارسال شده رو نشون میده
  • پارامتر date: زمان ارسال پیام رو نشون میده

تقریبا این پارامترها در همه‌ی پیام‌های ارسالی ثابت و یکسان هستن و میتونیم روی وجود اون‌ها در پاسخ‌های تلگرام به درخواست ارسال پیام از طرف ما حساب باز کنیم.

دریافت پیام‌های کاربر

تا اینجا یاد گرفتیم که چطور یک درخواست رو به تلگرام ارسال کنیم و روی متد sendMessage مانور بیشتری دادیم و ازش مثال‌هایی رو بررسی کردیم. اما یک سوال بزرگ که هنوز پاسخی بهش ندادیم باقی مونده:

چطور پیام‌های ارسالی کاربران به ربات رو دریافت کنیم؟

در ابتدای کار بهتره به جای استفاده از کلمه‌ی پیام از کلمه‌ی آپدیت استفاده کنیم، چون پیام‌ها فقط بخشی از آپدیت‌های تلگرام هستند و آپدیت‌های تلگرام میتونند موارد دیگه‌ای مثل موارد زیر رو هم شامل بشند:

  • پیام‌ها (پیام‌های متنی یا مدیا‌ها) – وقتی کاربر پیامی در چت ربات یا در گروه/کانالی که ربات حضور داره ارسال می‌کنه
  • callback query ها – وقتی کاربر روی دکمه‌های شیشه‌ای کیبوردی که ربات ایجاد کرده کلیک میکنه.
  • inline query ها – وقتی کاربر در پیامی ابتدا یوزرنیم ربات رو تایپ میکنه و بعد متنی رو می‌نویسه (مثل ربات @pic یا @gif که احتمالا باهاشون کار کردید)
  • و …

پس بهتره سوال بالا رو گسترش بدیم و این سوال و بپرسیم:

چطور آپدیت‌های مرتبط با رباتمون رو از تلگرام دریافت کنیم؟

تلگرام دو روش بسیار قدرتمند برای این کار ارائه داده که خودم بعد از ۳ سال کار با ربات‌های تلگرامی هنوز با فکر کردن به قدرت پنهان پشت این دو روش تعجب می‌کنم و تلگرام رو تحسین می‌کنم. در ادامه این دو روش رو با هم بررسی می‌کنیم.

۱) متد setWebhhook

یک راه تلگرام برای ارسال آپدیت‌ها به ربات، متد setWebhook هست. توی این متد ما قبل از این‌که برنامه‌نویسی رباتمون رو شروع کنیم، این متد رو فراخوانی می‌کنیم تا تنظیمات وبهوک انجام بشه و بعد شروع به برنامه‌نویسی ربات می‌کنیم.

در این متد، ما یک آدرس URL رو به تلگرام معرفی می‌کنیم و بهش می‌گیم اگه آپدیتی برای ربات داشتی، بی‌زحمت برای این آدرس URL ارسالش کن. با این کار اگر آپدیتی برای ربات ایجاد بشه، تلگرام اطلاعات مربوط به آپدیت رو برای آدرسی که مشخص کردیم در قالب فرمت JSON ارسال می‌کنه.

قوانین و شرایط متعددی در رابطه با این متد موجوده که در ادامه بررسیشون می‌کنیم:

  • آدرس اعلام شده به تلگرام حتما باید با پرتکل https باشه.
  • آدرس شما باید HTTP Response Code مناسبی نسبت به درخواست تلگرام داشته باشه، در صورتی که HTTP Response Code شما چیزی به جز ۲۰۰ باشه (مثل ۴۰۰، ۴۰۴، ۵۰۰، ۵۰۳ و سایر خطاهای موجود) تلگرام ارسال اون آپدیت رو ناموفق تلقی می‌کنه و مجددا ارسالش می‌کنه.
  • اگر آدرس شما به دفعات زیاد دچار خطا باشه و HTTP Response Code مناسبی در پاسخ به ریکوئست ارسالی تلگرام نداشته باشه (به عنوان مثال فرض کنید کد شما دچار یک خطای برنامه‌نویسی باشه و خطای ۵۰۰ به درخواست تلگرام جواب داده بشه، یا آدرسی که وارد کردید وجود نداشته باشه و خطای ۴۰۴ به تلگرام جواب داده بشه)، تلگرام از ارسال آپدیت‌های فعلی و بعدی به آدرس شما خودداری می‌کنه.
  • اگر آدرس URL شما بیش از ۱۵ – ۲۰ ثانیه در واکنش به request تلگرام لود بشه (مثلا حالتی رو فرض کنید که برنامه‌نویسی ربات شما به گونه‌ای هست که با دریافت نوعی آپدیت باید یک فایل سنگین رو از آدرسی دریافت و روی هاستتون ذخیره کنید و این عملیات بیشتر از ۱۵ – ۲۰ ثانیه طول بکشه و مشخصا درخواست تلگرام به آدرس شما هم به همین اندازه طول بکشه)، تلگرام کانکشن رو می‌بنده و مجدد request رو برای شما ارسال می‌کنه. در این جور مواقع اگه پیش‌بینی می‌کنید پردازش شما طولانی هست، باید طوری کدنویسیتون رو انجام بدید تا ابتدا به درخواست تلگرام هدر ۲۰۰ برگردونده بشه و بحث دریافت آپدیت کامل بشه و بعد اون آپدیت توسط شما پردازش بشه. اینطوری دیگه تلگرام معطل زمان پردازش شما نمیمونه و مشکلی پیش نمیاد.

در متد setWebhook چندین پارامتر برای تنظیم وجود داره که مهم‌ترین‌هاش در جدول زیر ذکر شدند.

پارامترتوضیحات
urlآدرس مورد نظر ما که قصد داریم آپدیت‌هامون رو در اون دریافت کنیم.
ip_addressآیپی سرور ما که دامنه‌مون بر روی اون سرور میزبانی میشه. عموما سیستم DNS تلگرام کمی کند هست و اگه از سروری به روی سرور دیگه‌ای مهاجرت کنیم، با این پارامتر می‌تونیم زودتر از این‌که تلگرام تغییرات آیپی سرور ما رو متوجه بشه، خودمون این تغییرات رو بهش اعلام کنیم.
max_connectionsحداکثر تعداد ریکوئست‌های همزمان که تلگرام اجازه داره برای شما ارسال کنه. فرض کنیم ربات ما در لحظه ۱۰۰ آپدیت از چت‌های مختلف دریافت می‌کنه، با این پارامتر میتونیم مشخص کنیم تلگرام در لحظه حداکثر چندتاشون رو برای ما ارسال کنه. مقدار پیش‌فرض این پارامتر ۴۰ هست و می‌تونه عددی بین ۱ تا ۱۰۰ باشه.
drop_pending_updatesاین پارامتر میتونه مقدار true یا false داشته باشه. گاهی اوقات ما تعدادی آپدیت در انتظار داریم که قصد داریم با تنظیم وبهوک، اون آپدیت‌های قدیمی در نظر گرفته نشن و برامون ارسال نشن. می‌تونیم با دادن مقدار true به این پارامتر این کار رو انجام بدیم.
allowed_updatesبا این پارامتر می‌تونیم مشخص کنیم که ربات ما چه نوع آپدیت‌هایی رو دریافت کنه. مثلا می‌تونیم براش مشخص کنیم فقط پیام‌ها یا مثلا callback_query ها (آپدیت‌های مربوط به کلیک کاربر روی دکمه‌های شیشه‌ای) دریافت بشن.
جدول پارامترهای متد setWebhook تلگرام

یک مثال به زبان PHP برای استفاده از متد setWebhook جهت تنظیم آدرس وبهوک رباتمون:

<?php

$data = [
    'url' => 'https://blog.farahost.net/bot/index.php',
    'max_connections' => 50,
];

$ch = curl_init('https://api.telegram.org/bot794746520:AAEFsSLepmGE-un1h6uB3tuc-ltYlLdbsBA/sendMessage');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$result = curl_exec($ch);
$result_array = json_decode($result, true);

echo json_encode($result_array, 448);

در صورت موفقیت‌آمیز بودن درخواست، تلگرام چنین ریسپانسی به درخواست ما داره:

{
    "ok": true,
    "result": true,
    "description": "Webhook was set"
}

حالا همه چیز برای دریافت آپدیت‌های تلگرام آماده هست. و لازمه برنامه‌نویسی لازم در هاست یا سروری که تهیه کردیم و وبهوک ربات رو بر روی آدرسش تنظیم کردیم انجام بدیم.

به عنوان مثال آدرس وبهوکی که قبل‌تر تنظیم کردیم برابر با https://blog.farahost.net/bot/index.php بود، پس باید به هاستی که از دامنه‌ی blog.farahost.net میزبانی می‌کنه وارد بشیم و یک پوشه‌ی bot ایجاد کرده و داخل اون پوشه فایل index.php رو ایجاد کنیم و برنامه‌نویسی خودمون برای دریافت و پردازش آپدیت‌های ارسالی تلگرام به اون رو انجام بدیم.

در کد زیر یک کد کاملا ساده نوشتیم تا در صورتی که برای ربات کلمه‌ی hello ارسال بشه، ربات در جواب پاسخ Hello there رو ارسال کنه.

<?php

$token = "794746520:AAEFsSLepmGE-un1h6uB3tuc-ltYlLdbsBA";

function tgRequest($method, $data = []){
    global $token;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot{$token}/{$method}");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    return json_decode(curl_exec($ch), true) ?: false;
}

$updates = json_decode(file_get_contents('php://input'), true);

if($updates['message']['text'] == 'hello')
    tgRequest('sendMessage', [
            'chat_id' => $updates['message']['chat']['id'],
            'text' => 'Hello there!'
        ]);

می‌بینیم که کدمون به درستی داره کار می‌کنه:

یک بار دیگه بیاید فرایندی که انجام میشه تا ربات پیام ما رو دریافت کنه و پاسخش رو ارسال کنه بررسی کنیم:

  1. پیام hello توسط ما در پیوی ربات ارسال میشه
  2. تلگرام تنظیمات وبهوک ربات رو بررسی میکنه تا ببینه وبهوک برای ربات تنظیم شده یا خیر
  3. وبهوک برای ربات تنظیم شده، پس تلگرام آپدیت مرتبط با پیامی که ارسال کردیم رو به URL تنظیم شده برای وبهوک ارسال می‌کنه
  4. این آپدیت توسط برنامه‌نویسی که داشتیم دریافت و در متغیر updates به صورت یک آرایه ذخیره میشه (خط ۱۴ کدنویسیمون)
  5. مقدار text آپدیت دریافت شده با if موجود در خط ۱۶ بررسی میشه و در صورتی که برابر با hello باشه دستورات مربوط به این شرط اجرا میشه
  6. تابع tgRequest که نوشتیم اجرا میشه و در نهایت با متد sendMessage یک پیام با متن Hello there به چتی که آپدیت ازش دریافت شده ارسال میشه

۲) متد getUpdates

تا اینجای این مقاله راه اندازی یک ربات تلگرام با متد setWebhook رو بررسی کردیم و باهاش آشنا شدیم.

اما باید بدونیم در کنار متد قدرتمند setWebhook، یک متد دیگه با نام getUpdates داریم که کاملا ساز و کار مختلفی با متد قبل داره و به نحو دیگه‌ای کار می‌کنه.

در این متد، ما هیچ وبهوکی برای ربات تعریف نمی‌کنیم و در صورتی که آپدیتی برای ربات ایجاد بشه، تلگرام اصلا اون رو برای ما ارسال نمی‌کنه، بلکه ما خودمون باید اون رو از تلگرام دریافت کنیم!
فرض کنید در حال استفاده از متد getUpdates هستیم و برای ربات یک پیام ارسال می‌کنیم، این پیام در سرورهای تلگرام ذخیره میمونه و ما خودمون باید با ارسال درخواست این آپدیت رو دریافت کنیم.

شاید براتون سوال پیش بیاد که چطور بفهمیم کی باید آپدیت رو از تلگرام دریافت کنیم؟ پاسخ ساده‌ست: همیشه!
بله، همیشه! ما باید به طور مداوم به تلگرام reuqest ارسال کنیم و درخواست دریافت آپدیت‌های موجود رو داشته باشیم؛ هر وقت تلگرام در جواب request ارسال شده‌ی ما آپدیتی داشت و ارائه کرد، اون آپدیت رو دریافت و پردازش کنیم.

در متد getUpdates نیز ما چند پارامتر داریم که اون ها رو به صورت اجمالی بررسی می‌کنیم:

پارامترتوضیحات
offsetمشخصه‌ای برای تنظیم کردن ردیف آپدیت دریافتی (در موردش صحبت می‌کنیم)
limitمحدود کردن حداکثر تعداد آپدیت‌های دریافتی از تلگرام، فرضا اگه مقدار این متغیر برابر با ۴۰ باشه و ۳۰۰ آپدیت پردازش نشده برای ربات وجود داشته باشه، تلگرام فقط ۴۰ آپدیت اول رو در جواب درخواست ما پاسخ میده.
allowed_updatesمشخص کردن نوع آپدیت‌های مجاز دریافتی (لیست انواع آپدیت‌ها در تلگرام)
جدول پارامترهای متد getUpdates تلگرام

حال قصد داریم به صورت عملی از این متد برای دریافت آپدیت‌ها از تلگرام و پردازششون استفاده کنیم.
نکته‌ی مهم این هست اگر قرار هست متد getUpdates رو فراخوانی کنیم، باید آدرس وبهوکی برای ربات تنظیم نشده باشه. در صورتی که وبهوک برای ربات تنظیم شده، با فراخوانی متد deleteWebhook حذف خواهد شد.

فرض کنید ما برای ربات یک عکس و یک پیام ارسال کردیم:

همون طور که گفتیم، تلگرام آپدیت مربوط به این پیام و عکس ارسال شده رو جایی ارسال نمی‌کنه و فقط این دو آپدیت در سرورهای تلگرام ذخیره هست و هرموقع که ما از متد getUpdates استفاده کنیم، این دو آپدیت نمایش داده خواهد شد. به کد زیر دقت کنید:

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot794746520:AAEFsSLepmGE-un1h6uB3tuc-ltYlLdbsBA/getUpdates");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = json_decode(curl_exec($ch), true);

echo json_encode($result, 448);

به خروجی دقت کنید:

{
    "ok": true,
    "result": [
        {
            "update_id": 957509236,
            "message": {
                "message_id": 261,
                "from": {
                    "id": 577710232,
                    "is_bot": false,
                    "first_name": "Hadi",
                    "last_name": "Moghadam",
                    "username": "Hadiology",
                    "language_code": "en"
                },
                "chat": {
                    "id": 577710232,
                    "first_name": "Hadi",
                    "last_name": "Moghadam",
                    "username": "Hadiology",
                    "type": "private"
                },
                "date": 1619441653,
                "text": "It's a sample message"
            }
        },
        {
            "update_id": 957509237,
            "message": {
                "message_id": 262,
                "from": {
                    "id": 577710232,
                    "is_bot": false,
                    "first_name": "Hadi",
                    "last_name": "Moghadam",
                    "username": "Hadiology",
                    "language_code": "en"
                },
                "chat": {
                    "id": 577710232,
                    "first_name": "Hadi",
                    "last_name": "Moghadam",
                    "username": "Hadiology",
                    "type": "private"
                },
                "date": 1619441702,
                "photo": [
                    {
                        "file_id": "AgACAgQAAxkBAAIBBmCGuCajXyXw0xJiIXNWcqS78ftxAAJptTEbYjA5ULQR03YZlQTHG6OAJ10AAwEAAwIAA20AAxuLBwABHwQ",
                        "file_unique_id": "AQADG6OAJ10AAxuLBwAB",
                        "file_size": 19154,
                        "width": 320,
                        "height": 214
                    },
                    {
                        "file_id": "AgACAgQAAxkBAAIBBmCGuCajXyXw0xJiIXNWcqS78ftxAAJptTEbYjA5ULQR03YZlQTHG6OAJ10AAwEAAwIAA3gAAx2LBwABHwQ",
                        "file_unique_id": "AQADG6OAJ10AAx2LBwAB",
                        "file_size": 98159,
                        "width": 800,
                        "height": 534
                    },
                    {
                        "file_id": "AgACAgQAAxkBAAIBBmCGuCajXyXw0xJiIXNWcqS78ftxAAJptTEbYjA5ULQR03YZlQTHG6OAJ10AAwEAAwIAA3kAAxyLBwABHwQ",
                        "file_unique_id": "AQADG6OAJ10AAxyLBwAB",
                        "file_size": 145328,
                        "width": 1024,
                        "height": 683
                    }
                ]
            }
        }
    ]
}

می‌بینیم که تلگرام در result فرمت JSON خروجی، آرایه‌ای از هر دو آپدیت پردازش نشده رو در اختیار ما قرار داده که اولین آپدیت مربوط به پیام ارسال شده و دومین پیام مربوط به عکس ارسال شده هست.

حال قصد داریم مشابه کدی که برای متد setWebhook نوشتیم، برای متد getUpdates هم بنویسیم.
یعنی کدی بنویسیم که که با متد getUpdates کار کنه و در صورتی که ما برای ربات پیام hello ارسال کردیم، ربات در جواب Hello there رو ارسال کنه. به کد زیر دقت کنید:

<?php

$token = "794746520:AAEFsSLepmGE-un1h6uB3tuc-ltYlLdbsBA";

function tgRequest($method, $data = []){
    global $token;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot{$token}/{$method}");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    return json_decode(curl_exec($ch), true) ?: false;
}

function getUpdates(){
    return tgRequest('getUpdates')['result'];
}

$updates = getUpdates();

foreach($updates as $update){
    if($update['message']['text'] == 'hello')
        tgRequest('sendMessage', [
                'chat_id' => $update['message']['chat']['id'],
                'text' => 'Hello there!'
            ]);
}

در این کد ما در تابع getUpdates (خط ۱۴) به کمک تابع tgRequest متد getUpdates رو فراخوانی می‌کنیم و خروجی رو برمی‌گردونیم.
سپس با حلقه‌ی foreach هر آپدیت را یکی یکی بررسی می‌کنیم.
با توجه به if خط ۲۱، در صورتی که ما برای ربات پیام hello ارسال کنیم به ما پاسخ میده، پس برای دو پیام قبلی ما با توجه به کدی که زدیم ربات عکس‌العملی نخواهد داشت.
پس یک پیام hello برای ربات ارسال می‌کنیم و سپس یک‌بار اسکریپت بالا رو اجرا می‌کنیم، نتیجه به این شکل هست:

اما یک نکته‌ی مهم
اگر ما مجدد اسکریپت رو اجرا کنیم، دوباره ربات به ما همین پیام رو ارسال می‌کنه!

در واقع در حالت پیش‌فرض تلگرام آپدیتی که یکبار ازش دریافت کردیم رو حذف نمی‌کنه و توی درخواست‌های بعدی باز هم اون رو در اختیار ما می‌ذاره!
شاید فکر کنید این مشکل از سمت تلگرامه، اما این یک قابلیت بسیار خوب هست برای شرایطی که سرور یا هاست شما دچار اختلال باشه، آپدیت رو دریافت کنه اما نتونه پردازشش کنه. این آپدیت‌ها حذف نخواهند شد و دوباره با ارسال ریکوئست در اختیارتون قرار می‌گیره.
حال برای این که وقتی آپدیتی رو دریافت کردیم، در درخواست بعدی دیگه دریافتش نکنیم، باید از پارامتر offset در متد getUpdates استفاده کنیم.
پس باید در کد قبلی تغییراتی اعمال کنیم که به ترتیب ذکرشون می‌کنیم:

  1. تابع getUpdates رو ویرایش می‌کنیم تا امکان تنظیم کردن offset رو داخلش داشته باشیم.
  2. از یک حلقه‌ی while – true استفاده می‌کنیم تا با یک بار اجرای اسکریپت، این حلقه به صورت مادام اجرا بشه و یکسره در حال دریافت آپدیت از تلگرام باشه.
  3. هر آپدیت دارای یک update_id هست، هر بار که متد getUpdates رو فراخوانی می‌کنیم، باید offset رو برابر با عددی که یک واحد از update_id آخرین آپدیت بزرگتر هست تنظیم کنیم، تا به تلگرام بگیم آپدیت‌هایی که update_id کمتر از این offset رو دارند، دیگه نمایش داده نشند.
<?php

$token = "794746520:AAEFsSLepmGE-un1h6uB3tuc-ltYlLdbsBA";

function tgRequest($method, $data = []){
    global $token;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://api.telegram.org/bot{$token}/{$method}");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    return json_decode(curl_exec($ch), true) ?: false;
}

function getUpdates($offset = 0){
    return tgRequest('getUpdates', ['offset' => $offset])['result'];
}

$updates = [];

while(true){
    
    $updates = getUpdates(end($updates)['update_id'] + 1);
    
    foreach($updates as $update){
        if($update['message']['text'] == 'hello')
            tgRequest('sendMessage', [
                    'chat_id' => $update['message']['chat']['id'],
                    'text' => 'Hello there!'
                ]);
    }
}

سخن آخر

در این مقاله قصد داشتیم به طور فنی و با کمک PHP، کلیت API تلگرام و ارتباط گرفتن با اون جهت راه‌اندازی یک ربات تلگرامی رو بررسی کنیم.
امیدوارم از خوندن این مقاله استفاده‌ی مورد انتظارتون رو کرده باشید.

هادی مقدم

سلام، من هادی‌ام! دانشجوی کارشناسی مهندسی برق در دانشگاه فردوسی مشهد و برنامه‌نویس زبان‌های PHP ، C و B4A هستم. عاشق نوشتن و آموزش هرچیزی به دیگران هستم و خوشحالم که در بلاگ فراهاست با آموزش‌های متفاوت از دنیای اینترنت در خدمتتون هستم.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا
بستن