Sokan Academy

ساخت ربات telegram - قسمت نهم - ساخت دیتابیس و شمارشگر پیام های کاربر

ساخت ربات telegram - قسمت نهم - ساخت دیتابیس و شمارشگر پیام های کاربر

در قسمت های قبل به طور کامل با نحوه کدنویسی ربات آشنا شدیم ، حال وقت آن است که یک رباتی طراحی کنیم که قابلیت ذخیره اطلاعات را داشته باشد ، ابتدا باید نحوه کار با دیتابیس را فرا بگیرید (سرور مجازی که پیشنهاد می کنیم xamp است) ، بعد از فرا گرفتن کار با پایگاه داده سپس به تحقق ربات شمارش پیام کاربرمی پردازیم ، سناریوی ربات ما به این طریق است که کاربر پس از استارت ، ربات چت ای دی کاربر را در دیتابیس ذخیره کرده و هر بار پس از ارسال پیام بوسیله کاربر پیغام کاربر همراه با تعداد پیام های کاربر به ادمین ربات ارسال می شود.

فاز اول - کار با پایگاه داده :

- در این قسمت قصد آموزش کامل دیتابیس را نداریم ، فقط تا قسمتی آموزش خواهیم داد که مورد نیاز باشد ؛ ابتدا xamp را نصب کرده و سپس در منوی باز شده سرویس های MySQL و Apache را استارت کنید ، بعد از این مرحله ، مرورگر خود را باز کرده و در قسمت url ، آدرس زیر را وارد می کنید :

http://localhost/phpmyadmin/

- بعد از وارد کردن آدرس بالا اگر سرویس های گفته شده در حال اجرا باشند ، مرورگر شما صفحه ای را به شما نشان خواهد داد که در سمت چپ بالا ؛ phpMyAdmin نوشته شده واین پنجره دارای آپشن های زیادی است ، شاید در نگاه اول کمی گیج کننده بیاید ولی اصلا نگران نباشید شما قرار نیست از تمام آپشن های نشان داده شده استفاده کنید ، در قسمت سمت راست تب بالا چندین گزینه مانند زیر دارد :

+----------+-----+--------+---------------+--------+--------+----
| Database | SQL | Status | User accounts | Export | Import | ...
+----------+-----+--------+---------------+--------+--------+----

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

CREATE DATABASE signbot

- دستورات کار با دیتابیس را کوئری می نامند و خط بالا نیز یک کوئری نامیده می شود ، با استفاده از این کوئری می توانید یک دیتابیس بنام signbot را در سرور خود بسازید اما دیتابیس به تنهایی فایده ای برای شما ندارد بلکه باید دارای جدول (Table) و فیلد (Field) نیز باشد ، هردیتابیس میتواند به میزان حافظه دیسک سرور شما دارای بی نهایت جدول و هر جدول می تواند بسته به تنظیمات سرور دارای بی نهایت فیلد باشد.

- با اجرای کوئری بالا بوسیله دکمه Go ، دیتابیسی جدید در سمت چپ مرورگر ، در لیست دیتابیس ها ایجاد شده ، آن را انتخاب کرده (دراینجا نام دیتابیس ما signbot است) ، با انتخاب دیتابیس منویی شبیه زیر به شما نشان داده می شود :

+-----------+-----+--------+-------+--------+--------+----
| Structure | SQL | Search | Query | Export | Import | ...
+-----------+-----+--------+-------+--------+--------+----

- از منوی بالا ، گزینه SQL را انتخاب کنید و در پنجره باز شده کوئری زیر را بنویسید :

CREATE TABLE user_data (
  _chatId char(12) NOT NULL,
  _countMsg int(11) NOT NULL
)

- با اجرای این کوئری می توانید یک جدول ایجاد کنید که دارای دو فیلد است ، همانطور که واضح است برای ایجاد یک جدول باید در قسمت SQL ، کوئری CREATE TABLE را بنویسید که پارامتر بعدی نام جدول است و این کوئری دارای body است به این معنی که مانند بالا بعد از نام جدول یک پرانتز باز شده و فیلد های مورد نیاز در آن گنجانده شده و بعد پرانتز بسته شده ، در این کوئری ما یک فیلد به نام chatId_ داریم که از نوع کاراکتر و مقدار مجاز آن 12 کاراکتر است و نمیتواند خالی باشد ، همچنین فیلد دیگری به نام countMsg_ که از نوع عدد با مقدار مجاز 11 کاراکتر و مانند فیلد قبلی نمی تواند مقدار تهی داشته باشد.

- اما در دیتابیس ما یک مشکل اساسی وجود دارد و آن هم این است که ممکن است در وارد کردن اطلاعات ، اطلاعات تکراری هم وارد شوند به عنوان مثال دو chatId یکسان در دو ردیف وجود داشته باشد ، برای حل این مشکل ما باید فیلد chatId_ را منحصر به فرد کنیم ، برای این منظور می توانیم از کوئری زیر استفاده کنیم که مقدار فیلد مذکور را یکه ، منحصر به فرد و تبدیل به کلید خارجی میکنند (برای درک مفهوم کلید خارجی می توانید به مقالات همین نویسنده در آینده مراجعه کنید) :

ALTER TABLE user_data
  ADD PRIMARY KEY (_chatId);

- همانطور که ملاحظه می کنید این کوئری گوینده این است که در جدول user_data یک فیلد را تبدیل به کلید خارجی کن که نام آن chatId_ است.

- تا اینجا فاز اول به پایان رسید ، برای این که بتوانید از دیتابیس در ربات خود استفاده کنید باید دیتابیس را در دیتابیس آنلاین ایمپورت (Import) کنید و جهت ایمپورت کردن فقط لازم است از این دیتابیس یک خروجی با فرمت SQL ، با استفاده از گزینه Export در تب گزینه ها بگیرید ، حال وارد فاز دوم می شویم که ربات می تواند چت ای کاربر را در دیتابیس ثبت کرده و پیام دریافت کند.

فاز دوم - پیکر بندی و ساخت ربات ثبت نام :

- در ابتدای کار باید سه کلاس به نام های Telegram.php ، Database.php و index.php داشته باشیم ، که در ادامه کد این کلاس ها را قرار داده و به توضیح آن می پردازیم :

فایل اول index.php :

<?php
require_once("Telegram.php");
require_once("Database.php");

define("_TOKEN", "<-BotToken->");
define("_ADMIN", "<-AdminChatId->");

global $config;
$config['host'] = "<-HostAddress->";
$config['user'] = "<-Username->";
$config['pass'] = "<-Password->";
$config['name'] = "<-DatabaseName->";
$config['table'] = "<-TableName->";

$json = file_get_contents('php://input');

$tg = new Telegram($json);
$db = new Database();

$chatId = $tg->getChatId();
$message = $tg->getText();

if ($message == "/start") {
  $db->insertNewUser($chatId);
  $textMessage = "Hi Welcome !\n";
  $textMessage .= "Please send to me your message.";
  $tg->sendMessage($chatId, $textMessage);
} else {
  $textMessage = "Name : " . $tg->getFullName() . "\n";
  $textMessage .= "Counter : " . $db->getUserCounter($chatId) . "\n";
  $textMessage .= "Message : " . $message;
  $tg->sendMessage(_ADMIN, $textMessage);
}

- کدهای نوشته شده در این فایل شباهت زیادی به پروژه های قبل داشته به همین دلیل به توضیح قسمتی از کد تکراری نمی باشد می پردازم ، قطعه کد زیر :

global $config;
$config['host'] = "<-HostAddress->";
$config['user'] = "<-Username->";
$config['pass'] = "<-Password->";
$config['name'] = "<-DatabaseName->";
$config['table'] = "<-TableName->";

- ما در زبان برنامه نویسی ، پدیده ای بنام متغییر های سراسری داریم که با تعریف آن می توان از همه جای برنامه به آن ها دسترسی داشت ، php کمی قوانین نوشتاری اش با بقیه زبان ها متفاوت است وبرای جلوگیری از مبهم بودن این بخش به توضیح اضافی در مورد نحوه کدنویسی php نمیپردازم ، اما این قطعه کد چه مفهومی دارد ؟ همانطور که ملاحظه می کنید کلمه کلیدی global در ابتدای این قطعه کد نمایانگر این است که این متغییر سراسری است و متغییر config که خود آرایه است با استفاده از این کلمه کلیدی به یک آرایه سراسری تبدیل شده و بقیه خطوط کد مربوط به مقدار دهی این آرایه سراسری به اندیس های نام برده شده است.

- این آرایه جهت پیکربندی اتصال به دیتابیس تعریف شده و دارای 5 اندیس که به ترتیب با نام های host آدرس دیتابیس ، user نام کاربری جهت ورود به دیتابیس ، pass رمز ورود به دیتابیس ، name نام دیتابیس و table نام جدولی است که فیلدهای ما داخل آن قرار دارند ، می باشد ؛ توجه کنید ما در این پروژه دارای یک جدول می باشیم و برای همین آن را در در آرایه بالا ذکر کردیم.

- نکته ای دیگر این است که ما باید از متن ارسال شده بوسیله کاربر استفاده کنیم ، به این طریق که اگر ورودی پیام ما کلمه "start/" باشد ، به این معنی است که کاربری برای اولین بار است که وارد ربات می شود ، ولی ممکن است کاربری چندین بار کلمه "start/" را بفرستد ، نگران این موضوع نباشید ؛ زیرا ما در معماری دیتابیس این نکته را ذکر کرده ایم که اگر chatId تکراری بود آن را در دیتابیس ثبت نکند.

- اما اگر پیام ارسالی از طریق کاربر "start/" نبود ، فرض بر این است که یک پیام متنی است ، پیام را همراه با تعداد پیام های ارسالی از کاربر به ادمین ربات ارسال میکند.

فایل دوم Telegram.php :

<?php


class Telegram {
  private static $jsonData;

  public function __construct($json = null) {
    if ($json != null) {
      self::$jsonData = json_decode($json);
    }
  }

  public function getChatId() {
    return self::$jsonData->message->chat->id;
  }

  public function getFullName() {
    $fullName = "";
    if (isset(self::$jsonData->message->from->first_name))
      $fullName .= self::$jsonData->message->from->first_name;
    elseif (isset(self::$jsonData->message->from->last_name))
      $fullName .= self::$jsonData->message->from->last_name;
    return $fullName;
  }

  public function getText() {
    return self::$jsonData->message->text;
  }

  public function sendMessage($chatId, $message) {
    $message = urlencode($message);
    $url = "https://api.telegram.org/bot" . _TOKEN;
    $url .= "/sendMessage?chat_id=" . $chatId;
    $url .= "&text=" . $message;
    file_get_contents($url);
  }
}

- این کلاس Telegram ربات ماست ، توضیح این کلاس در بخش های قبل بطور کامل گفته شده است اما یک توضیح کوتاه در مورد متد ()getFullName می گویم ، در بعضی مواقع کاربران تلگرام از تنظیم نام خانوادگی و به ندرت نام خودداری می کنند ، برای اینکه ربات ما در حین کار دچار خطا نشود و توقف سرویس دهی نکند ناچاریم که موارد نام و نام خانوادگی را از لحاظ تنظیم بودن بررسی کنیم.

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

فایل Database.php :

<?php


class Database {
  private $connection;

  public function __construct() {
    global $config;
    $this->connection = new mysqli($config['host'], $config['user'], $config['pass'], $config['name']);
    if ($this->connection->connect_error) {
      echo "Connection failed: " . $this->connection->connect_error;
      exit;
    }
    $this->query("SET NAMES 'ut8'");
  }

  public function query($sql) {
    return $this->connection->query($sql);
  }

  public function insertNewUser($chatId) {
    global $config;
    $sql = "INSERT INTO " . $config['table'] . " VALUES ('" . $chatId . "', '0')";
    $this->query($sql);
  }

  public function getUserCounter($chatId) {
    global $config;
    $result = $this->query("SELECT _countMsg FROM " . $config['table'] . " WHERE _chatId LIKE '" . $chatId . "'");
    $countMsg = $result->fetch_array()['_countMsg'] + 1;
    $this->query("UPDATE " . $config['table'] . " SET _countMsg = '" . $countMsg . "' WHERE _chatId = '" . $chatId . "'");
    return $countMsg;
  }
}

- به مهم ترین کلاس این پروژه رسیدیم ، این کلاس دارای 4 متد است که در ادامه به توضیح هر کدام می پردازیم :

- متد construct_ :

این متد سازنده کلاس است و وظیفه اتصال به دیتابیس را دارد ، اما چگونه ؟ در زبان php توابع بسیاری جهت کار با دیتابیس وجود دارد ، ما برای اتصال به دیتابیس باید از کلاس mysqli شی ایجاد کنیم (البته راه های دیگری هم برای اتصال وجود دارد ، ما استاندارد ترین راه را توضیح می دهیم) ، کلاس mysqli دارای سازنده ای است که پارامترهای آن به ترتیب pass ، user ، host و name می باشد ، اتصال به دیتابیس به همین سادگی برقرار می شود و بعد از آن چک میکنیم اگر خطایی رخ داده باشد خطا را در خروجی چاپ کند در غیر این صورت به ادامه فعالیت بپردازد ؛ در خط نهایی این متد کد زیر قرار دارد :

$this->db_query("SET NAMES 'ut8'");

- این قسمت از کد ، encoding دیتابیبس را مشخص می کند و به دیتابیس می گوید که اطلاعات ارسالی با اینکدینگ utf8 می باشد ؛ قمستی از کد بالا (SET NAMES 'ut8') کوئری است ، ما در کلاس پایگاه داده متدی دیگری تعریف کرده ایم که اجرای کوئری های ما ، به عهده متد query است که در ادامه به توضیح آن می پردازیم.

- متد query :

کلاس mysqli ، حاوی متد های فراوانی است که وظیفه های مختلفی دارند ، ما از متد اجرای کوئری این کلاس استفاده می کنیم ، برای استفاده از این متد باید از نمونه (شی) ساخته شده کلاس mysqli استفاده کنیم و متد query این کلاس را مانند زیر فراخوانی کنیم :

$this->connection->query("SQL Query");

توجه کنید این متد یک پارامتر دارد که همان کوئری ماست.

- متد insertNewUser :

وظیفه این متد ، ذخیره یک کاربر جدید در دیتابیس است ، توجه کنید بخش اصلی در این متد ، کوئری نوشته شده است ، برای ذخیره یک کاربر جدید در دیتابیس با معماری کنونی ، باید کوئری مانند زیر بنویسید :

INSERT INTO user_data VALUES ('441660894', '0')

- این کوئری به دیتابیس می گوید که وارد کن در جدول user_data مقدارهای 441660894 در جایگاه chatId_ و 0 در جایگاه countMsg_ ، اما بدلیل اینکه ما باید متدی بنویسیم که برای تمام کاربرها قابل استفاده باشد ؛ باید این دومقدار را پویا کنیم و بصورت زیر از طریق متد دریافت کنیم :

public function insertNewUser($chatId) {
    global $config;
    $sql = "INSERT INTO " . $config['table'] . " VALUES ('" . $chatId . "', '0')";
    $this->query($sql);
}

و در نهایت با استفاده ازمتد query ، این کوئری را اجرا کنیم.

- متد getUserCounter :

به مهم ترین متد این پروژه رسیدیم ، وظیفه این متد دریافت شمارشگر تعداد پیام های یک کاربرخاص و تحویل آن برنامه است ولی در این حین عملیاتی دیگری انجام میدهد ، این عملیات افزودن مقدارشمارشگر به میزان یک واحد است ، ابتدا برای دریافت شمارشگر باید چه فرآیندی انجام شود؟! ، به کوئری زیر توجه کنید :

SELECT * FROM user_data WHERE _chatId LIKE '441660894' 

- معنی این کوئری این است که انتخاب کن از بین همه فیلد ها (کاراکتر * به معنی همه فیلدها) از جدول user_data ، در جایی که مقدار فیلد chatId_ برابر با 441660894 است ، خروجی این کوئری در همه حال یک آرایه است ، اما اگر بخواهیم یک فیلد خاص را بگیریم (به جای همه فیلدها که با کاراکتر * دریافت کردیم) ، کافی است به جای * نام فیلد مورد نظر را قرار دهیم ، مانند زیر :

SELECT _countMsg FROM user_data WHERE _chatId LIKE '441660894' 

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

$result = $this->query("SELECT _countMsg FROM " . $config['table'] . " WHERE _chatId LIKE '" . $chatId . "'");
$countMsg = $result->fetch_array()['_countMsg'] + 1;

و بدلیل اینکه قرار است که کدی پویا شود و برای همه کاربرا قابل استفاده باشد مقادیر جستجو را پویا میکنیم که مقدار chatId_ در این کوئری پویاست ، اما ما گفتیم که مقدار خروجی این کوئری یک آرایه است ؛ چطور باید به این آرایه دست پیدا کنیم ؟ با استفاده از متد ()fetch_array مانند کد بالا ، می توان به آرایه دسترسی داشت از طرفی هم می دانیم اندیس خروجی ما بنام countMsg_ است ، پس بعد از این متد ، نام اندیس را قرار می دهیم ، اما ما باید تعداد پیام ها را هر دفعه یک واحد افزایش دهیم ، بنابراین در ادامه کد این مقدار را یک واحد افزایش می دهیم ، بطور خلاصه و مفید ما در یک خط کد توانستیم تعداد جدید پیام های یک کاربر خاص را دریافت کنیم.

- ما باید این مقدار جدید را هم در دیتابیس ثبت کنیم و هم به برنامه دهیم ، برای بروزرسانی (update) یک مقدار در دیتابیس باید از دستور update استفاده کنیم ، به کوئری زیر توجه کنید :

UPDATE user_data SET _countMsg = '1' WHERE _chatId = '441660894'

این کوئری به دیتابیس می گوید که مقدار فیلد countMsg_ در جدول user_data را به مقدار عددی 1 تغییر بده در جایی که chatId_ آن فیلد برابربا 441660894 است ، با این توضیح ، حال میتوانیم قطعه کد زیر را بهتر توضیح دهیم :

$this->query("UPDATE " . $config['table'] . " SET _countMsg = '" . $countMsg . "' WHERE _chatId = '" . $chatId . "'");

که به دلایل ذکر شده باید بصورت پارامتری نوشته شود ، پارامترهای داخل این کد chatId$ و countMsg$ است که مقدار جدید به خود گرفته ، با این عمل این کد قابل استفاده برای تمام کاربران است.

- حال باید مقدار جدید شمارشگر که مقدار متغییر countMsg$ است را به برنامه ارسال کنیم ، مانند کد زیر:

return $countMsg;

این متد که متدی از نوع برگشتی است ، شمارشگر را به فایل index.php که محل فراخوانی این متد است ، ارسال می کند.

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

پایان آموزش ساخت ربات تلگرام

موفق باشید.

این محتوا آموزنده بود؟
رباتتلگرام

sokan-academy-footer-logo
کلیه حقوق مادی و معنوی این وب‌سایت متعلق به سکان آکادمی می باشد.