نویسنده: حمید حق دوست

  • یک ربات ساده تلگرام با لاراول

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

    تصور غلط در مورد ربات تلگرام

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

    ساخت یک ربات خام در تلگرام

    عملیات ساخت ربات تلگرام خودش از طریق یه ربات انجام میشه، بات فادر اسم رباتی هست که این کار رو انجام میده و برای دیدن اون میتونید به این آیدی مراجعه کنید : @BotFather، نحوه ساخت ربات با botfather خیلی مشخصه و نیازی به توضیح نیست. بعد از ساخت ربات یه توکن به ربات تعلق میگیره و از این به بعد این توکن بعنوان شناسه ربات شما استفاده میشه. توکن شما یه چیزی شبیه ۱۲۳۴۵۶:ABC-DEF1234ghIkl-zyx57W2v1u123ew11 هست که توی این نوشته به اختصار از <token>  برای نشون دادنش استفاده میکنیم.

    نحوه ی اهراز هویت ربات توسط تلگرام

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

    https://api.telegram.org/bot<token>/METHOD_NAME

    که METHOD_NAME  نام متدی هست که قراره در هر درخواست ازش استفاده کنید.

    شما میتونید با هر زبان سمت سروری بک اند رباتتون رو بنویسید. برای اینکه درخواست هایی که از طریق کاربران ربات به ربات ارسال شدن رو دریافت کنید دو روش دارید:

    1. دریافت آپدیت ها با ارسال لحظه ای درخواست از طرف شما
    2. تنظیم وب هوک برای دریافت آپدیت بدون ارسال درخواست لحظه ای

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

    درخواست getUpdates ربات تلگرام

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

    تنظیم setWebhook برای ربات تلگرام

    برای این کار شما باید آدرسی که میخواید هوک روی اون fire بشه رو میفرستید و تلگرام به محض دریافت پیام جدید درخواست رو به این آدرس ارسال میکنه. برای ارسال درخواست هاتون میتونید از افزونه postman برای کروم استفاده کنید که کارتون رو راحتتر میکنه. توجه داشت باشید که برای این کار شما حتما باید گواهینامه ssl داشته باشید و آدرس بصورت https ارسال بشه.

    استفاده از پکیج irazasyed/telegram-bot-sdk

    اگه توی لاراول دارید کار میکنید میتونید از irazasyed/telegram-bot-sdk استفاده کنید. این پکیج کارتون رو خیلی راحتتر میکنه… بعد از نصب این پکیج میتونید برای تست اون از طریق زیر عمل کنید

    ابتدا توی فایل .env  توکنی که برای ربات دریافت کردید رو بصورت زیر وارد کنید

    TELEGRAM_BOT_TOKEN=<token>

    و توی کدتون هم یچیزی مثل این رو بنویسید

    $telegram = new \Telegram\Bot\Api();
    $response = $telegram->getMe();
    	
    $botId = $response->getId();
    $firstName = $response->getFirstName();
    $username = $response->getUsername();
    	
    dd($botId, $firstName, $username);

    در صورتی که اطلاعات ربات رو دریافت کردید ینی ربات شما درست ایجاد شده است. تنها کاری که الان باید بکنید اینه که یه route رو از csrf protection در بیارید و اون روت رو بعنوان url برای هوکتون در نظر بگیرید و درخواست ها رو هندل بکنید.

     

  • دیزاین پترن singleton در PHP

    در ادامه بحث هامون در مورد دیزاین پترن ها امروز میخوام بصورت خلاصه در مورد singleton design pattern بنویسم که فکر میکنم به درد خیلی هاتون بخوره و خیلی از پیچیدگی کد نویسی رو براتون کمتر کنه. بصورت خلاصه و مفید اگه بخوام بگم این دیزاین پترن همونطور که از اسمش پیداست از تکرار جلوگیری میکنه و جاهایی استفاده میشه که بخوایم یه کد تکراری رو فقط یکبار بنویسیم. پس سینگلتون جاهایی به کارمون میاد که ما به یه نمونه از شی بصورت گلوبال میخوایم دسترسی داشته باشیم. مثلا شما ممکنه مجبور باشید توی یک سیستم بارها به دیتابیس وصل بشید. یا ممکنه بخواید از api یه سایت دیگه هر چند بار پشت سر هم استفاده کنید یا هر چیز دیگه ای که خودتون صلاح میدونید… با مثال توضیح میدم که ایده ی این الگو چطور هست. در زیر یه پیاده سازی پایه از این الگو رو میبینیم :

    class Database
    {
        public static function Instance()
        {
            static $inst = null;
            if ($instnce === null) {
                $instnce = new Database();
            }
            return $instnce;
        }
    
        public function getUsers()
        {
            return 'users...';
        }
        
        public function getPosts()
        {
            return 'posts...';
        }
    }
    
    $users = Database::Instance()->getUsers();
    $posts = Database::Instance()->getPosts();

    همونطور که میبینید Instance  به صورت متد استاتیک تعریف شده و بصورت استاتیک بهش دسترسی پیدا میکنیم.

  • دیزاین پترن Simple Factory در PHP

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

    Design patternها یا فارسیش میشه احتمالا الگوهای طراحی نرم افزار توی همه زبان ها خیلی خیلی مهمن. معمولا وقتی کدی مینویسیم که قرار نیست در آینده گسترش داده بشه خیالمون راحته و از یجای کار شروع میکنیم و یجا تموم میکنیم و کار رو تحویل میدیم، ولی وقتی کارفرما میگه که “در آینده قراره امکانات زیادی از قبیل فلان۱ و فلان۲ و… به سیستم اضافه بشه”، اونجا باید یه فکر پایه ای تر برای سیستم داشته باشیم. طوری که اگه قرار شد یه بخش جدید رو به سیستم اضافه کنیم مجبور نباشیم تو بخشای قبلی دست اندازی کنیم یا حداقل کم مجبور باشیم(!).

    فرض کنید که میخواید یه فروشگاه بنویسید که ادمین روزی چند تا محصول از نوع اسباب بازی به سیستم اضافه میکنه. ابتدایی ترین روشی که به فکر همه ما میرسه اینه که یه کلاس ایجاد کنیم تحت نام Product  و توی اون درج، اصلاح، حذف و … محصول که فعلا اسباب بازی هست رو انجام بدیم. یه چیزی شبیه این :

    <?php
    class Product {
        public function __construct($name) {}
    
        public function save() {}
    }
    $product = new Product('first toy');
    $product->save();

    تا اینجا همه چی خوبه و شما در آرامش قبل از طوفان به سر میبرید! مشکل زمانی پیش میاد که مجبور بشید مثلا بجز اسباب بازی ، کتاب هم در فروشگاهتون بفروشید. اینجا دیگه روش ایجاد و اصلاح و … فرق میکنه و نمیتونید همین متد های قبل رو استفاده کنید. توی دیزاین پترن بالا شما مجبورید یه $type  زمان نمونه گیری از کلاس بگیرید و توی هر متد if و else بذارید و بگید اگه این دسته بود این کارو بکن و اگه… که قطعا روش خوبی نیست و مثلا وقتی چنتا دسته دیگه بعدها اضافه بشه کدمون خیلی داغون میشه.

    نحوه ی پیاده سازی دیزاین پترن Simple Factory در PHP

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

    اول یه کلاس factory بسازید :

    class ProductFactory {
      public function __construct(){ }
    
      public static function create($type){
         if ($type == '')
            throw new Exception('invalid product type');
         else {
            $className = 'product_' . ucfirst($type);
            if (class_exists($className))
               return new $className;
            else
               throw new Exception('Product type not found');
         }
      }
    }
    

    حالا واسه ساخت اسباب بازی از روش خیلی ساده زیر استفاده کنید :  

    class product_Toy
    {
      public function __construct(){
         echo "toy is creating";
      }
    }
    $toy = ProductFactory::create('toy');
    

    حالا اگه یه دسته جدید مثل کتاب به محصولاتون اضافه شه خیلی راحت میتونید کلاسش رو بسازید محصولتون رو اضافه کنید :

    class product_Book
    {
      public function __construct(){
         echo "book is creating";
      }
    }
    $book = ProductFactory::create('book');
    

    در مجموع simple factory method خیلی ایده ی سختی نداره. میگه وقتی داری از یه کلاس نمونه میگیری که خودش میتونه انواع مختلفی داشته باشه یدونه فکتوری واسش درست کن و از فکتوری نمونه بگیر که هر بار مجبور نشی هزار تا جایی که ازش نمونه گرفتی رو تغییر بدی. بعد برو توی فکتوری و چک کن که با توجه به کانفیگت کدوم کلاس رو نمونه بگیری.

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

    امیدوارم کمکتون کرده باشم و خوشحال میشم نظراتتون رو بشنوم 🙂

  • ساخت custom notification channel در لاراول

    لاراول برای ارسال نوتیفیکیشن درایور های متنوعی داره که برای کاراتون میتونید ازش استفاده کنید… ولی بعضی وقتا پیش میاد که نیاز دارید چنل خودتون رو داشته باشید، برای این کار باید کانال ارسال خودتون رو بنویسید که خیلی راحته

    مثلا در مسیر app  یک فولدر با عنوان channels  بسازید و توش یه کلاس php با اسم دلخواهتون ایجاد کنید. من اسمشو میذارم SmsChannel .

    <?php
    
    namespace App\Channels;
    
    use Illuminate\Notifications\Notification;
    
    class SmsChannel
    {
        /**
         * Send the given notification.
         *
         * @param  mixed  $notifiable
         * @param  \Illuminate\Notifications\Notification  $notification
         * @return void
         */
        public function send($notifiable, Notification $notification)
        {
            $message = $notification->toSms($notifiable);
            //do your action
        }
    }

    در قسمت do your action عملیاتی که برای ارسال نوتیفیکیشنتون(!) رو که میتونه متنوع باشه رو انجام بدید… مثلا اگه میخواید با استفاده از یه سرویس دهنده خاص اس ام اس ارسال کنید میتونید کلاسهای اون رو ایمپورت کنید و اس ام اس رو ارسال کنید.

    مثلا برای ارسال پیامک بصورت زیر عمل کنید :

    send_sms($message['receptor'], $message['message']);

    که آرایه message  از متد های کلاس های نوتیفیکیشن ها ارسال میشه…

    برای ارسال نوتیفیکیشن در متد via  در کلاس نوتیفیکیشن \App\Channels\SmsChannel::class  رو برگردونید… یه چیزی مثل این :

    /**
         * Get the notification's delivery channels.
         *
         * @param  mixed  $notifiable
         * @return array
         */
        public function via($notifiable)
        {
            return [\App\Channels\SmsChannel::class];
        }

    که میتونید از $notifiable  استفاده کنید و ببینید که اس ام اس واسه کاربر ارسال بشه یا نه… مثلا اعتبار کاربریش اجازه ارسال رو میده یا نه.

    و متد زیر رو برای ارسال پیام در کلاس مربوط به نوتیفیکیشن بنویسید :

    public function toSms($notifiable)
        {
            return [
                'receptor' => $notifiable->mobile,
                'message'  =>  'یک ورود ناموفق به حساب شما ثبت شد.'
            ];
        }
  • باز شدن ناگهانی کانال تلگرام و درخواست عضویت

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

    مشکل: دارید توی اینستا و یا تلگرام و یا هرجای دیگه میچرخید که یهویی پرت میشید توی تلگرام و یه کانال باز میشه و بهتون میگه که آیا مطمئنید که میخواید توی کانال فلان عضو شید؟ و ازتون میخواد اوکی کنید تا توی کانال عضو شید….

    دلیل رو اینجوری پیدا کردم : چک کردم دیدم توی وب خارج هیچ سوالی در این مورد پرسیده نشده، فهمیدم که کار خودمونه… ینی ایرانیا 🙂 یه برنامه ایرانی روی گوشیم داشتم، حذفش کردم و مشکل درست شد!!! ینی از هر روشی استفاده میکنیم که پول در بیاریم… حتی به قیمت زیر سوال رفتن برنامه اصلیمون…

    برنامه ای که برای من مشکل درست کرده بود اسمش هست : “عکس نوشته ساز”. اگر این برنامه رو نصب دارید که حتمن کار خودشه… اگه ندارید هم چک کنید ببینید کدوم برنامه هست و اسمش رو کامنت کنید زیر این پست تا بقیه هم بدونن…

     

    البته من به بازار هم مشکوکم و خدا کنه که کار بازار نباشه این حرکت… که اگه باشه باید همگی سرمونو بذاریم زمین و بمیریم 😐

     

    موفق باشید

  • ذخیره کردن شکلک ها در MySQL

    اخیرا که ملت همه ریختن تو شبکه اجتماعی و با شکلک – ایموجی – ها و… سروکار دارن ما هم باید بتونیم کارشون رو راه بندازیم 🙂

    کانکشن پیشفرض MySQL لاراول به صورت پیشفرض از کاراکتر ست utf8 استفاده میکنه که نمیتونه شکلک ها رو ذخیره کنه و معمولا با این خطا مواجه میشیم :

    SQLSTATE[HY000]: General error: 1366 Incorrect string value...

    برای حل این مشکل کانکشن mysql  در config/database.php  رو به صورت زیر اصلاح کنید :

    'mysql' => [
        'driver' => 'mysql',
    	[...]
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        [....]

    و دیتابیس رو ریست کنید. حواستون باشه که از دیتاتون قبلش بکاپ بگیرید…

  • خطای migrate لاراول ۵٫۴

    همونطور که میدونید لاراول ۵٫۴ مدتیه که منتشر شده. توی این نسخه، لاراول توی کاراکتر ست پیشفرضش یسری تغییری داده و کاراکتر ست فعلی اون utf8mb4 هست که قابلیت پشتیبانی از ایموجی ها رو هم داره.  خطایی که هنگام اجرایphp artisan migrate  توی MySQL  زیر  ۵٫۷٫۷ باهاش مواجه مشید یه چیزی مثل خطای زیر هست :

    [Illuminate\Database\QueryException]
    SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table users add unique users_email_unique(email))
    
    [PDOException]
    SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

    برای حل این مشکل توی فایل AppServiceProvider.php  طول پشفرض رشته رو تغییر بدید…

    use Illuminate\Support\Facades\Schema;
    
    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    الان دیگه نباید مشکلی وجود داشته باشه… موفق باشید

     

  • file_get_content بوسیله curl در php

    همونطور که میدونید تابع flie_get_contents()  سورس فایل مورد نظر رو که میتونه حتی یک صفحه وب باشه رو میریزه توی یه رشته و میتونید هر بلایی سرش بیارید(مثلا با html-dom-parser به المنت هاش دسترسی پیدا کنید). بعضی وقتا ssl و… نمیذارن که بصورت مستقیم به محتویات صفحه دسترسی پیدا کنید. همینطور وقتی میخواید یه عکس رو از یه صفحه ای که ssl روش هست کپی کنید…  من به این مشکل برخوردم و با curl مشکلم رو حل کردم… جمع و جورش رو براتون در قالب یه فانکشن گذاشتم که امیدوارم به دردتون بخوره…

     function file_get_contents_curl( $url ) {
            $ch = curl_init();
            curl_setopt( $ch, CURLOPT_AUTOREFERER, TRUE );
            curl_setopt( $ch, CURLOPT_HEADER, 0 );
            curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
            curl_setopt( $ch, CURLOPT_URL, $url );
            curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, TRUE );
            curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0);
            $data = curl_exec( $ch );
            curl_close( $ch );
            return $data;
        }

    موفق باشید…

  • لاراول ۵٫۴ با قابلیت جدید Automatic Facade

    حتما با فساد ها در لاراول آشنا هستید… با قابلیت جدید لاراول در نسخه ۵٫۴ شما میتونید توی هوا از یه کلاس شبیه یه فساد استفاده کنید… یه کلاس مثل کلاس زیر تعریف کنید :

    namespace App;
    
    class Zonda 
    {
        public function zurf()
        {
            return ‘Zurfing’;
        }
    }

    و بعد توی route و یا کنترلرتون به صورت زیر عمل کنید :

    use Facades\ {
        App\Zonda
    };
    
    Route::get('/', function () {
        return Zonda::zurf();
    });

    به کجا داریم میریم ما؟؟؟ :دی

  • مشکل migrate در لاراول ۵

    اگه بعد از php artisan migrate  کردن اررور زیر رو میگیرید :

     [PDOException]                                    
      SQLSTATE[HY000] [2002] No such file or directory

    توی فایل app\database.php  مقدار localhost  رو به ۱۲۷٫۰٫۰٫۱  تغییر بدید… معمولا توی ابونتو همچین مشکلی هست …